Skip to content

WXT 模块

WXT 提供了一个"模块系统",让你可以在构建过程的不同阶段运行代码来修改构建行为。

添加模块

有两种方式可以将模块添加到你的项目中:

  1. NPM:安装一个 NPM 包,例如 @wxt-dev/auto-icons,然后将其添加到配置中:

    ts
    export default defineConfig({
      modules: ['@wxt-dev/auto-icons'],
    });

    在 NPM 上搜索 "wxt module" 是查找已发布 WXT 模块的好方法。

  2. 本地模块:在项目的 modules/ 目录中添加文件:

    plaintext
    <rootDir>/
      modules/
        my-module.ts

    要了解更多关于编写自定义模块的内容,请阅读 编写模块 文档。

模块选项

WXT 模块可能需要或允许设置自定义选项来改变其行为。选项有两种类型:

  1. 构建时选项:在构建过程中使用的配置,例如功能标志
  2. 运行时选项:在运行时访问的配置,例如回调函数

构建时选项放在 wxt.config.ts 中,运行时选项放在 app.config.ts 文件 中。请参阅每个模块的文档,了解哪些选项是必需的以及应该放在哪里。

如果你使用 TypeScript,模块会增强 WXT 的类型,因此如果选项缺失或不正确,你将收到类型错误。

执行顺序

模块的加载顺序与 Hook 的执行顺序相同。详情请参阅 Hooks 文档

编写模块

以下是一个基本的 WXT 模块示例:

ts
import { defineWxtModule } from 'wxt/modules';

export default defineWxtModule({
  setup(wxt) {
    // 你的模块代码写在这里...
  },
});

每个模块的 setup 函数在 wxt.config.ts 文件加载完成后执行。wxt 对象提供了编写模块所需的一切:

  • 使用 wxt.hook(...) 钩入构建生命周期并进行修改
  • 使用 wxt.config 获取项目 wxt.config.ts 文件中解析后的配置
  • 使用 wxt.logger 向控制台输出日志信息
  • 还有更多!

完整的属性和函数列表请参阅 API 参考

另外请务必阅读 所有可用的 Hooks —— 它们是编写模块的关键。

实用示例

模块较为复杂,需要对 WXT 的代码及其工作原理有更深入的了解。最好的学习方式是通过示例。

更新解析后的配置

ts
import { defineWxtModule } from 'wxt/modules';

export default defineWxtModule({
  setup(wxt) {
    wxt.hook('config:resolved', () => {
      wxt.config.outDir = 'dist';
    });
  },
});

添加构建时配置

ts
import { defineWxtModule } from 'wxt/modules';
import 'wxt';

export interface MyModuleOptions {
  // 在这里添加构建时选项...
}
declare module 'wxt' {
  export interface InlineConfig {
    // 为 wxt.config.ts 中的 "myModule" 键添加类型
    myModule: MyModuleOptions;
  }
}

export default defineWxtModule<AnalyticModuleOptions>({
  configKey: 'myModule',

  // 构建时配置可通过 setup 的第二个参数获取
  setup(wxt, options) {
    console.log(options);
  },
});

添加运行时配置

ts
import { defineWxtModule } from 'wxt/modules';
import 'wxt/utils/define-app-config';

export interface MyModuleRuntimeOptions {
  // 在这里添加运行时选项...
}
declare module 'wxt/utils/define-app-config' {
  export interface WxtAppConfig {
    myModule: MyModuleOptions;
  }
}

运行时选项通过以下方式获取:

ts
const config = getAppConfig();
console.log(config.myModule);

这在生成运行时代码时非常有用。

添加自定义入口选项

模块可以通过增强入口选项类型来为入口添加自定义选项。这允许你添加在构建过程中可以访问的自定义配置。

ts
import { defineWxtModule } from 'wxt/modules';
import 'wxt';

declare module 'wxt' {
  export interface BackgroundEntrypointOptions {
    // 为 background 入口添加自定义选项
    myCustomOption?: string;
  }
}

