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