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
可以注册插件
plugin
name
string
version?
string
beforeBootstrap?
(options: interfaces.Options) => void
hook
的第一个参数为 Garfish.run
提供的配置信息sync
, sequential
Garfish.run
调用后触发hook
时配置未注册到全局bootstrap?
(options: interfaces.Options) => void
hook
的第一个参数为 Garfish.run
提供的配置信息sync
, sequential
Garfish.run
调用后触发hook
时配置已经注册到全局beforeBootstrap
beforeRegisterApp?
(appInfo: interfaces.AppInfo | Array<interfaces.AppInfo>) => void
hook
的第一个参数为需要注册的应用信息sync
, sequential
Garfish.run
且,提供了 apps
参数时触发Garfish.registerApp
调用时hook
是子应用信息尚未注册成功registerApp?
(appInfo: interfaces.AppInfo | Array<interfaces.AppInfo>) => void
hook
的第一个参数为需要注册的应用信息sync
, sequential
Garfish.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
, sequential
beforeLoad
、afterLoad
、beforeMount
、afterMount
在调用 app.unmount
或 app.hide
触发该 hook
,用户除了手动调用这两个方法外,Garfish Router
托管模式还会自动触发
app.unmount
渲染应用是 cacheMode
为 false
;app.hide
渲染应用是 cacheMode
为 true
;此时子应用 DOM 元素还未卸载,副作用尚未清除;
此时子应用 DOM 树已渲染完成,garfish 实例 activeApps
中已添加当前子应用 app 实例;
sync
, sequential
此时,应用在渲和运行过程中产生的副作用已清除,DOM 已卸载,沙箱副作用已清除,garfish 实例 activeApps
当前 app 已移除;
在应用销毁过程中会调用应用生命周期中的 destory
函数,用户可在销毁前定义相关操作;
若应用卸载过程中出现异常,会触发 errorUnmountApp
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:
示例