single-spa源码分析之按需加载

源码相关

与 activeWhen 相关

activeWhen API 可以控制页面是否需要加载

以下片段是源码及注释

// \single-spa-source-code\src\applications :447
/**
 * 得到一个函数,函数负责判断浏览器当前地址是否和用户给定的baseURL相匹配,匹配返回true,否则返回false
 */
function sanitizeActiveWhen(activeWhen) {
  // activeWhen 接收一个函数(箭头函数),将location传入 (location) => location.hash.startsWith('#/app1'); 调用后返回一个字符串
  // location.hash:hash属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)
  // startsWith() 方法用于检测字符串是否以指定的前缀开始
  let activeWhenArray = Array.isArray(activeWhen) ? activeWhen : [activeWhen];
  // 保证数组中每个元素都是一个函数
  activeWhenArray = activeWhenArray.map((activeWhenOrPath) =>
    typeof activeWhenOrPath === "function"
      ? activeWhenOrPath
      : // activeWhen如果是一个路径,则保证成一个函数
        pathToActiveWhen(activeWhenOrPath)
  );
  // 返回一个函数,函数返回一个 boolean 值
  return (location) =>
    activeWhenArray.some((activeWhen) => activeWhen(location)); // 调用用户配置的函数,传入location
}

// activeWhen传入的不是函数,而是字符串或者数组,则特殊处理
// '/app1', '/users/:userId/profile', '/pathname/#/hash' ['/pathname/#/hash', '/app1']
// 具体见官方文档api,有详细说明:https://zh-hans.single-spa.js.org/docs/api
export function pathToActiveWhen(path, exactMatch) {
  // 根据用户提供的baseURL,生成正则表达式
  const regex = toDynamicPathValidatorRegex(path, exactMatch);
  // 函数返回boolean值,判断当前路由是否匹配用户给定的路径
  return (location) => {
    // compatible with IE10
    let origin = location.origin;
    if (!origin) {
      origin = `${location.protocol}//${location.host}`;
    }
    const route = location.href
      .replace(origin, "")
      .replace(location.search, "")
      .split("?")[0];
    return regex.test(route);
  };
}

sanitizeActiveWhenpathToActiveWhen是两个关键方法,控制是否需要按需加载 app.js,像我目前项目中写的一般都是(location) => true,也就是默认加载所有 app.js,优化点在于activeWhen函数,能够实现按需加载(根据路径加载)。

single-spa提供了两种挂载方式,分为简单参数对象参数。(具体见官方文档 api,有详细说明:https://zh-hans.single-spa.js.org/docs/api)

简单参数
singleSpa.registerApplication(
  "appName",
  () => System.import("appName"),
  (location) => location.pathname.startsWith("appName")
);
对象参数
singleSpa.registerApplication({
    name: 'appName',
    app: () => System.import('appName'),
    activeWhen: '/appName'
    customProps: {}
})

二者区别在于如果选择对象参数时,需要走一层转换pathToActiveWhen函数,另外activeWhen属性也可以传递数组,一个数组中任何条件为真,则保留应用活动。如activeWhen:['/authority', '/test'],访问例如http://localhost:7000/test,http://localhost:7000/test,都能激活应用。作者在源码中也有相应的逻辑,let activeWhenArray = Array.isArray(activeWhen) ? activeWhen : [activeWhen];

https://zh-hans.single-spa.js.org/docs/api/#pathtoactivewhen,文档中详细介绍了pathToActiveWhen的例子。

single-spa规定我们使用按需时传入的格式,具体根据项目情况而定

如采用 Hash 模式:

(location) => location.hash.startsWith("#/app1");

如采用 history 模式:

(location) => location.pathname.startsWith("app1");

若是当前浏览器 URL 与#/app1相匹配时(假定使用的是 hash),
single-spa 调用sanitizeActiveWhen方法时,接收activeWhen参数,在\single-spa-source-code\src\applications :434 做了一层校验validateRegisterWithConfig(appNameOrConfig);,注意看validateRegisterWithConfig函数,其中allowsStringAndFunction箭头函数,规范和保证了activeWhen必须是字符串,或者函数或者数组

export function validateRegisterWithConfig(config) {
  // 1. 异常判断,应用的配置对象不能是数组或者null
  if (Array.isArray(config) || config === null)
    throw Error(
      formatErrorMessage(
        39,
        __DEV__ && "Configuration object can't be an Array or null!"
      )
    );
  // 2. 应用配置必须是指定的几个关键字
  const validKeys = ["name", "app", "activeWhen", "customProps"];
  // 过滤函数,将不是 validKeys 中的key,过滤出来。
  const invalidKeys = Object.keys(config).reduce(
    (invalidKeys, prop) =>
      validKeys.indexOf(prop) >= 0 ? invalidKeys : invalidKeys.concat(prop),
    []
  );
  // 如果存在无效的key,则抛出一个错误,表示书写不合法
  if (invalidKeys.length !== 0)
    throw Error(
      formatErrorMessage(
        38,
        __DEV__ &&
          // 配置对象只接受 validKeys 中的属性,其他的无效
          `The configuration object accepts only: ${validKeys.join(
            ", "
          )}. Invalid keys: ${invalidKeys.join(", ")}.`,
        validKeys.join(", "),
        invalidKeys.join(", ")
      )
    );
  // 3. 应用名称存在校验
  if (typeof config.name !== "string" || config.name.length === 0)
    throw Error(
      formatErrorMessage(
        20,
        __DEV__ &&
          // 应用名称必须存在,且不能是空字符串
          "The config.name on registerApplication must be a non-empty string"
      )
    );
  // app 属性只能是一个对象或者函数
  // 对象是一个已被解析过的对象,是一个包含各个生命周期的对象;
  // 加载函数必须返回一个 promise
  // 以上信息在官方文档中有提到:https://zh-hans.single-spa.js.org/docs/configuration
  if (typeof config.app !== "object" && typeof config.app !== "function")
    throw Error(
      formatErrorMessage(
        20,
        __DEV__ &&
          "The config.app on registerApplication must be an application or a loading function"
      )
    );
  // 第三个参数,可以是一个字符串,也可以是一个函数,也可以是两者组成的一个数组,表示当前应该被激活的应用的baseURL
  const allowsStringAndFunction = (activeWhen) =>
    typeof activeWhen === "string" || typeof activeWhen === "function";
  if (
    !allowsStringAndFunction(config.activeWhen) &&
    !(
      Array.isArray(config.activeWhen) &&
      config.activeWhen.every(allowsStringAndFunction)
    )
  )
    throw Error(
      formatErrorMessage(
        24,
        __DEV__ &&
          // activeWhen 必须是字符串,或者函数或者数组
          "The config.activeWhen on registerApplication must be a string, function or an array with both"
      )
    );
  // 5. 自定义属性校验, 必须是一个对象
  if (!validCustomProps(config.customProps))
    throw Error(
      formatErrorMessage(
        22,
        // customProps 必须是对象,不能是函数或者数组,也不能为空
        __DEV__ && "The optional config.customProps must be an object"
      )
    );
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值