你可能会发现,sword的代码仓库使用了monorepo,在packages这个目录中,我们定义了很多官方插件,比如在server中的运行时,比如log插件,它们都有自己的作用,而这些插件都是基于sword插件系统上实现的。
在这一章节中,我们将会简单了解sword插件系统是什么样子的,它提供了一些什么功能?
如何写一个插件
在sword中提供了很多root节点,比如log 节点,server节点,在sword运行时中,会注册插件,并且在运行过程中把对应方法执行时机交由插件实现,听起来很简单,做起来也很简单,这是一个插件的类型:
export type Plugin = {name: string;// 提供几个钩子用来定义函数,作为框架runtime的shimserver?: {start: (...args: any[]) => Promise<void> | void;};log?: {err: (v: string | Error) => void;info: (v: string) => void;success: (v: string) => void;};// 还有其他的root节点,具体内容参见插件系统的子文档};
可以清楚的看到,有一个plugin name,这个name主要用在日志上,可以打印出某个时机执行的逻辑是由sword实现的,还是某个插件实现的,这会方便调试,所以name并不是一个唯一值。
sword不同于其他框架的插件系统,它可以一个插件同时实现多个root节点,即我写了一个插件叫做:“seho-plugin”,代表了我一个插件实现了多个功能,这样做有一个好处就是,用户在选择插件的时候可以选择又大又全的插件,而不用一个一个添加组合,可以让应用程序的开发始终是“最佳方案”。那么既然一个插件可以实现多个root,那如果你注册了多个插件,运行时同一时间只会运行一个root,那么在sword中采取的措施就是,新的root替换旧的root
比如我写了一个seho-plugin(伪代码演示):
export const plugin = (): Plugin => {return {name: 'seho-plugin',log: () => {console.log("这是旧的log")},server: () => {console.log("这是旧的server")}};};
我又注册了一个叫做server的插件
export const plugin = (): Plugin => {return {name: 'server',log: () => {},server: () => {console.log("这是新的server")}};};
那么此时sword会应用这样的一个插件对象:
{log: () => {console.log("这是旧的log")},server: () => {console.log("这是新的server")}};
所以sword的插件系统给用户了最大的选择权,你可以让你的插件是颗粒度小的,也可以让你的插件是大而全的,所以我们写插件也非常简单,我们只需要导出一个插件对象就可以啦!
下面演示了一个log插件的开发:
import chalk from 'chalk';import type { Plugin } from '@swordjs/sword-framework';const now = () => {const _ = new Date();return `${_.getFullYear()}-${_.getMonth() + 1}-${_.getDate()} ${_.getHours()}:${_.getMinutes()}:${_.getSeconds()}`;};export const log = {err: (v: string | Error): void => {console.log(`${chalk.gray(now())} ${v}`);},info: (v: string): void => {console.log(`${chalk.gray(now())} ${chalk.yellow(v)}`);},success: (v: string): void => {console.log(`${chalk.gray(now())} ${chalk.green(v)}`);}};/*** 定义终端打印日志插件* @preset true* @return {*}*/export const useLogPlugin = (): Plugin => {return {name: 'log',log};};
使用插件
import { useApp, usePlugin } from '@swordjs/sword-framework';const plugin = usePlugin();plugin.add(useLogPlugin);const app = useApp();const init = () => {// ...};init();
这里useplugin的类型:
declare const usePlugin: () => {add: (plugin: Plugin | (() => Plugin)) => Promise<Plugin[]>;};
