如何写一个插件
Last updated
Was this helpful?
Last updated
Was this helpful?
使用帮助你更容易的开发插件
让我们实现第一个插件 —— , 它用来在终端和浏览器端分别打印用户欢迎语
*其实只有
package.json
和index.js
*是必须的
以下分别做下介绍
package.json
在package.json
中只有 2 个字段是 svrx 依赖的
name
: 包名要求必须是 svrx-plugin
开头,这是为了方便使用 npm 服务来进行插件查找
index.js
其中
assets
: 前端资源配置,他们会被自动注入到前端脚本中
style
: css 脚本注入,默认注入 html 头部,本例没有使用
script
: script 脚本注入,默认注入 html 尾部
注入前端资源都会被合并成一个资源
hook.onCreate
: 插件创建的钩子,在这里我们可以通过注入的服务组件来扩展插件,这里仅介绍使用到的服务
logger
: 日志服务
config
: 获取用户参数的组件
本例做的是在终端打印关于 user 参数的欢迎语
client.js
前端注入脚本中有一个**「全局变量 svrx」**, 挂载了一些 svrx 在前端的内置服务。
这个全局 svrx 仅在插件脚本内部可以访问,不用担心全局污染
这里我们仅仅是做了一个用户相关控制台 log 输出
与服务端的 config 组件不一样,这里的 config 是通过 websocket 传递的,所以接口返回的是 promise
所以我们跳过这一步,直接运行
检查下浏览器端和命令行终端将可以看到 'Hello svrx from browser' 的类似日志,说明插件已经生效
也可以通过脚本的方式来启动
所有插件服务都可以在两个地方被注入
插件定义中的hooks.onCreate
钩子
svrx 实例的plugin
事件回调,此事件会在所有插件组装完毕后执行
接下来,我们依次说明这 7 个组件
middleware.add(name, definition)
增加一个中间件
Usage
Param
name
[String]: 定义一个唯一的中间件名
debug 模式下根据此命名可以 track 请求响应的管线
definition.priority
[Number]: 默认为 10. svrx 会根据 priority 由高到低的组装中间件,即请求会先经过高优先级的插件
definition.onRoute
[Function]: 满足 koa 规范的中间件定义,如果 definition
是一个函数,则会自动成为 definition.onRoute
middleware.del(name)
删除一个中间件
Usage
Param
name
: 传入add
的名称
injector
用来改写响应流或注入前端资源
injector.add(type, definition)
增加一种注入资源, 目前支持原生的 js 和 css 注入,他们注入规则如下
样式会合并到/svrx/svrx-client.css
下,并注入到 html 的head
闭合标签前
脚本会合并到/svrx/svrx-client.js
,并注入到 html 的body
闭合标签前
Usage
上例会往/svrx/svrx-client.js
注入 content 字段中的脚本内容
Param
type
: 目前仅支持script
以及style
definition.content
[String]: 资源的内容
definition.filename
[String]: 资源文件,必须是绝对地址
content 的优先级高于 filename,二者取其一即可
injector.replace(pattern, replacement)
自定义 html 的替换规则
Usage
上例将 html 中的 svrx 替换为 server-x
Param
pattern
[String|RegExp]
replacement
[String|Function]
injector.replace
的使用与String.prototype.replace
完全一致 资源注入就是通过injector.replace
实现的
内置事件监听器,支持 async sorted emitter,即可以依次调用监听函数,并可在任意一个事件监听中终止事件传递
events.on(type, fn)
Usage
Param
type
[String]: 事件名
fn(payload, ctrl)
: 事件回调,它包含 2 个入参
payload
[String]: 事件参数, 通过 emit 传入
ctrl
[Object]: 控制器, 调用ctrl.stop()
可终止 sorted emit
如果回调返回一个Promise
(比如 async function),视为一个异步回调
events.emit(type, param, sorted)
Usage
Param
type
[String]: 事件名
payload
: 事件参数,被on
中注册的回调函数接收
sorted
[Boolean]: 默认false
, 是否串行阻塞的触发事件
Return
Promise
events.off(name, handler)
Usage
plugin
: 当插件准备完毕后触发
file:change
: 当文件发生变更时被触发
ready
: 当服务启动时触发,如果你需要在服务启动处理部分逻辑(如获取服务端口),请注册这个事件
插件配置管理
config.get(path)
获取一个插件配置
config 内部维护的数据结构为不变数据,对于配置有实时性要求的,必须使用 config.get
来取值,确保获得最新配置项目
Usage
你也可以获取全局参数,只需要加$.
前缀
Param
field
: 配置名,深层配置用.
分割,比如user.name
Return
配置值
config.set(field, value)
设置配置项
Usage
Param
field
: 配置名,深层配置用.
分割,比如user.name
value
配置值
config.watch([field, ]handler)
监听配置变化, 配置变化检查会在set
、del
、splice
方法后被触发
Param
field
: 字段名, field
是可选的,如不传入则所有 config 变更都会触发
handler(evt): 监听回调
evt.affect [Function]: 判断本次变更是否影响某字段
config.del(field)
删除某个配置项
Usage
Param
配置名
config.splice(field, start[, delCount[, items...])
数组 splice 的 config 版本
router.route(register)
Usage
Param
register({...methods}): 注册回调
router.action(name, builder)
注册一个与 proxy
、json
类似的 action
Usage
Param
name
[String]: action 名,即后续的调用方法名
builder(payload)
payload: 即传入 action 方法的参数,如上栗的'svrx'
router.load(filename)
加载的文件同样支持 hot reloading
Usage
Param
filename
: 路由文件的绝对路径
Return
Promise
日志模块,它的分级可以通过logger.level
来控制(默认为warn
)
或从 cli 端
上例将会输出warn
以上的日志,如notify
、error
logger[level](msg)
svrx 提供了多种级别的日志,分别是silent
, notify
, error
, warn
(默认日志分级), info
, debug
Usage
logger.notify
由于会非常常用,所以它有一个 aliaslogger.log
io.on( type, handler )
Param
type
: 事件名
handler(payload)
: 事件回调
payload
: 事件参数
io.emit(type, payload)
发送 io 事件到客户端
Usage
server side
client side
Param
type
: 事件名
payload
: 事件参数
注意事件参数必须是可序列化的,因为要通过网络传输
io.off(type[, handler])
解除监听
Usage
io.register(name, handler)
注册一个 io 服务, 它可以在客户端或服务端以io.call
的方式调用
Usage
Param
name
[String]: 服务名,call
中会被使用
handler
: 服务逻辑实现,异步请返回 Promise 或使用 async/await
io.call(name, payload)
调用注册的服务
Usage
上例如下调用会返回 'Hello svrx'
Param
name
[String]: 服务名
payload
[Any]: 服务入参
Return
Promise
客户端 API 统一通过 svrx 全局变量暴露,如下例
以下依次说明
通信模块,负责与服务端通信
io.on(type, handler)
监听服务端 io 事件
Usage
server side
client side
注意后端
io.emit
属于广播,所有前端页面都会收到信息
Param
type
: 事件名
handler(payload)
: 事件回调
payload
: 事件参数
io.emit(type, payload)
发送 io 事件到服务端
Usage
client side
server side
Param
type
: 事件名
payload
: 事件参数
注意事件参数必须是可序列化的,因为要通过网络传输
io.off(type[, handler])
解除监听
Usage
io.call(name, payload)
Usage
Param
name
[String]: 服务名
payload
[Any]: 服务入参
Return
Promise
Usage
events 与 io 的不同在于 io 是 服务端与客户端的通信,而 events 是单端的事件触发器
客户端的config
模块与服务端几乎一致,唯一区别是从同步接口变成了 Promise 化的异步接口(因为 socket 的网络通信)
config.get(field)
Usage
注意获取的参数是属于脚本的,如果获取全局请加
$.
前缀
config.set
、config.splice
、config.del
上述三个方法和get
一样,与服务端表现一致,不过返回值变为 Promise
Usage
Usage
Field 详解
default
[Any]: 默认值
required
[Boolean]: 是否是必须的, 默认是false
properties
[Object]: 定义属性,每层属性又是一层 schema 定义
anyOf
: 属性任选其一,如
不建议大家发布测试插件到 npm, 可以通过以下方式来进行本地测试
指定 path 参数后,svrx 会加载本地包,而不是从 npm 中获取
svrx 官方提供的脚手架帮助你更容易的开发和发布你的插件
engines.svrx
: 定义此插件的可运行 svrx 版本,svrx 会自动加载最新的匹配插件, engines.svrx 可以是一个 ,如0.1.x
或~0.1
等
configSchema
插件参数定义,请参考了解更多,这里我们定义了一个默认为'svrx'
的字符串类型的参数 user
hook.onCreate
实际上还接受多种组件服务,具体请
svrx 其实还暴露了其它前端服务,具体请参考
在根目录,我们直接运行npm publish .
尝试发布,会发现发布失败了,因为hello-world
插件已经被。
进一步阅读:
middleware 负责添加满足 完成后端逻辑的注入
除了field
外,
从插件层面扩展或注册
快捷注册路由,与一致
methods: 对应
Return: builder 返回标准的
手动加载一个 route 文件,与
io 负责插件后端与前端的通信, 请结合 查看
监听浏览器端发送消息(即通过)
在 client 端的 与服务端完全一致,但要确保 payload 是可序列化的,因为会经过网络传输
浏览器端内部的事件发射器,这部分和完全一致,不做赘述
svrx 支持一种基于 扩展的参数定义,以内部定义的参数为例
type
[String]: ,可以是array
、string
、number
、boolean
、object
、null
ui
: svrx 的扩展字段,是否要在 中被展示
进一步的 JSON Schema 定义请参考