使用 PNPM 的情况下,Jest 解决 ESM 依赖库的报错问题

环境

  • NX
  • PNPM
  • lodash-es
  • Jest

从 karma 转移到 Jest 遇到了如下报错

主要原因是 "node_modules" 文件夹中 ESM(ECMAScript Modules) 库不被 Jest 支持。

鉴于 Jest ESM 支持还在几乎不可用的试验阶段,而目前我主要是在公司项目上迁移到 Jest。所以本文主要采用 transformIgnorePatternsmoduleNameMapper 两种配置来解决这个问题。

shell 复制代码
Test suite failed to run

Jest encountered an unexpected token

Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.

By default "node_modules" folder is ignored by transformers.

Here's what you can do:
    • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
    • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript
    • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
    • If you need a custom transformation specify a "transform" option in your config.
    • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation

以下配置主要以 lodash-es 作为参考。

transformIgnorePatterns

官方文档的解释是:正则表达式模式字符串的数组,在转换之前与所有源文件路径匹配。如果文件路径与任何模式匹配,则不会对其进行转换。 即 transformIgnorePatterns 用于指定在进行代码转换时应该忽略的文件或文件夹。

而在 NX 默认的 Jest 配置中,配置为 node_modules/(?!.*\\.mjs$)。 这个正则表达式的含义是,匹配以 node_modules/ 开头的文件夹路径,但排除那些以 .mjs 为扩展名的文件夹路径。?! 是一个否定预查,表示不匹配这样的文件夹路径。

javascript 复制代码
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],

以上配置意思就是将会把以 .mjs 为扩展名的文件从 ESM 转换为 CommonJS,以支持 Jest。

添加转换 lodash-es

顺便支持一下 PNPM

javascript 复制代码
const esModules = ['.*\\.mjs$', 'lodash-es'].join('|');

export default {
    ...
    transformIgnorePatterns: [`node_modules/(?!.pnpm|${esModules})`],
    ...
}

转换后 failed 数量从 15 减少到 11,但是这么做会有一个转换的过程会有额外的支出,需要 51s。不过第一次转换完后貌似就会缓存然后就不用转换了。

支出更少的方法 moduleNameMapper

这种方法需要库本身有对应的 CommonJS,就不需要转换了。可以跑到 12s

javascript 复制代码
export default {
    ...
    moduleNameMapper: {
        '^lodash-es$': 'lodash',
    },
  ...
}

最终配置参考如下

javascript 复制代码
/* eslint-disable */
const esModules = ['.*\\.mjs$'].join('|');

export default {
  displayName: 'pc',
  preset: '../../jest.preset.js',
  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
  coverageDirectory: '../../coverage/apps/pc',
  moduleNameMapper: {
    '^lodash-es$': 'lodash',
  },
  transform: {
    '^.+\\.(ts|mjs|js|html)$': [
      'jest-preset-angular',
      {
        tsconfig: '<rootDir>/tsconfig.spec.json',
        stringifyContentPathRegex: '\\.(html|svg)$',
      },
    ],
  },
  transformIgnorePatterns: [`node_modules/(?!.pnpm|${esModules})`],
  snapshotSerializers: [
    'jest-preset-angular/build/serializers/no-ng-attributes',
    'jest-preset-angular/build/serializers/ng-snapshot',
    'jest-preset-angular/build/serializers/html-comment',
  ],
};

参考

  1. Jest setup "SyntaxError: Unexpected token export"
  2. Configuring Jest · Jest
  3. ECMAScript Modules · Jest
  4. Configuring Jest · Jest
相关推荐
前端技术1 分钟前
ArkTS第三章:声明式UI开发实战
java·前端·人工智能·python·华为·鸿蒙
码小瑞5 分钟前
画布文字在不同缩放屏幕上的归一化
前端
神の愛6 分钟前
java日志功能
java·开发语言·前端
小李子呢02117 分钟前
前端八股(1)--Promise 常用方法有哪些?和async和await的区别
前端
喵个咪11 分钟前
Go 语言 CMS 横评:风行 GoWind 对比传统 PHP/Java CMS 核心优势
前端·后端·cms
落魄江湖行14 分钟前
入门篇八 Nuxt4页面元信息与 SEO:让搜索引擎爱上你的网站
前端·typescript·seo·nuxt4
╰つ栺尖篴夢ゞ17 分钟前
Web之深入解析Cookie的安全防御与跨域实践
前端·安全·存储·cookie·跨域
木斯佳20 分钟前
前端八股文面经大全:腾讯前端一面(2026-04-04)·深度解析
前端·ai·鉴权·monorepo
code_Bo22 分钟前
kiro生成小程序商业案例
前端·微信小程序·小程序·云开发
yellowbuff23 分钟前
为什么你的 0.01 秒倒计时看起来一卡一卡的?
前端