Create React App中Web Workers致Jest报错:Cannot use 'import.meta' outside a module
解决方案:无需Eject即可在Create React App中使用Web Workers且兼容Jest
问题背景
在Create React App项目中使用如下代码创建Web Worker时:
const workerSimplerExample: Worker = useMemo( () => new Worker(new URL("../workers/simple-example.ts", import.meta.url), {type:"module"}), [] );
开发和生产构建均正常,但执行npm test或yarn test时,Jest会抛出错误:SyntaxError: Cannot use 'import.meta' outside a module,且不想通过eject修改Jest/Babel配置。
方案1:Mock Worker与import.meta.url(推荐)
在测试环境中替换Worker的实现,并Mock import.meta.url,避免触发不支持的语法。
- 在项目的
src/setupTests.ts文件中添加以下代码:
// 模拟Web Worker类 class MockWorker { constructor(_url: string, _options?: any) { this.postMessage = jest.fn(); this.onmessage = null; this.onerror = null; } postMessage: jest.Mock; onmessage: ((e: MessageEvent) => void) | null; onerror: ((e: ErrorEvent) => void) | null; terminate = jest.fn(); } // Mock import.meta.url Object.defineProperty(import.meta, 'url', { value: 'http://localhost:3000', }); // 全局替换Worker global.Worker = MockWorker as unknown as typeof Worker;
- 重新执行测试命令,此时Jest会使用Mock的Worker,不再触发
import.meta相关错误。
方案2:环境区分,测试环境返回Mock Worker
在组件中直接判断环境,测试环境下不创建真实Worker,避免执行含import.meta的代码:
// 定义Mock Worker类型 type MockWorker = { postMessage: jest.Mock; onmessage: ((e: MessageEvent) => void) | null; onerror: ((e: ErrorEvent) => void) | null; terminate: jest.Mock; }; const workerSimplerExample: Worker | MockWorker = useMemo(() => { if (process.env.NODE_ENV === 'test') { // 测试环境返回Mock实例 return { postMessage: jest.fn(), onmessage: null, onerror: null, terminate: jest.fn(), }; } // 生产/开发环境创建真实Worker return new Worker(new URL("../workers/simple-example.ts", import.meta.url), {type:"module"}); }, []);
该方案无需额外配置文件,直接在组件内处理环境分支。
方案3:将Worker文件放入Public目录,避免使用import.meta.url
把Worker文件编译后放到Public目录,直接通过静态路径访问,彻底避开import.meta:
- 在
package.json中添加编译Worker的脚本:
"scripts": { "build-worker": "tsc src/workers/simple-example.ts --outDir public/workers --target ESNext --module ESNext", "prestart": "npm run build-worker", "prebuild": "npm run build-worker" }
- 修改组件中创建Worker的代码:
const workerSimplerExample: Worker = useMemo( () => new Worker('/workers/simple-example.js', {type:"module"}), [] );
- 执行
npm start或npm run build时,会自动先编译Worker文件到Public目录,测试时因代码未使用import.meta,不会触发Jest错误。
内容的提问来源于stack exchange,提问作者Tyler V.
相关产品推荐
相关产品推荐

