Garfish.run
用于初始化全局配置、注册子应用信息,并启动基于路由匹配的子应用自动渲染流程。
garfish 基于
activeWhen
参数自动进行子应用激活匹配,可参考 activeWhen 了解 garfish 路由匹配逻辑;
类型
run(options?: interfaces.Options): Garfish;
// type 定义
export interface Options extends Config, AppGlobalConfig, GlobalLifecycle {}
默认值
- {}
示例
import Garfish from "garfish";
import type { interfaces } from "garfish";
const config: interfaces.Options = {
/* global options */
basename: '/',
domGetter: '#subApp',
disablePreloadApp: false,
...
/* app infos */
apps: [
{
name: 'react',
activeWhen: '/react',
entry: 'http://localhost:3000',
...
}
],
/* lifecycle hooks */
beforeLoad(appInfo) {
console.log('子应用开始加载', appInfo.name);
},
afterLoad(appInfo) {
console.log('子应用加载完成', appInfo.name);
},
...
}
Garfish.run({ config });
参数
options
domGetter?
- Type: interfaces.DomGetter
export type DomGetter =
| string
| (() => Element | null)
| (() => Promise<Element>);
- 子应用的默认挂载点,可选,没有默认值,若省略需要在子应用 AppInfo 中单独指定。二者同时存在时,子应用指定优先级更高;
- 当提供
string
类型时需要其值是selector
, Garfish 内部会使用document.querySelector(domGetter)
去选中子应用的挂载点 - 当提供
string
类型的domGetter
时,子应用在触发渲染后并不会若当前文档流上并不存在挂载点,Garfish
框架内部在3s
内轮讯是否有挂载点 - 当提供函数时,将在子应用挂载过程中执行此函数,并期望返回一个 dom 元素;
- 若
domGetter
在子应用渲染时无法查询到挂载点,则会丢出domGetter
无效的异常
basename?
- Type: string
- 子应用的基础路径,可选,默认值为全局 basename;
- 通过路由驱动自动加载子应用时实际传递给子应用的 basename 为
basename + activeWhen
计算的值 - 若手动载入渲染应用时
basename
为实际传入的值 - 通过 provider 函数 的
basename
参数透传给子应用,子应用需要将 basename 设置为相应子应用的基础路由,这是必须的; - 为什么子应用需要设置 basename ?
props?
- Type: Object
- 初始化时主应用传递给子应用的数据,可选。子应用
provider
导出函数 生命周期方法中将接收到此数据;
disablePreloadApp?
- Type: boolean
- 是否禁用子应用的资源预加载,可选,默认值为
false
。默认情况下 Garfish 会开启子应用的资源预加载能力; - Garfish 会在用户端计算子应用打开的次数,应用的打开次数越多,预加载权重越大;
- 预加载能力在弱网情况和手机端将不会开启;
disableSourceListCollect?
- Type: boolean
- 是否禁用收集子应用资源列表,可选,默认值为
false
。默认情况下 Garfish 会自动收集子应用的资源,用于进行监控分析;
sandbox?
Type: SandboxConfig | false 可选,默认值为 全局 sandbox 配置,当设置为 false 时关闭沙箱;
SandboxConfig:
interface SandboxConfig {
// 是否开启快照沙箱,默认值为 false:关闭快照沙箱,开启 vm 沙箱
snapshot?: boolean;
// 是否自动以子应用入口的域名前缀对子应用 fetch 请求的进行补齐,默认值为 false
fixBaseUrl?: boolean;
// 是否自动以子应用入口的域名前缀对相对路径资源进行前缀修正,默认值为 true,v1.15.0 版本提供
fixStaticResourceBaseUrl?: boolean;
// 是否开启开启严格隔离,默认值为 false。开启严格隔离后,子应用的渲染节点将会开启 Shadow DOM close 模式,并且子应用的查询和添加行为仅会在 DOM 作用域内进行
strictIsolation?: boolean;
// modules 仅在 vm 沙箱时有效,用于覆盖子应用执行上下文的环境变量,使用自定义的执行上下文,默认值为[]
modules?: Array<Module> | Record<string, Module>;
// disableElementtiming 1.14.4 版本提供,默认值为 false,将会给子应用元素注入 elementtiming 属性,可以通过此属性获取子应用元素的加载时间
disableElementtiming?: boolean;
// fixOwnerDocument 1.17.2 版本提供 ,默认值 false,目前可能会存在 ownerDocument 逃逸的情况,设置为 true 之后将会避免 ownerDocument 逃逸
fixOwnerDocument?: boolean;
}
type Module = (sandbox: Sandbox) => OverridesData | void;
export interface OverridesData {
recover?: (context: Sandbox['global']) => void;
prepare?: () => void;
created?: (context: Sandbox['global']) => void;
override?: Record<PropertyKey, any>;
}
- 示例
Garfish.run({
sandbox: {
snapshot: false,
strictIsolation: false,
// 覆盖子应用 localStorage,使用当前主应用 localStorage
modules: [
() => ({
override: {
localStorage: window.localStorage,
},
}),
],
},
});
请注意: 如果你在沙箱内自定义的行为将会产生副作用,请确保在 recover 函数中清除你的副作用,garfish 将在应用卸载过程中执行 recover 函数销毁沙箱副作用,否则可能会造成内存泄漏。
在什么情况下我应该关闭 sandbox ?
Garfish 目前已默认支持沙箱 esModule 能力,若需要在 vm 沙箱支持 esModule 应用,请使用
@garfish/es-module
garfish 官方插件支持此能力,但这会带来严重的性能问题,原因。如果你的项目不是很需要在 vm 沙箱下运行,此时可以关闭沙箱;
若开启快照沙箱,请注意:
- 快照沙箱无法隔离主、子应用
- 快照沙箱无法支持多实例(同时加载多个子应用) :::
autoRefreshApp?
- Type: boolean
- 主应用在已经打开子应用页面的前提下,跳转子应用的子路由触发子应用的视图更新,默认值为
true
; - 若关闭
autoRefreshApp
, 则跳转 子应用子路由 将只能通过 Garfish.router 进行跳转,使用框架自身路由 API(如 react-router)跳转将失效; - 在某些场景下,通过主应用触发子应用视图更新可能会导致触发子应用的视图刷新而触发子应用的 hook,所以提供关闭触发子应用视图刷新的能力;
protectVariable?
- Type: string[]
- 在开启沙箱的情况下,提供使得 window 上的某些变量处于受保护状态的能力:这些值的读写不会受到沙箱隔离机制的影响,所有应用均可读取到,可选;
- 若希望在应用间共享 window 上的某些值,可将该值放置在数组中;
- 该属性与 setGlobalValue 功能相同,推荐使用
protectVariable
属性,通过protectVariable
可以明确的感知哪些值可能在应用间相互影响;
insulationVariable?
- Type: string[]
- 在开启沙箱的情况下,沙箱的子应用的环境变量将会从主应用中继承,举例:
- 在加载子应用前,主应用有一段:
window.xxxx = 123
- 子应用中可以获取获取主应用的环境变量
console.log(window.xxxx)
,输出 123 - 因为目前
Garfish
的主子应用环境是隔离的,但是子应用的环境继承至主应用时可能会造成一些影响不符合预期
- 在加载子应用前,主应用有一段:
- 若希望在子应用某些环境变量不继承至主应用,可以使用
insulationVariable
配置,例如:insulationVariable: ['xxxx']
- 'xxxx' 在子应用中将不会继承至主应用,
console.log(window.xxxx)
输出undefined
apps?
- Type: AppInfo[]
- 子应用列表信息,此字段参数信息与 registerApp 一致,可跳转查看详细介绍;
export interface AppInfo extends AppConfig, AppLifecycle {}
export interface AppGlobalConfig {
// 子应用的基础路径,通过路由驱动自动加载子应用时实际传递给子应用的 basename 为计算的值
// 若手动载入渲染应用时 basename 为这里指定的值
basename?: string;
// 子应用挂载点,同上,此处会覆盖全局默认的 domGetter
domGetter?: DomGetter;
// 传递给子应用的数据, 同上,此处会覆盖全局默认的 props
props?: Record<string, any>;
// 子应用的沙箱配置,同上,此处会覆盖全局默认的 sandbox
sandbox?: false | SandboxConfig;
}
export type AppConfig = Partial<AppGlobalConfig> & {
// 子应用的名称,需要唯一
name: string;
// 子应用的入口资源地址,支持 HTML 和 JS
entry?: string;
// 是否缓存子应用,默认值为 true;
cache?: boolean;
// 是否检查 provider, 默认为true;
noCheckProvider?: boolean;
};
- 示例
Garfish.run({
...,
apps: [
{
name: 'vue-app',
basename: '/demo',
activeWhen: '/vue-app',
entry: 'http://localhost:3000',
props: {
msg: 'vue-app msg',
}
}
}
]
beforeLoad
Type: async (appInfo: AppInfo, appInstance: App) => false | undefined
- 该
hook
的参数分别为:应用信息、应用实例; - 当返回
false
时将中断子应用的加载及后续流程;
- 该
Kind:
async
,sequential
Trigger:
- 在调用
Garfish.load
时触发该hook
- 子应用加载前触发,此时还未开始加载子应用资源;
- 在调用
示例
Garfish.run({
...,
beforeLoad(appInfo) {
console.log('子应用开始加载', appInfo.name);
}
afterLoad
Type: async (appInfo: AppInfo, appInstance: interfaces.App) => void
该
hook
的参数分别为:应用信息、应用实例;Kind:
async
,sequential
Trigger:
- 在调用
Garfish.load
后并且子应用加载完成时触发该hook
;
- 在调用
示例
Garfish.run({
...,
afterLoad(appInfo) {
console.log('子应用加载完成', appInfo.name);
}
})
errorLoadApp
Type: (error: Error, appInfo: AppInfo, appInstance: interfaces.App) => void
- 该
hook
的参数分别为:error
实例、appInfo
信息、appInstance
应用实例 - 一旦设置该 hook,子应用加载错误不会 throw 到文档流中,全局错误监听将无法捕获到;
- 该
Kind:
sync
,sequential
Trigger:
- 在调用
Garfish.load
过程中,并且加载失败时触发该hook
- 在调用
示例
Garfish.run({
...,
errorLoadApp(error, appInfo) {
console.log('子应用加载异常', appInfo.name);
console.error(error);
}
})
beforeMount
Type: (appInfo: AppInfo, appInstance: interfaces.App, cacheMode: boolean) => void
- 该
hook
的参数分别为:appInfo
信息、appInstance
应用实例、是否为缓存模式
渲染和销毁
- 该
Kind:
sync
,sequential
Previous Hook:
beforeEval
、afterEval
Trigger:
- 此时子应用资源准备完成,运行时环境初始化完成,准备开始渲染子应用 DOM 树;
- 在调用
app.mount
或app.show
触发该hook
,用户除了手动调用这两个方法外,Garfish Router
托管模式还会自动触发- 在使用
app.mount
渲染应用是cacheMode
为false
; - 在使用
app.show
渲染应用是cacheMode
为true
;
- 在使用
示例
Garfish.run({
...,
beforeMount(appInfo) {
console.log('子应用开始渲染', appInfo.name);
}
})
afterMount
Type: (appInfo: AppInfo, appInstance: interfaces.App, cacheMode: boolean) => void
- 该
hook
的参数分别为:appInfo
信息、appInstance
应用实例、是否为缓存模式
渲染和销毁
- 该
Kind:
sync
,sequential
Previous Hook:
beforeLoad
、afterLoad
、beforeMount
Trigger:
- 此时子应用 DOM 树已渲染完成,garfish 实例
activeApps
中已添加当前子应用 app 实例; - 在挂载过程中,会调用应用生命周期中的
render
函数,用户可在挂载前定义相关操作; - 若挂载过程中出现异常,会触发 errorMountApp,同时会清除已创建的 app 渲染容器 appContainer
- 此时子应用 DOM 树已渲染完成,garfish 实例
示例
Garfish.run({
...,
afterMount(appInfo) {
console.log('子应用渲染结束', appInfo.name);
}
})
beforeEval
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:
- 在子应用挂载过程中、实际执行代码前触发该 hook;
- 应用 html 内的 script 和动态创建的脚本执行时都会触发该 hook
- 此时 DOM 树已添加至文档流中,子应用代码准备执行;
- 若代码执行过程中抛出异常,则将触发 errorMountApp,否则触发 beforeEval
示例
Garfish.run({
...,
beforeEval(appInfo) {
console.log('子应用代码开始执行', appInfo.name);
}
})
afterEval
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
触发前触发; - 子应用 html 内的 script 和动态创建的脚本执行时都会触发该 hook
- 在实际执行代码后。
示例
Garfish.run({
...,
afterEval(appInfo) {
console.log('子应用代码执行完成', appInfo.name);
}
})
errorMountApp
Type: (error: Error, appInfo: AppInfo, appInstance: interfaces.App) => void
- 一旦设置该 hook,子应用加载错误不会 throw 到文档流中,全局错误监听将无法捕获到;
Kind:
sync
,sequential
Previous Hook:
beforeLoad
、afterLoad
、beforeMount
、afterMount
Trigger:
- 在渲染过程中出现异常会触发该
hook
,子应用同步执行的代码出现异常会触发该hook
,异步代码无法触发
- 在渲染过程中出现异常会触发该
示例
Garfish.run({
...,
errorMountApp(error, appInfo) {
console.log('子应用渲染异常', appInfo.name);
console.error(error);
}
})
beforeUnmount
- Type: ( appInfo: AppInfo, appInstance: interfaces.App) => void
- Kind:
sync
,sequential
- Previous Hook:
beforeLoad
、afterLoad
、beforeMount
、afterMount
- Trigger:
- 在调用
app.unmount
或app.hide
触发该hook
,用户除了手动调用这两个方法外,Garfish Router
托管模式还会自动触发- 在使用
app.unmount
渲染应用是cacheMode
为false
; - 在使用
app.hide
渲染应用是cacheMode
为true
;
- 在使用
- 此时子应用 DOM 元素还未卸载,副作用尚未清除;
- 此时子应用 DOM 树已渲染完成,garfish 实例
activeApps
中已添加当前子应用 app 实例;
- 在调用
afterUnmount
- Type: ( appInfo: AppInfo, appInstance: interfaces.App) => void
- Kind:
sync
,sequential
- Trigger:
- 此时,应用在渲和运行过程中产生的副作用已清除,DOM 已卸载,沙箱副作用已清除,garfish 实例
activeApps
当前 app 已移除; - 在应用销毁过程中会调用应用生命周期中的
destory
函数,用户可在销毁前定义相关操作; - 若应用卸载过程中出现异常,会触发 errorUnmountApp
- 此时,应用在渲和运行过程中产生的副作用已清除,DOM 已卸载,沙箱副作用已清除,garfish 实例
errorUnmountApp
Type: (error: Error, appInfo: AppInfo, appInstance: interfaces.App)=> void
- 一旦设置该 hook,子应用销毁错误不会向上 throw 到文档流中,全局错误监听将无法捕获到;
Kind:
sync
,sequential
Trigger:
- 在
app.unmount
或app.hide
销毁过程中出现异常则会触发该hook
,用户除了手动调用这两个方法外,Garfish Router
托管模式还会自动触发
- 在
示例
Garfish.run({
...,
errorUnmountApp(error, appInfo) {
console.log('子应用销毁异常', appInfo.name);
console.error(error);
}
})
onNotMatchRouter
Type: (path: string)=> void
- 该
hook
的参数分别为:应用信息、应用实例;
- 该
Kind:
sync
,sequential
Trigger:
- 路由发生变化当前未激活子应用且未匹配到任何子应用时触发
示例
Garfish.run({
...,
onNotMatchRouter(path) {
console.log('未匹配到子应用', path);
}
})