Web Worker - Jest - 无法在模块外使用“import.meta”

Posted

技术标签:

【中文标题】Web Worker - Jest - 无法在模块外使用“import.meta”【英文标题】:Web Worker - Jest - Cannot use 'import.meta' outside a module 【发布时间】:2021-08-18 23:56:19 【问题描述】:

我正在开发一个nextjs 10.1.3 内置网络应用程序。我们实施了一个 web worker 来提高其中一个页面的性能,并且计划继续添加更多的 worker;此外,所有代码都经过了适当的单元测试,并且在之前的 webpack 版本(第 4 版及更低版本)中使用 worker-loader 我们能够对其进行测试。

使用新的 webpack 5 版本,不再需要 worker-loader 插件;相反,使用新版本加载 Web Worker 的方式是new Worker(new URL("@/workers/task.worker.js", import.meta.url));

这样做,我的代码与npm build && npm start 一样正常工作;但是,当我尝试添加相应的单元测试时,我收到了以下错误:Cannot use 'import.meta' outside a module 一切都发生了,因为 import.meta.url 用于在浏览器中添加工作人员的位置。

我在网上阅读了很多关于 babel 的帖子,但我想摆脱那个选项。有没有其他选项可以用玩笑来模拟import.meta.url

非常欢迎任何帮助。这是当前配置。

package.json


  ...
    "@babel/core": "^7.8.6",
    "next": "^10.1.3",
    "react": "^16.13.0",
    "webpack": "^5.37.1"
    "devDependencies": 
        ...
        "enzyme": "^3.11.0",
        "enzyme-adapter-react-16": "^1.15.2",
        "jest": "^24.9.0",
        "jest-cli": "^25.1.0",
        ...
    
  ...

next.config.js

const 
...
 = process.env;

const basePath = "";
const COMMIT_SHA = [];

const  parsed: localEnv  = require("dotenv").config();
const webpack = require("webpack");
const withBundleAnalyzer = require("@next/bundle-analyzer")(
  enabled: process.env.ANALYZE === "true",
);

const nextConfig = 
  env: 
    NEXT_PUBLIC_COMMIT_SHA: COMMIT_SHA,
  ,
  images: 
    domains: [
      "...",
    ],
  ,
  future: 
    webpack5: true,
  ,
  productionBrowserSourceMaps: true,
  trailingSlash: true,
  reactStrictMode: true,
  webpack: (config, options) => 
    if (localEnv) 
      config.plugins.push(new webpack.EnvironmentPlugin(localEnv));
     else 
      config.plugins.push(new webpack.EnvironmentPlugin(process.env));
    
    config.module.rules.push(
      test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
      use: 
        loader: "url-loader",
        options: 
          limit: 100000,
          name: "[name].[ext]",
        ,
      ,
    );

    config.output = 
      ...config.output,
      chunkFilename: options.isServer
        ? `$options.dev ? "[name]" : "[name].[fullhash]".js`
        : `static/chunks/$options.dev ? "[name]" : "[name].[fullhash]".js`,
      publicPath: `/_next/`,
      globalObject: `(typeof self !== 'undefined' ? self : this)`,
    ;

    config.plugins.push(new webpack.IgnorePlugin(/pages.*\/__tests__.*/));

    config.plugins.push(
      new options.webpack.DefinePlugin(
        "process.env.NEXT_IS_SERVER": JSON.stringify(
          options.isServer.toString()
        ),
      )
    );

    return config;
  ,
;

module.exports = withBundleAnalyzer(nextConfig);

useEffect 工人

useEffect(() => 
    if (pageData.data?.length) 
      workerRef.current = new Worker(new URL("@/workers/task.worker.js", import.meta.url));
      workerRef.current.addEventListener("message", result => 
        if (result.error) 
          setWorkerError();
         else 
          updateData(result.data);
        
      );
      
      const ids = pageData.data.map(store => store.id);

      workerRef.current.postMessage(ids);
     else 
      setNoDataFound();
    

    return () => 
      workerRef.current && workerRef.current.terminate();
    ;
  , []);

jest.config.js

module.exports = 
  moduleDirectories: ["node_modules", "src", "static", "store"],
  modulePathIgnorePatterns: [
    "<rootDir>/node_modules/prismjs/plugins/line-numbers",
  ],
  testPathIgnorePatterns: [
    "<rootDir>/src/components/component-library",
    "<rootDir>/.next",
    "jest.config.js",
    "next.config.js",
  ],
  collectCoverageFrom: [
    "**/src/**",
    "**/store/**",
    "**/pages/**",
    "!**/__tests__/**",
    "!**/node_modules/**",
    "!**/component-library/**",
  ],
  testEnvironment: "node",
  collectCoverage: true,
  verbose: false,
  automock: false,
  setupFiles: ["./setupTests.js"],
  moduleNameMapper: 
    "@/components/(.*)$": "<rootDir>/src/components/$1",
    "@/functions/(.*)$": "<rootDir>/src/components/functions/$1",
    "@/services/(.*)$": "<rootDir>/src/components/services/$1",
    "@/workers/(.*)$": "<rootDir>/src/components/workers/$1",
    "@/scripts(.*)$": "<rootDir>/src/scripts/$1",
    "@/src(.*)$": "<rootDir>/src/$1",
    "@/__mocks__(.*)$": "<rootDir>/__mocks__/$1",
    "@/pages(.*)$": "<rootDir>/pages/$1",
    "@/store(.*)$": "<rootDir>/store/$1",
    "\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js",
  ,
  coveragePathIgnorePatterns: ["/node_modules/"],
  coverageThreshold: 
    global: 
      branches: 67,
      functions: 66,
      lines: 73,
      statements: 72,
    ,
  ,
  runner: "groups",
  extraGlobals: [],
  testTimeout: 10000,
;

【问题讨论】:

很确定你遇到了这个Jest ESM issue。 Jest 还不完全支持 ES 模块,import.meta 是 ESM 标准。 谢谢@MattCarlotta 我很高兴这个功能很快就会推出! 那么如何模拟这个 有什么更新吗?我仍然遇到这个问题。 SyntaxError 是否有任何解决方法:无法在模块外使用“import.meta”` 【参考方案1】:

在我的设置(typescript + ts-jest)中,我预先添加了以下节点选项以使其工作:

NODE_OPTIONS=--experimental-vm-modules

参考可以在这里找到:https://jestjs.io/docs/ecmascript-modules

【讨论】:

以上是关于Web Worker - Jest - 无法在模块外使用“import.meta”的主要内容,如果未能解决你的问题,请参考以下文章

在 web worker 中使用模块脚本

SyntaxError:无法在模块外使用 import 语句:运行 Jest-expo 测试时

Jest 无法从 npm 链接模块转换导入

测试套件无法运行在 vue3 中使用 jest 时找不到模块'vue-template-compiler

Jest 使用 Mock Service Worker (MSW) 或其他模拟离线网络?

无法使用 Jest 中的 openlayers 模块测试任何代码