你可能会发现,sword的代码仓库使用了monorepo,在packages这个目录中,我们定义了很多官方插件,比如在server中的运行时,比如log插件,它们都有自己的作用,而这些插件都是基于sword插件系统上实现的。
在这一章节中,我们将会简单了解sword插件系统是什么样子的,它提供了一些什么功能?

如何写一个插件

在sword中提供了很多root节点,比如log 节点,server节点,在sword运行时中,会注册插件,并且在运行过程中把对应方法执行时机交由插件实现,听起来很简单,做起来也很简单,这是一个插件的类型:

  1. export type Plugin = {
  2. name: string;
  3. // 提供几个钩子用来定义函数,作为框架runtimeshim
  4. server?: {
  5. start: (...args: any[]) => Promise<void> | void;
  6. };
  7. log?: {
  8. err: (v: string | Error) => void;
  9. info: (v: string) => void;
  10. success: (v: string) => void;
  11. };
  12. // 还有其他的root节点,具体内容参见插件系统的子文档
  13. };

可以清楚的看到,有一个plugin name,这个name主要用在日志上,可以打印出某个时机执行的逻辑是由sword实现的,还是某个插件实现的,这会方便调试,所以name并不是一个唯一值。
sword不同于其他框架的插件系统,它可以一个插件同时实现多个root节点,即我写了一个插件叫做:“seho-plugin”,代表了我一个插件实现了多个功能,这样做有一个好处就是,用户在选择插件的时候可以选择又大又全的插件,而不用一个一个添加组合,可以让应用程序的开发始终是“最佳方案”。那么既然一个插件可以实现多个root,那如果你注册了多个插件,运行时同一时间只会运行一个root,那么在sword中采取的措施就是,新的root替换旧的root

比如我写了一个seho-plugin(伪代码演示):

  1. export const plugin = (): Plugin => {
  2. return {
  3. name: 'seho-plugin',
  4. log: () => {
  5. console.log("这是旧的log")
  6. },
  7. server: () => {
  8. console.log("这是旧的server")
  9. }
  10. };
  11. };

我又注册了一个叫做server的插件

  1. export const plugin = (): Plugin => {
  2. return {
  3. name: 'server',
  4. log: () => {},
  5. server: () => {
  6. console.log("这是新的server")
  7. }
  8. };
  9. };

那么此时sword会应用这样的一个插件对象:

  1. {
  2. log: () => {
  3. console.log("这是旧的log")
  4. },
  5. server: () => {
  6. console.log("这是新的server")
  7. }
  8. };

所以sword的插件系统给用户了最大的选择权,你可以让你的插件是颗粒度小的,也可以让你的插件是大而全的,所以我们写插件也非常简单,我们只需要导出一个插件对象就可以啦!

下面演示了一个log插件的开发:

  1. import chalk from 'chalk';
  2. import type { Plugin } from '@swordjs/sword-framework';
  3. const now = () => {
  4. const _ = new Date();
  5. return `${_.getFullYear()}-${_.getMonth() + 1}-${_.getDate()} ${_.getHours()}:${_.getMinutes()}:${_.getSeconds()}`;
  6. };
  7. export const log = {
  8. err: (v: string | Error): void => {
  9. console.log(`${chalk.gray(now())} ${v}`);
  10. },
  11. info: (v: string): void => {
  12. console.log(`${chalk.gray(now())} ${chalk.yellow(v)}`);
  13. },
  14. success: (v: string): void => {
  15. console.log(`${chalk.gray(now())} ${chalk.green(v)}`);
  16. }
  17. };
  18. /**
  19. * 定义终端打印日志插件
  20. * @preset true
  21. * @return {*}
  22. */
  23. export const useLogPlugin = (): Plugin => {
  24. return {
  25. name: 'log',
  26. log
  27. };
  28. };

使用插件

  1. import { useApp, usePlugin } from '@swordjs/sword-framework';
  2. const plugin = usePlugin();
  3. plugin.add(useLogPlugin);
  4. const app = useApp();
  5. const init = () => {
  6. // ...
  7. };
  8. init();

这里useplugin的类型:

  1. declare const usePlugin: () => {
  2. add: (plugin: Plugin | (() => Plugin)) => Promise<Plugin[]>;
  3. };