Web Workers
本文将介绍在 Rslib 项目中如何配置和使用 Web Workers。
Note
使用 Web Workers 时,仅支持生成 ESM 格式的产物,因此 format 必须设置为 'esm'(默认值)。
使用 Worker 构造器
基本用法
你可以使用标准构造器语法创建 Worker:
index.ts
new Worker(new URL('./worker.ts', import.meta.url));
Rslib 会重写 Worker URL,使其指向生成的 JavaScript 文件,并将 Worker 输出为 ES 模块:
index.js
new Worker(new URL('./worker.js', import.meta.url), {
type: 'module',
});
更多 Worker 语法可以查看 Rspack - Web Workers。
限制
Rslib 依赖静态分析处理 new Worker 及类似的 Worker API,因此必须直接传入 new URL('./worker.ts', import.meta.url)。URL 字符串和通过变量传入的 URL 对象均不受支持:
new Worker('./worker.ts');
const workerUrl = new URL('./worker.ts', import.meta.url);
new Worker(workerUrl);
产物模式
lib.bundle 配置项会影响 Worker 的构建方式。下面以同一组源码为例,展示 bundle 和 bundleless 模式分别生成的产物:
export const worker = new Worker(new URL('./worker.ts', import.meta.url));
import { add } from './helper';
self.onmessage = ({ data }: MessageEvent<[number, number]>) => {
self.postMessage(add(data[0], data[1]));
};
export const add = (left: number, right: number) => left + right;
Bundle 模式
在 bundle 模式下,Rslib 会将 Worker 入口拆分为独立 chunk,并将 Worker 导入的模块打包到该 chunk 中:
const worker = new Worker(new URL('./worker.js', import.meta.url), {
type: 'module',
});
export { worker };
const add = (left, right) => left + right;
self.onmessage = ({ data }) => {
self.postMessage(add(data[0], data[1]));
};
export {};
Bundleless 模式
在 bundleless 模式下,Rslib 会保留源码的模块结构,并将 Worker URL 和 Worker 内部的导入重写为对应的 ESM 产物路径:
const worker = new Worker(new URL('./worker.js', import.meta.url), {
type: 'module',
});
export { worker };
import { add } from './helper.js';
self.onmessage = ({ data }) => {
self.postMessage(add(data[0], data[1]));
};
const add = (left, right) => left + right;
export { add };
使用 query 后缀导入
Rslib 支持在 bundle 模式下通过 query 后缀导入 Web Worker,详情请参考 Rsbuild - Web Workers。
输出独立 Worker 文件
你可以在导入请求后添加 ?worker 来导入 Web Worker 脚本,Rslib 会为该 Worker 脚本生成独立的 ESM 文件:
index.ts
import MyWorker from './worker.ts?worker';
export const worker = new MyWorker();
内联 Worker
你可以在导入请求后添加 ?worker&inline 来导入 Web Worker 脚本,Rslib 会在导入该 Worker 的 JavaScript 文件中内联 Worker 代码,不再生成独立的 Worker 文件:
index.ts
import InlineWorker from './worker.ts?worker&inline';
export const worker = new InlineWorker();
类型声明
当你在 TypeScript 代码中使用 query 后缀导入 Worker 时,TypeScript 可能会提示该模块缺少类型定义:
TS2307: Cannot find module './worker.ts?worker' or its corresponding type declarations.
此时你可以在 tsconfig.json 中添加 @rslib/core 提供的 预设类型:
tsconfig.json
{
"compilerOptions": {
"types": ["@rslib/core/types"]
}
}
预设类型中已包含 *?worker、*?worker&inline 和 *?inline&worker 的类型声明。