- 测试
- 开发工具
【免费下载链接】ts-jest
A Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.
stringifyContentPathRegex是 ts-jest 提供的一个正则表达式配置项,用于把匹配到的文件(典型场景是 HTML 模板)当作纯文本字符串导出,而不是当作 TypeScript/JavaScript 源码进行编译。本文以 ts-jest 仓库(当前版本 29.0 文档)为基准,完整讲解该选项的语义、三种配置写法、正则匹配细节、源码实现原理与历史兼容性,帮助你安全地在 Jest 中完成「HTML 模板字符串化」类需求。
选项是什么:为__HTML_TRANSFORM__保留的字符串化能力
stringifyContentPathRegex选项最初是为了向后兼容旧版 ts-jest 的__HTML_TRANSFORM__全局配置而保留的(详见下文「历史迁移」一节)。它的作用非常明确:
- 它是一个正则表达式模式,用来匹配将被转换的文件路径;
- 一旦匹配成功,该文件不会被当作源码编译,而是被导出为一个导出其文件内容的模块。
也就是说,当正则命中某个文件后,ts-jest 完全跳过 TypeScript 编译管线,直接生成类似下面的模块代码:
module.exports = "文件原始内容字符串"一个直观的例子
假设你有一个文件foo.ts,内容为:
export default "bar"并且你的stringifyContentPathRegex被设置为foo\\.ts$。那么最终得到的模块不是编译foo.ts源码的结果,而是一个导出了字符串"export default \"bar\""的模块——文件内容被整体「字符串化」了。
注意这里的正则需要转义:foo\\.ts$中的\\.匹配一个字面量点号.,$锚定文件路径结尾。如果你直接在jest.config.ts中书写,也可以使用 JavaScript 正则字面量/foo\.ts$/,二者语义一致(具体类型与规范化见下文源码分析)。
关键注意事项(CAUTION)
无论你想让哪些文件被stringifyContentPathRegex命中,都必须同时满足两个前提,否则匹配不会生效:
- Jest 的
transform选项中指向ts-jest的规则必须能匹配到这些文件。也就是说,ts-jest 只会处理被transform交给它的文件;stringifyContentPathRegex只能在 ts-jest 已经接管的文件范围内生效。 - 可能还需要把这些文件的扩展名加入 Jest 的
moduleFileExtensions选项。例如你希望foo.html被处理,就应把html加入moduleFileExtensions,否则 Jest 在模块解析阶段可能根本不会把该文件交给 transform 管线。
这两点共同决定了「正则写了却不起作用」的绝大多数排查方向:先确认transform规则覆盖了目标扩展名,再确认moduleFileExtensions包含该扩展名。
配置示例:三种写法完整继承
写法一:jest.config.js(推荐基于 preset 扩展)
// jest.config.js const { defaults: tsjPreset } = require('ts-jest/presets') /** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { // [...] moduleFileExtensions: [...tsjPreset.moduleFileExtensions, 'html'], transform: { ...tsjPreset.transform, '\\.html$': [ 'ts-jest', { stringifyContentPathRegex: /\.html$/, }, ], }, }写法二:jest.config.ts
// jest.config.ts import type { JestConfigWithTsJest } from 'ts-jest' import tsJestPresets from 'ts-jest/presets' const jestConfig: JestConfigWithTsJest = { // [...] moduleFileExtensions: [...tsJestPresets.defaults.moduleFileExtensions, 'html'], transform: { ...tsJestPresets.defaults.transform, '\\.html$': [ 'ts-jest', { stringifyContentPathRegex: /\.html$/, }, ], }, }写法三:package.json中的内联 Jest 配置
// package.json { // [...] "jest": { "moduleFileExtensions": ["js", "ts", "html"], "transform": { "\\.(html|ts|js)$": [ "ts-jest", { "stringifyContentPathRegex": "\\.html$" } ] } } }文档原文特别说明:在jest.config.js版本中,你可以像package.json版本那样书写,但从 preset(ts-jest/presets)扩展会带来更强的兼容性——升级 ts-jest 版本时无需改动配置即可保持行为一致。
关于示例的补充说明
- 示例中
transform的 key'\\.html$'是 Jest 用来匹配待转换文件路径的正则;stringifyContentPathRegex: /\.html$/则是 ts-jest 内部用来决定「文件内容是否字符串化」的正则。二者作用层面不同,但示例中刻意保持一致(都匹配.html结尾),这也是最常见的组合。 - 在
package.json版本中"\\.(html|ts|js)$"同时覆盖了 html/ts/js 三种扩展名,确保.html文件能被 ts-jest 接管;此时moduleFileExtensions也必须包含html。 - 正则在 JSON 配置中必须写成字符串(如
"\\.html$"),在jest.config.js/ts中则推荐使用原生正则字面量/.html$/。
源码级解析:正则如何被规范化与使用
类型定义
在 src/types.ts 中,该选项的类型被定义为:
stringifyContentPathRegex?: string | RegExp即既接受字符串形式,也接受 RegExp 对象形式,这解释了为什么 JSON 配置(只能存字符串)和 JS/TS 配置文件(可用字面量正则)都能正常工作。
规范化流程
在 src/legacy/config/config-set.ts 中,ConfigSet 构造时会对该选项做归一化处理:
// stringifyContentPathRegex if (options.stringifyContentPathRegex) { this._stringifyContentRegExp = typeof options.stringifyContentPathRegex === 'string' ? new RegExp(normalizeRegex(options.stringifyContentPathRegex)!) // eslint-disable-line @typescript-eslint/no-non-null-assertion : options.stringifyContentPathRegex this.logger.debug( { stringifyContentPathRegex: this._stringifyContentRegExp }, 'normalized stringifyContentPathRegex config via ts-jest option', ) }从源码结构可以看到:
- 传入的字符串会经过
normalizeRegex处理后用new RegExp(...)编译为正则对象; - 传入的正则对象会被直接使用;
- 归一化结果保存在内部属性
_stringifyContentRegExp中,并输出 debug 日志便于排查。
匹配判定
在 src/legacy/config/config-set.ts 中,判定逻辑非常简洁:
shouldStringifyContent(filePath: string): boolean { return this._stringifyContentRegExp ? this._stringifyContentRegExp.test(filePath) : false }未配置该选项时恒返回false,即所有文件照常走编译流程;配置后则用正则测试传入的文件路径。
字符串化输出
在 src/legacy/ts-jest-transformer.ts 中,processWithTs首先调用configs.shouldStringifyContent(sourcePath)判断,命中后直接短路编译流程:
const shouldStringifyContent = configs.shouldStringifyContent(sourcePath) const babelJest = shouldStringifyContent ? undefined : configs.babelJestTransformer // ... if (shouldStringifyContent) { // handles here what we should simply stringify result = { code: `module.exports=${stringify(sourceText)}`, } }注意两个细节:
- 命中字符串化的文件不会再走 babel 转换(
babelJest被置为undefined); - 输出代码为
module.exports=<JSON.stringify后的源码文本>,即把整个文件内容序列化为一个字符串并导出。
测试用例印证
在 src/legacy/ts-jest-transformer.spec.ts 中有一个直接验证该行为的测试:对foo.html(内容为<h1>Hello World</h1>)配置stringifyContentPathRegex: '\\.html$'后调用tr.process,期望产物为:
{ "code": "module.exports=\"<h1>Hello World</h1>\"" }这与文档描述完全一致:HTML 内容没有被 TypeScript 编译,而是被转义后作为字符串导出。另外,src/legacy/config/config-set.spec.ts 还验证了该选项同时支持字符串('\\.str$')与正则对象(/\.str$/)两种形式,以及未配置时的默认行为。
历史迁移:从__TRANSFORM_HTML__到stringifyContentPathRegex
文档明确指出该选项是为__HTML_TRANSFORM__的向后兼容而保留。在 src/utils/backports.ts 中可以看到对应的迁移逻辑:
if ('__TRANSFORM_HTML__' in globals) { warnConfig('globals.__TRANSFORM_HTML__', 'globals.ts-jest.stringifyContentPathRegex') if (globals.__TRANSFORM_HTML__) { mergeTsJest.stringifyContentPathRegex = '\\.html?$' } delete globals.__TRANSFORM_HTML__ }含义是:如果旧配置中启用了globals.__TRANSFORM_HTML__,ts-jest 会打印弃用警告(提示改用globals.ts-jest.stringifyContentPathRegex),并自动把等效正则\\.html?$写入新的选项位置,最后删除旧键。\\.html?$中的?让l可省略,因此同时覆盖.html与.htm。相关警告文案可在 src/utils/snapshots/backports.spec.ts.snap 的快照中看到。
如果你正在从旧版本升级,请检查配置中是否残留globals.__TRANSFORM_HTML__,并替换为本文所述的stringifyContentPathRegex写法。
实战要点与最佳实践
- 正则只匹配路径,不匹配内容。
stringifyContentPathRegex测试的是传入 ts-jest 的文件路径(如foo.html),因此写\.html$即可覆盖所有.html文件;若只针对某个目录,可写成^src/templates/.*\.html$之类带锚点的模式。 transform与moduleFileExtensions是生效前提。stringifyContentPathRegex只在 ts-jest 被 Jest 指定的 transform 规则接管文件后才生效;moduleFileExtensions中缺少对应扩展名会导致 Jest 根本不解析该类文件。二者缺一不可。- 字符串化后文件内容可被
require/import直接读取。因为产物是module.exports="...",测试代码中可以import html from './template.html'拿到模板原文,适用于需要把 HTML 片段注入 DOM 或做快照断言的场景。 - 字符串形式需注意转义。JSON 配置中必须写成
"\\.html$"(两个反斜杠表示一个正则中的字面量点);而在jest.config.js/ts中直接使用/\.html$/更直观,且与源码内部new RegExp归一化后的对象等价。 - 不要用该选项匹配 TS 业务源码。它会让匹配到的
.ts/.js文件跳过编译直接变成字符串模块(如文档中的foo.ts示例所示),绝大多数情况下这不是你想要的;它最适合的是模板类资源文件。
参考文件索引
- 选项类型定义:src/types.ts
- 字符串/正则归一化与匹配判定:src/legacy/config/config-set.ts、src/legacy/config/config-set.ts
- 字符串化输出实现:src/legacy/ts-jest-transformer.ts
- 行为验证测试:src/legacy/ts-jest-transformer.spec.ts、src/legacy/config/config-set.spec.ts
- 旧配置迁移逻辑:src/utils/backports.ts
- 测试
- 开发工具
【免费下载链接】ts-jest
A Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.
相关推荐
Handsontable 数据导出指南:用 ExportFile 插件将网格导出为 CSV 文件、Blob 与字符串
Handsontable 数据导出指南:用 ExportFile 插件将网格导出为 CSV 文件、Blob 与字符串 本文以 Handsontable 的 Ex
前端UI组件GO-FLY开源在线客服系统:基于Go语言的高性能实时通讯解决方案
GO FLY开源在线客服系统:基于Go语言的高性能实时通讯解决方案 GO FLY是一款采用Go语言构建的 开源私有化部署在线客服系统 ,专为需要高性能实时通讯的
后端即时通讯前端LeetCode 0028 找出字符串中第一个匹配项的下标:六大字符串匹配算法(BF / RK / KMP / BM / Horspool / Sunday)全解析
LeetCode 0028 找出字符串中第一个匹配项的下标:六大字符串匹配算法(BF / RK / KMP / BM / Horspool / Sunday)全
教程文档知识库
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考