Garfish.registerApp

用于注册子应用信息,为 Garfish 实例方法。

INFO
  1. Garfish.run() 中 apps 应用信息注册底层就是依赖 registerApp 的注册能力;
  2. registerApp 为 Garfish 实例方法,用户可调用该 API 动态注册子应用信息,若出现 Garfish.run() 中的同名 app 应用信息,将覆盖Garfish.run() 中的 app 应用信息(merge, not override);

类型

registerApp(list: interfaces.AppInfo | Array<interfaces.AppInfo>): Garfish;

默认值

示例

import Garfish from 'garfish';

// 注册单个应用:
Garfish.registerApp({
  name: 'vue-app',
  basename: '/demo',
  activeWhen: '/vue-app',
  entry: 'http://localhost:3000',
  props: {
    msg: 'vue-app msg',
  },
});

// 注册多个应用
Garfish.registerApp([
  {
    name: 'vue-app',
    activeWhen: '/vue-app',
    entry: 'http://localhost:3000',
  },
  {
    name: 'react-app',
    activeWhen: '/react-app',
    entry: 'http://localhost:2000',
  },
]);

Type AppInfo

AppInfo 为子应用 app 配置类型,此配置与 Garfish.run() 全局配置中 app 相关参数含义相同。

export interface AppInfo extends AppConfig, AppLifecycle {}
INFO

Garfish 处理 app 参数的原则是:

  1. 对于同名字段,子应用中的配置具备更高优先级;

  2. 默认情况下,Garfish 使用全局配置作为每个子应用配置;

  3. 针对单个子应用的信息配置不影响其它子应用;

参数

name

  • Type: string
  • 子应用名称,必选;
  • 请确保每个子应用名称唯一;

basename?

  • Type: string

  • 子应用的基础路径,可选,默认值为全局 basename

  • 通过路由驱动自动加载子应用时实际传递给子应用的 basename 为 basename + activeWhen 计算的值

  • 若手动载入渲染应用时 basename 为实际传入的值

  • 通过 provider 函数basename 参数透传给子应用,子应用需要将 basename 设置为相应子应用的基础路由,这是必须的;

  • 为什么子应用需要设置 basename ?

entry

  • Type: string
  • 子应用的入口资源地址,支持 HTML 和 JS 入口,必选

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 无效的异常

props?

  • Type: Object
  • 初始化时主应用传递给子应用的数据,可选。子应用 provider 导出函数 生命周期方法中将接收到此数据;

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;
  // disableLinkTransformToStyle  1.18.0 版本提供 ,默认值 false,禁用掉 link 自动 transform 成 style 的行为
  disableLinkTransformToStyle?: boolean;
  // excludeAssetFilter 1.18.0 版本提供,默认值为 undefined,用于过滤不需要再子应用沙箱中执行的资源例如 jsonp,url 参数为对应 script 的地址,返回 true 则会过滤掉该资源
  excludeAssetFilter?: (url: string) => 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,
        },
      }),
    ],
  },
});
DANGER

请注意:

如果你在沙箱内自定义的行为将会产生副作用,请确保在 recover 函数中清除你的副作用,garfish 将在应用卸载过程中执行 recover 函数销毁沙箱副作用,否则可能会造成内存泄漏。

  • 在什么情况下我应该关闭 sandbox ?

    Garfish 目前已默认支持沙箱 esModule 能力,若需要在 vm 沙箱支持 esModule 应用,请使用 @garfish/es-module garfish 官方插件支持此能力,但这会带来严重的性能问题,原因。如果你的项目不是很需要在 vm 沙箱下运行,此时可以关闭沙箱;

  • Garfish 沙箱机制

INFO

若开启快照沙箱,请注意:

  1. 快照沙箱无法隔离主、子应用
  2. 快照沙箱无法支持多实例(同时加载多个子应用)

activeWhen?

  • Type: string | ((path: string) => boolean)

  • 子应用的激活路径或激活条件,是子应用配置中的重要配置项,接收 string 和 函数类型,可选。

  • activeWhen 使用场景为基于路由模式加载子应用时,计算当前应激活的子应用的判断条件,当使用手动加载 loadApp 时将忽略 activeWhen 选项。如果你的应用是基于路由驱动式挂载子应用,你应该始终传递 activeWhen

  • 在每次发生路由变化时,Garfish 都会触发 activeWhen 的校验逻辑去判断当前应该激活的子应用;

  • 当参数为 string 类型时:

  • 当参数为 function 类型时:

    • function 将接受到参数 path,用户可在函数内定义判断逻辑,返回 true 表示激活当前应用,否则应返回 false
    • 示例
    import Garfish from "garfish";
    Garfish.run({
      ...,
      apps: [
        {
          name: "vue",
          activeWhen: (path) => path.startsWith('/vue-app') || path.startsWith('/sub-app')
          entry: 'http://localhost:3000'
        }
      ]
    })
    • 校验过程中,当参数为 function 类型时,Garfish 会将当前的路径传入激活函数分割以得到子应用的最长激活路径,并将 basename + 子应用最长激活路径 传递给子应用参数;
  • 什么时候不需要设置 activeWhen?

    activeWhen 为基于路由模式加载子应用时的激活路径(或条件),目的是为了寻找当前应该激活的子应用。当用户使用 loadApp 手动挂载应用时,此时可省略 activeWhen 参数。

DANGER
  1. 子应用如果本身具备路由,在微前端的场景下,必须把 basename 作为子应用的基础路径,没有基础路由,子应用的路由可能与主应用和其他应用发生冲突;

  2. 我们强留建议不要使用根路径作为子应用的激活条件,为什么?

cache?

  • Type: boolean
  • 是否缓存子应用。若已加载过应用,在缓存模式下将返回相同的应用实例,可选,默认值为 true
  • Garfish 默认会对加载过的 app 进行缓存策略,目的是为了节省二次渲染开销,避免重复的编译代码造成的性能浪费,以及避免逃逸代码可能造成的内存泄漏。若关闭此选项,将会严重影响子应用的加载速度,需要仔细权衡;
  • 在缓存模式下,Garfish 将不会执行子应用所有代码,仅执行 render ,可以避免逃逸代码造成的内存问题;
  • 缓存模式也存在一定的弊端,关于 Garfish 的缓存机制,请移步 Garfish 缓存机制

noCheckProvider

  • Type: boolean
  • 是否检查 provider 函数,可选,默认为 true;

asyncProviderTimeout

  • Type: number
  • 全局异步provider超时时间,默认是2000ms,设置为0的话,只允许同步provider;
  • 此项特性适用于那些不太方便处理成同步暴露provider的子应用,比如某些脚手架新建的项目,项目里看到的entry文件,实际上会被包裹一层并且动态import进来;