ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ts-jest 故障排查实战:CI 模块解析、node_modules 转换与测试卡顿三大难题的解决之道

ts-jest 故障排查实战:CI 模块解析、node_modules 转换与测试卡顿三大难题的解决之道 测试开发工具【免费下载链接】ts-jestA Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.项目地址https://gitcode.com/gh_mirrors/ts/ts-jest点击查看免费下载本文以 ts-jest 28.x 版本的官方 Troubleshooting 指南仓库内 website/versioned_docs/version-28.0/guides/troubleshooting.md为核心骨架编写。使用 ts-jest 开发时最常见的三类问题——CI 环境下模块找不到、第三方 node_modules 语法无法执行、导入依赖时测试长时间卡顿——几乎都能在这份指南中找到对应解法。读完本文你将掌握roots、moduleDirectories、moduleNameMapper、transformIgnorePatterns、allowJs与isolatedModules的组合运用并理解这些问题背后 ts-jest 的模块解析与编译原理。指南的适用范围先判断问题归属ts-jest 是带 source map 支持的 Jest transformer让你可以用 Jest 测试 TypeScript 项目。当测试运行时出现问题第一步不是急着改配置而是判断问题到底出在 Jest 本身还是出在 ts-jest 的转换环节。如果问题与模块执行、mock、test runner 相关请先参考 Jest 官方的 Troubleshooting 指南本文只聚焦与 ts-jest 转换行为直接相关的问题。本文内容对应 ts-jest 28.x 时代即website/versioned_docs/version-28.0版本快照仓库 website/docs 下的最新版指南还补充了 ESM.mjs、type: module场景的处理方式可对照阅读。下面逐一拆解指南中的三大问题及其标准解法。问题一CI 环境下运行 ts-jest 报 Cannot find module ... from ...现象在 CI持续集成机器上运行 Jest 测试时出现形如Cannot find module from 的报错。这类错误的核心是Jest 的模块解析系统找不到被测模块的真实物理路径。CI 环境与本地环境的目录结构、安装方式、包管理器行为都可能不同因此本地能跑的测试在 CI 上失败是常见现象。解决思路四个检查点指南给出的标准排查顺序如下按步骤逐一核对即可。检查点 1roots是否覆盖了源码根目录roots定义了 Jest 搜索测试文件和模块的根路径。如果rootDir没有被正确引用Jest 就无从定位文件。在现有 jest 配置中补充module.exports { // ...原有配置 roots: [rootDir] }rootDir是 Jest 内置令牌指向配置文件所在目录。如果你的模块或测试分布在多个目录也可以传入数组如roots: [rootDir/src, rootDir/test]。检查点 2moduleDirectories与modulePaths是否包含模块目录Jest 默认从node_modules查找依赖但某些项目会把可复用的模块放在自定义目录如 monorepo 中的packages/*或内部lib/。此时需要显式声明module.exports { // ...原有配置 moduleDirectories: [node_modules, module-directory], modulePaths: [path-of-module] }moduleDirectories追加需要参与解析的目录名数组元素会被拼接到各搜索路径下modulePaths追加从根路径出发的绝对模块搜索路径效果类似在环境变量NODE_PATH中追加路径。检查点 3moduleNameMapper是否把导入路径映射到真实物理路径当模块通过别名、路径映射或第三方库的入口导入时Jest 无法直接解析需要手动映射module.exports { // ...原有配置 moduleNameMapper: { import-path: rootDir/real-physical-path } }import-path是源码中的导入写法通常配合正则或通配符如^shared/(.*)$: rootDir/shared/$1右侧是它在仓库中的真实位置。若项目使用了 TypeScript 的paths映射ts-jest 也提供了对应的支持方式可参考仓库文档 paths-mapping 与相关实现 src/config/paths-to-module-name-mapper.ts。检查点 4GitHub 目录大小写与本地不一致指南特别提醒了一个容易被忽略的坑GitHub 上的文件夹名可能与本地不一致——即便你在本地重命名了目录GitHub 有时也不会同步更新大小写。此时应通过 Git 重命名并提交git mv source destination然后提交这次变更。这能确保远端仓库与本地目录结构完全一致避免 CI 拉取后路径错位。源码佐证预设中如何约束模块范围从仓库源码看ts-jest 默认预设通过transform与testMatch约束处理范围。src/constants.ts 中定义了默认测试匹配模式export const DEFAULT_JEST_TEST_MATCH [**/__tests__/**/*.[jt]s?(x), **/?(*.)(spec|test).[jt]s?(x)]而 src/presets/create-jest-preset.ts 中的createDefaultPreset只注册了.tsx?的转换规则。这意味着若你的自定义目录不在 Jest 默认测试匹配范围内就需要通过上述roots、moduleDirectories、moduleNameMapper显式声明。此外仓库 e2e/tests/transform-js.test.ts 等端到端测试通过runJest真实拉起 Jest 进程验证了各类配置在编译compiler与转译transpiler两种模式下的可用性可作为排查配置时的参考样例。问题二SyntaxError: Cannot use import statement outside a module现象运行测试时 Jest 抛出SyntaxError: Cannot use import statement outside a module 22 | import Component from ../../node_modules/some-module/lib; | ^错误信息通常直接指明是哪个模块示例中的some-module出了问题该 node_modules 包发布的是 ESM 语法import/export但 Jest 默认不对 node_modules 内的文件做转换导致 Node 在 CommonJS 环境下直接执行 ESM 源码而报错。解决方案用transformIgnorePatterns白名单化目标模块Jest 的transformIgnorePatterns默认排除整个node_modules。要允许其中特定模块参与转换使用否定前瞻技巧module.exports { // ...原有配置 transformIgnorePatterns: [node_modules/(?!(some-module|another-module))] }这样some-module与another-module将被 ts-jest 转换其余 node_modules 包仍保持不转换的默认行为。要点正则中的(?!(...))表示后面不能跟这些名字因此凡是命中括号内名单的模块路径都不被 ignore多个模块用|分隔中间不要有空格空格会参与路径匹配导致失效此配置只解决模块需要被转换的问题不改变模块的解析路径。源码佐证ts-jest 的转换模式与预设从 src/constants.ts 可以看到 ts-jest 支持的几类转换模式export const TS_TRANSFORM_PATTERN ^.\\.tsx?$ export const ESM_TS_TRANSFORM_PATTERN ^.\\.m?tsx?$ export const TS_JS_TRANSFORM_PATTERN ^.\\.[tj]sx?$ export const ESM_TS_JS_TRANSFORM_PATTERN ^.\\.m?[tj]sx?$ export const JS_TRANSFORM_PATTERN ^.\\.jsx?$TS_JS_TRANSFORM_PATTERN^.\\.[tj]sx?$表示 ts-jest 同时处理.ts/.tsx/.js/.jsx这正是混编 JS 项目预设 presets/js-with-ts/jest-preset.js 的转换范围presets/default/jest-preset.js 则只处理 TypeScript 文件^.\\.tsx?$。因此当你要转换某个 node_modules 内的 ESM 包时需保证该包文件的扩展名落在当前transform正则的覆盖范围内若包内是.js而你的配置只匹配.ts即使加了transformIgnorePatterns白名单也不会生效应改用TS_JS_TRANSFORM_PATTERN或为.js单独补充转换规则。新版指南的 ESM 补充场景仓库当前版指南 website/docs/guides/troubleshooting.md 对该问题做了细分28.x 指南未覆盖属后续版本补充可按需升级 ts-jest 后采用问题文件是.mjs扩展名可以不为每个包单独列名而是加一条专门转换 node_modules 下.mjs文件的规则让 ts-jest 把它们统一转成 CommonJS包在package.json中声明了type: module此时包内.js文件按 ESM 语义执行仍需逐个在transformIgnorePatterns中列名。这两类场景本质都是ESM 源码需要被转译与 28.x 指南中transformIgnorePatterns的思路一脉相承。问题三导入依赖时测试卡住、长时间无响应现象在禁用缓存如jest --no-cache的情况下Jest 处理文件耗时极长看起来像卡死。原因分析指南明确指出ts-jest 内部使用 TypeScript 编译器 API 把 ts/js 文件转换为 js 文件而不是像 Babel/SWC/esbuild 那样逐文件快速转译。如果配置不当ts-jest 会加载远超测试所需的文件导致机器内存和 CPU 被大量占用、测试明显变慢。一个典型诱因是ts-jest 被配置为同时处理 JavaScript 与 TypeScript 文件。文件数量倍增后编译器需要解析的程序变大耗时随之暴涨。解决方案只转换必要的内容第一步关闭 tsconfig 中的allowJs检查 tsconfig 文件确保compilerOptions.allowJs未开启或显式为false{ compilerOptions: { allowJs: false } }allowJs开启后TypeScript 编译器会把.js文件纳入编译范围等于让 ts-jest 连带处理所有 JS 文件这是性能恶化的主要来源之一。第二步收窄 jest 配置中的transform正则检查transform是否只把.ts文件交给 ts-jest。如果当前写的是同时匹配 t/j 的正则改为只匹配.tsmodule.exports { // ...原有配置 transform: { - ^.\\.(t|j)s$: [ts-jest, {}], ^.\\.ts$: [ts-jest, { isolatedModules: true }], }, }注意从 src/constants.ts 的预设模式看ts-jest 官方默认预设createDefaultPreset用的就是^.\\.tsx?$只匹配 ts/tsx而混编 JS 的预设才使用^.\\.[tj]sx?$。如果你的项目并不需要测试 JS 文件就应保持只匹配.ts避免把 JS 文件拖进编译流程。仓库 e2e/transform-js/jest-compiler-cjs.config.ts 展示了混编场景下的显式配置写法可作对照。第三步开启isolatedModules转译模式可选isolatedModules: true会让 ts-jest 像 Babel/SWC/esbuild 一样逐文件独立转译、跳过类型检查测试速度大幅提升。在 28.x 时代该选项可写在 ts-jest 的 transform 参数里如上面的 diff 所示默认值为false它的代价是失去类型检查能力且部分依赖跨文件信息的功能会受限例如const enumconst 枚举内联——这与 TypeScript 官方对isolatedModules的语义一致因为每个文件必须能独立编译在新版本中ts-jest配置项里的isolatedModules已标记为DEPRECATED官方建议改在tsconfig.json的compilerOptions.isolatedModules中声明详见仓库文档 isolatedModules option。升级到新版本时请迁移写法。源码佐证转译模式的底层实现ts-jest 的转译模式基于 TypeScript 的transpileModule语义实现对应源码 src/transpilers/typescript/transpile-module.ts。该文件复刻了 TypeScript 内部transpile.ts的实现并做了裁剪移除声明文件生成、允许自定义 AST transformer 接入且使用一个极简 lib.d.tsbarebonesLibContent代替完整标准库——只声明了Boolean、Function、Object、String、Array、Symbol等最小全局类型。这意味着转译模式不依赖完整类型环境每个文件独立产出因而更快、更省内存代价则是不做语义级类型检查跨文件错误如类型不匹配、模块解析缺失不会被报告。在 28.x 的旧编译器实现 src/legacy/compiler/ts-compiler.spec.ts 中也有对应测试当tsconfig.isolatedModules为true时getResolvedModules不再做模块解析、getCompiledOutput走独立转译路径测试快照直接验证了转译输出的差异——这正是关闭类型检查换速度在实现层的体现。进阶优化收窄include指南和 isolatedModules option 文档还给出了一条性能优化建议当采用完整编译模式isolatedModules: false时通过收窄 tsconfig 的include减小编译器加载的文件集合{ // ...其他配置 include: [my-typings/*, my-global-modules/*] }include中列出的文件越少测试运行能获得的性能提升越大。但要权衡如果include过窄ts-jest 可能识别不到测试真正需要的自定义类型、全局模块等文件导致运行时缺类型。建议让include恰好覆盖测试环境所需的最小文件集合兼顾性能与正确性。三大问题速查清单症状根因关键配置Cannot find module from 常见于 CI模块解析路径未覆盖roots、moduleDirectories、modulePaths、moduleNameMapper必要时git mv同步目录名SyntaxError: Cannot use import statement outside a modulenode_modules 内 ESM 包未转换transformIgnorePatterns: [node_modules/(?!(some-module\|another-module))]并确保扩展名落在transform正则范围内导入依赖后测试极慢/卡住ts-jest 全量编译、JS 文件被误纳入allowJs: false、transform只匹配.ts、按需开启isolatedModules、收窄 tsconfiginclude延伸阅读仓库内最新版故障排查指南website/docs/guides/troubleshooting.md含.mjs与type: module的 ESM 细分解法ts-jest 配置选项总览website/docs/getting-started/options.md其中 tsconfig 选项 说明如何指定/内联/禁用 tsconfigdiagnostics 选项 控制类型检查报告的开关预设与转换模式源码src/presets/create-jest-preset.ts、src/constants.ts转译模式实现与测试src/transpilers/typescript/transpile-module.ts、src/transpilers/typescript/transpile-module.spec.ts端到端验证样例e2e/tests/transform-js.test.ts 及 e2e/transform-js 目录下的编译/转译双模式配置排查时建议按先缩小范围、再逐项配置的顺序先用--no-cache与最小测试文件复现确认问题归属 ts-jest 后再对照上表定位到具体配置项修改。多数情况下问题一源于模块解析范围、问题二源于转换白名单、问题三源于过度编译——三者的配置思路互相独立可组合使用。赞分享测试开发工具【免费下载链接】ts-jestA Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.项目地址https://gitcode.com/gh_mirrors/ts/ts-jest点击查看免费下载相关推荐PR Agent /help_docs 工具实战指南基于 Git 文档仓库的智能问答与自动化配置PR Agent /help_docs 工具实战指南基于 Git 文档仓库的智能问答与自动化配置 本文以 PR Agent本仓库 pr agent的 he测试开发工具ts-jest 实战排障指南模块解析失败、node_modules 无法转换与测试卡死的解决方案ts jest 实战排障指南模块解析失败、node_modules 无法转换与测试卡死的解决方案 本文基于 ts jest 官方 Troubleshootin测试开发工具Grafana Tempo 依赖解析实战buger/jsonparser v1.6.x 变更全解与源码级性能剖析Grafana Tempo 依赖解析实战buger/jsonparser v1.6.x 变更全解与源码级性能剖析 output_article buger/测试开发工具上一篇G-Helper风扇曲线怎么调让ROG笔记本在静音和散热之间自由切换下一篇AntiMicroX 手柄键盘映射10 分钟上手创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表