export default defineWxtModule({
  setup(wxt) {
    wxt.hook('entrypoints:resolved', (_, entrypoints) => {
      const background = entrypoints.find((e) => e.type === 'background');
      if (background) {
        console.log('Custom option:', background.options.myCustomOption);
      }
    });
  },
});

现在用户可以在入口中设置自定义选项:

ts
export default defineBackground({
  myCustomOption: 'custom value',
  main() {
    // ...
  },
});

这对所有其他 JS 和 HTML 入口同样适用,以下是如何从 HTML 文件传递自定义选项的示例。

html
<html>
  <head>
    <meta name="wxt.myHtmlOption" content="custom value" />
    <title>Popup</title>
  </head>
  <body>
    <!-- ... -->
  </body>
</html>

生成输出文件

ts
import { defineWxtModule } from 'wxt/modules';

export default defineWxtModule({
  setup(wxt) {
    // 相对于输出目录
    const generatedFilePath = 'some-file.txt';

    wxt.hook('build:publicAssets', (_, assets) => {
      assets.push({
        relativeDest: generatedFilePath,
        contents: 'some generated text',
      });
    });

    wxt.hook('build:manifestGenerated', (_, manifest) => {
      manifest.web_accessible_resources ??= [];
      manifest.web_accessible_resources.push({
        matches: ['*://*'],
        resources: [generatedFilePath],
      });
    });
  },
});

该文件可以在运行时加载:

ts
const res = await fetch(browser.runtime.getURL('/some-text.txt'));

添加自定义入口

entrypoints/ 目录下的现有文件被发现后,可以使用 entrypoints:found Hook 来添加自定义入口。

INFO

entrypoints:found Hook 在对入口列表进行验证之前触发。因此,任何自定义入口仍会被检查是否有重复名称,并在调试时记录日志。

ts
import { defineWxtModule } from 'wxt/modules';

export default defineWxtModule({
  setup(wxt) {
    wxt.hook('entrypoints:found', (_, entrypointInfos) => {
      // 添加你的新入口
      entrypointInfos.push({
        name: 'my-custom-script',
        inputPath: 'path/to/custom-script.js',
        type: 'content-script',
      });
    });
  },
});

生成运行时模块

.wxt 中创建文件,添加导入别名,并为导出的变量添加自动导入。

ts
import { defineWxtModule } from 'wxt/modules';
import { resolve } from 'node:path';

export default defineWxtModule({
  imports: [
    // 添加自动导入
    { from: '#analytics', name: 'analytics' },
    { from: '#analytics', name: 'reportEvent' },
    { from: '#analytics', name: 'reportPageView' },
  ],

  setup(wxt) {
    const analyticsModulePath = resolve(
      wxt.config.wxtDir,
      'analytics/index.ts',
    );
    const analyticsModuleCode = `
      import { createAnalytics } from 'some-module';

      export const analytics = createAnalytics(getAppConfig().analytics);
      export const { reportEvent, reportPageView } = analytics;
    `;

    addAlias(wxt, '#analytics', analyticsModulePath);

    wxt.hook('prepare:types', async (_, entries) => {
      entries.push({
        path: analyticsModulePath,
        text: analyticsModuleCode,
      });
    });
  },
});

生成声明文件

ts
import { defineWxtModule } from 'wxt/modules';
import { resolve } from 'node:path';

export default defineWxtModule({
  setup(wxt) {
    const typesPath = resolve(wxt.config.wxtDir, 'my-module/types.d.ts');
    const typesCode = `
      // 声明全局类型,执行类型增强
    `;

    wxt.hook('prepare:types', async (_, entries) => {
      entries.push({
        path: 'my-module/types.d.ts',
        text: `
          // 声明全局类型,执行类型增强等
        `,
        // 重要 - 没有这一行,你的声明文件将不会成为 TypeScript 项目的一部分:
        tsReference: true,
      });
    });
  },
});

示例模块

你也可以查看其他人编写并发布的模块代码。以下是一些示例: