Skip to content

等待条件配置

injectsWaitConditionexternalsWaitCondition 允许您配置代码执行前的等待条件,确保依赖的资源已经准备就绪。

Injects 内置等待条件

injects 代码会自动等待 externals 加载完成后再执行,无需手动配置。内置等待条件为:

javascript
!!window["${extensionId}"] && !!window["${extensionId}_externals"]
!!window["${extensionId}"] && !!window["${extensionId}_externals"]

这意味着即使你不配置 injectsWaitCondition,injects 代码也会确保 externals 中的库(react、antd 等)已就绪后才执行,避免因加载顺序导致的运行时错误。

内置条件默认使用 30 秒超时、50ms 检查间隔。

TIP

如果你同时配置了 injectsWaitCondition,你的条件会与内置条件自动合并(AND 关系),最终条件为:(内置条件) && (你的条件),超时和间隔使用你配置的值。

功能介绍

在某些场景下,网站可能有异步加载的模块或资源,如果直接执行 externals 或 injects 代码可能会因为依赖未就绪而报错。等待条件功能可以让代码在特定条件满足后再执行。

配置

typescript
// vite.config.ts
import { defineConfig } from "vite";

export default defineConfig({
  //  ...
  plugins: [
    //    ...
    ViteWebExtKits({
      // externals 代码执行前的等待条件
      externalsWaitCondition: {
        condition: "!!window.MyApp && !!window.MyApp.ready",
        timeoutSeconds: 10,
        checkInterval: 100,
      },

      // injects 代码执行前的附加等待条件(会与内置 externals 就绪检查自动合并)
      injectsWaitCondition: {
        condition: "!!document.querySelector('#app')",
        timeoutSeconds: 10,
        checkInterval: 100,
      },
    }),
  ],
});
// vite.config.ts
import { defineConfig } from "vite";

export default defineConfig({
  //  ...
  plugins: [
    //    ...
    ViteWebExtKits({
      // externals 代码执行前的等待条件
      externalsWaitCondition: {
        condition: "!!window.MyApp && !!window.MyApp.ready",
        timeoutSeconds: 10,
        checkInterval: 100,
      },

      // injects 代码执行前的附加等待条件(会与内置 externals 就绪检查自动合并)
      injectsWaitCondition: {
        condition: "!!document.querySelector('#app')",
        timeoutSeconds: 10,
        checkInterval: 100,
      },
    }),
  ],
});

配置参数

typescript
type WaitCondition = {
  // 等待条件,字符串形式的条件表达式
  condition: string;

  // 超时时间(秒)
  timeoutSeconds: number;

  // 检查间隔(毫秒)
  checkInterval: number;
};
type WaitCondition = {
  // 等待条件,字符串形式的条件表达式
  condition: string;

  // 超时时间(秒)
  timeoutSeconds: number;

  // 检查间隔(毫秒)
  checkInterval: number;
};

使用示例

typescript
import { ViteWebExtKits } from "@webextkits/vite-plugins";

export default defineConfig({
  plugins: [
    ViteWebExtKits({
      extensionId: "my-extension",

      // externals 代码执行前的等待条件
      externalsWaitCondition: {
        condition: "!!window.MyApp && !!window.MyApp.ready",
        timeoutSeconds: 10,
        checkInterval: 100,
      },

      // injects 附加等待条件(内置的 externals 就绪检查无需手动配)
      injectsWaitCondition: {
        condition: "!!document.querySelector('#app')",
        timeoutSeconds: 10,
        checkInterval: 100,
      },
    }),
  ],
});
import { ViteWebExtKits } from "@webextkits/vite-plugins";

export default defineConfig({
  plugins: [
    ViteWebExtKits({
      extensionId: "my-extension",

      // externals 代码执行前的等待条件
      externalsWaitCondition: {
        condition: "!!window.MyApp && !!window.MyApp.ready",
        timeoutSeconds: 10,
        checkInterval: 100,
      },

      // injects 附加等待条件(内置的 externals 就绪检查无需手动配)
      injectsWaitCondition: {
        condition: "!!document.querySelector('#app')",
        timeoutSeconds: 10,
        checkInterval: 100,
      },
    }),
  ],
});

使用场景

1. 等待网站模块加载完成

某些网站(如 Facebook)的模块是异步加载的,需要等待特定模块就绪:

typescript
externalsWaitCondition: {
  condition: "!!window.require && !!window.require('react')",
  timeoutSeconds: 15,
  checkInterval: 200
}
externalsWaitCondition: {
  condition: "!!window.require && !!window.require('react')",
  timeoutSeconds: 15,
  checkInterval: 200
}

2. 等待 DOM 特定状态

injects 已自动等待 externals 就绪,如果还需要额外等待页面状态,可以配置 injectsWaitCondition

typescript
injectsWaitCondition: {
  condition: "!!document.querySelector('#app') && !!window.APP_INITIALIZED",
  timeoutSeconds: 30,
  checkInterval: 500
}
injectsWaitCondition: {
  condition: "!!document.querySelector('#app') && !!window.APP_INITIALIZED",
  timeoutSeconds: 30,
  checkInterval: 500
}

最终生效的条件为:(!!window["my-extension"] && !!window["my-extension_externals"]) && (!!document.querySelector('#app') && !!window.APP_INITIALIZED)

生成的代码示例

配置等待条件后,生成的代码会被包装在等待函数中:

javascript
// 生成的 externals.js 示例
(function () {
  var startTime = Date.now();
  var timeoutMs = 10000; // 10秒
  var checkInterval = 100; // 100毫秒

  function checkCondition() {
    try {
      return (function () {
        return !!window.MyApp && !!window.MyApp.ready;
      })();
    } catch (e) {
      return false;
    }
  }

  function waitingForCondition(callback) {
    function check() {
      if (Date.now() - startTime > timeoutMs) {
        console.error(
          '[externals] 等待条件超时: "!!window.MyApp && !!window.MyApp.ready"'
        );
        console.error("[externals] 超过 10 秒未满足条件,代码未执行");
        return; // 超时后不执行代码
      }

      if (checkCondition()) {
        callback();
      } else {
        setTimeout(check, checkInterval);
      }
    }

    check();
  }

  waitingForCondition(function () {
    // 原始的 externals 代码在这里执行
    (function () {
      // ... externals 内容
    })();
  });
})();
// 生成的 externals.js 示例
(function () {
  var startTime = Date.now();
  var timeoutMs = 10000; // 10秒
  var checkInterval = 100; // 100毫秒

  function checkCondition() {
    try {
      return (function () {
        return !!window.MyApp && !!window.MyApp.ready;
      })();
    } catch (e) {
      return false;
    }
  }

  function waitingForCondition(callback) {
    function check() {
      if (Date.now() - startTime > timeoutMs) {
        console.error(
          '[externals] 等待条件超时: "!!window.MyApp && !!window.MyApp.ready"'
        );
        console.error("[externals] 超过 10 秒未满足条件,代码未执行");
        return; // 超时后不执行代码
      }

      if (checkCondition()) {
        callback();
      } else {
        setTimeout(check, checkInterval);
      }
    }

    check();
  }

  waitingForCondition(function () {
    // 原始的 externals 代码在这里执行
    (function () {
      // ... externals 内容
    })();
  });
})();

注意事项

  1. 条件表达式:必须是可以被 eval 执行的 JavaScript 表达式,返回布尔值
  2. 超时处理:超时后代码不会执行,会在控制台输出错误信息
  3. 性能影响:检查间隔不宜太小,建议 50-500ms 之间
  4. 错误处理:条件表达式执行出错会被捕获,视为条件未满足

Powered by Vitepress