Garfish 框架引入了插件化机制,目的是为了让开发者能够通过编写插件的方式来扩展更多功能,或为自身业务定制个性化功能;同时框架的基础能力也都是通过插件机制来实现,确保框架核心足够精简和稳定。
插件的功能范围没有严格的限制,一般有下面两种:
Garfish router、Garfish sandbox)Garfish Router 增加了全局方法和应用的自动渲染和销毁能力,下面让我们来以 Garfish router 为例,如何编写一个插件,来实现路由的能力。
当插件被注册到 Garfish 框架时,将会调用插件函数并将 GarfishInstance 作为参数传递,函数的返回值中包括插件的基本信息:name、version,除了基本信息外最重要的则是包括 hook,Garfish 框架将在应用的整个生命周期中触发 hook 的调用,可以在 hook 中对信息进行二次处理或执行特定的功能。
让我们从编写插件函数开始,建议在单独的文件中创建它并将其导出,如下所示,以保持插件逻辑的整洁和分离,在实际开发过程中我们建议将实际插件的内容放置一个函数中返回,以便插件在实际调用时可接收参数
Garfish Router 的这个 plugin 期望达到的目标是通过提供的 Router Map 后 Garfish 框架能够自动的完成微前端应用的渲染和销毁调度,从而降低典型中台中管理应用销毁和渲染的工作,提升开发效率。那么要实现这个需求我们需要依次实现以下功能:
appInfo 的类型,让 appInfo 类型提示支持 activeWhen、basename 等配置Garfish 增加 router 类型Garfish 实例扩展 router 方法,用于实现路由跳转和路由监听等能力bootstrap hook(该 hook 会在主应用触发 Garfish.run 后调用),触发 bootstrap 后
history.push、history.replace,监听 popstate 浏览器后退事件appInfo 的 activeWhen 进行规则判断,对应用进行渲染和销毁registerApp hook(该 hook 会在注册子应用时触发)
Garfish Router 就是通过 Garfish 的 Plugin 机制实现,以下案例精简了大部分逻辑,主要介绍如何编写插件来扩展 Garfish 的整体功能,若想了解实现,请参考 Garfish Router plugin
插件编写总结
Garfish 实例扩展方法,通过 declare module 直接扩展 Garfish 的 interfaces,然后通过插件函数获取 Garfish 的实例直接添加方法,用于扩展 Garfish 的能力namespace interfaces 直接扩展 Garfish config 和 AppInfo 配置npm 包,在 package.json 中添加 garfish-plugin 关键词通过调用 Garfish.usePlugin 方法将插件添加到你的应用程序中。
我们将使用在 如何编写插件 部分中创建的 routerPlugin 插件进行演示。
usePlugin() 方法第一个参数接收要安装的插件,在这种情况下为 routerPlugin 的返回值。
它还会自动阻止你多次使用同一插件,因此在同一插件上多次调用只会安装一次该插件,Garfish 内部通过插件执行后返回的 name 作为唯一标识来进行区分,在进行插件命名时,请确保不会和其他插件之间发生冲突。
usePlugin通过 Garfish.usePlugin 可以注册插件
pluginnamestringversion?stringbeforeBootstrap?(options: interfaces.Options) => void
hook 的第一个参数为 Garfish.run 提供的配置信息sync, sequentialGarfish.run 调用后触发hook 时配置未注册到全局bootstrap?(options: interfaces.Options) => void
hook 的第一个参数为 Garfish.run 提供的配置信息sync, sequentialGarfish.run 调用后触发hook 时配置已经注册到全局beforeBootstrapbeforeRegisterApp?(appInfo: interfaces.AppInfo | Array<interfaces.AppInfo>) => void
hook 的第一个参数为需要注册的应用信息sync, sequentialGarfish.run 且,提供了 apps 参数时触发Garfish.registerApp 调用时hook 是子应用信息尚未注册成功registerApp?(appInfo: interfaces.AppInfo | Array<interfaces.AppInfo>) => void
hook 的第一个参数为需要注册的应用信息sync, sequentialGarfish.run 且,提供了 apps 参数时触发Garfish.registerApp 调用时hook 是子应用信息注册成功Type: async (appInfo: AppInfo, appInstance: App) => false | undefined
hook 的参数分别为:应用信息、应用实例;false 时将中断子应用的加载及后续流程;Kind: async, sequential
Trigger:
Garfish.load 时触发该 hook示例
Type: async (appInfo: AppInfo, appInstance: interfaces.App) => void
该 hook 的参数分别为:应用信息、应用实例;
Kind: async, sequential
Trigger:
Garfish.load 后并且子应用加载完成时触发该 hook;示例
Type: (error: Error, appInfo: AppInfo, appInstance: interfaces.App) => void
hook 的参数分别为:error 实例、 appInfo 信息、appInstance 应用实例Kind: sync, sequential
Trigger:
Garfish.load 过程中,并且加载失败时触发该 hook示例
Type: (appInfo: AppInfo, appInstance: interfaces.App, cacheMode: boolean) => void
hook 的参数分别为:appInfo 信息、appInstance 应用实例、是否为 缓存模式 渲染和销毁Kind: sync, sequential
Previous Hook: beforeEval、afterEval
Trigger:
app.mount 或 app.show 触发该 hook,用户除了手动调用这两个方法外,Garfish Router 托管模式还会自动触发
app.mount 渲染应用是 cacheMode 为 false;app.show 渲染应用是 cacheMode 为 true;示例
Type: (appInfo: AppInfo, appInstance: interfaces.App, cacheMode: boolean) => void
hook 的参数分别为:appInfo 信息、appInstance 应用实例、是否为 缓存模式 渲染和销毁Kind: sync, sequential
Previous Hook: beforeLoad、afterLoad、beforeMount
Trigger:
activeApps 中已添加当前子应用 app 实例;render 函数,用户可在挂载前定义相关操作;示例
Type: (appInfo: AppInfo, code: string, env: Record<string, any>, url: string, options) => void
hook 的参数分别为:appInfo 信息、code 执行的代码、env 要注入的环境变量,url 代码的资源地址、options 参数选项(例如 async 是否异步执行、noEntry 是否是 noEntry 模式);Kind: sync, sequential
Previous Hook: beforeMount
Trigger:
示例
Type: (appInfo: AppInfo, code: string, env: Record<string, any>, url: string, options) => void
hook 的参数分别为:appInfo 信息、code 执行的代码、env 要注入的环境变量,url 应用访问地址、options 参数选项例如 async 是否异步执行、noEntry 是否是 noEntry 模式;Kind: sync, sequential
Previous Hook: beforeLoad、afterLoad
Trigger:
afterMount 触发前触发;示例
Type: (error: Error, appInfo: AppInfo, appInstance: interfaces.App) => void
Kind: sync, sequential
Previous Hook: beforeLoad、afterLoad、beforeMount、afterMount
Trigger:
hook,子应用同步执行的代码出现异常会触发该 hook,异步代码无法触发示例
sync, sequentialbeforeLoad、afterLoad、beforeMount、afterMountapp.unmount 或 app.hide 触发该 hook,用户除了手动调用这两个方法外,Garfish Router 托管模式还会自动触发
app.unmount 渲染应用是 cacheMode 为 false;app.hide 渲染应用是 cacheMode 为 true;activeApps 中已添加当前子应用 app 实例;sync, sequentialactiveApps 当前 app 已移除;destory 函数,用户可在销毁前定义相关操作;Type: (error: Error, appInfo: AppInfo, appInstance: interfaces.App)=> void
Kind: sync, sequential
Trigger:
app.unmount 或 app.hide 销毁过程中出现异常则会触发该 hook,用户除了手动调用这两个方法外,Garfish Router 托管模式还会自动触发示例
Type: (path: string)=> void
hook 的参数分别为:应用信息、应用实例;Kind: sync, sequential
Trigger:
示例