DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
搬瓦工;先看线路,再选 VPS;CN2 GIA · 对应线路套餐;查看线路 →
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS

Terser 压缩 RegExp.$1 报错,先核对 compress.unsafe

Terser 5.51.2开启unsafe时,静态求值器可能从缺失的RegExp对象读取$1。局部关闭unsafe,保留运行时捕获语义,并核对实际生产压缩入口。

开启 Terser 的 compress.unsafe 后,压缩阶段报 Cannot read properties of undefined (reading '$1'),堆栈指向 AST_Dot._eval。输入里可能只有一条很短的语句:

console.log(RegExp.$1);

这条故障在 Terser 5.51.2、Node 24.20.0 的组合中出现;相同输入也有 5.47.0 失败、5.46.2 正常的对照。不要因为源码中没有普通对象的 $1 字段,就往业务代码里补一个同名对象。这里是压缩器试图提前求值时出错。

unsafe 触发了静态属性求值

正式 5.51.2 的求值器允许对某些原生静态属性做计算,再从内置对象表取对应对象。那份表包含 Array、Math、Number、Object、String,却没有 RegExp;RegExp.$1 进入这条分支后,最终会从 undefined 读取属性。

RegExp 的 $1 等旧式静态捕获属性依赖运行时的正则匹配状态,不能简单当成一个构建时常量。把源码改成空字符串、在构建前跑一次正则,或给压缩工具进程的 RegExp 手动塞值,都不能保留应用运行时语义。

先确认实际调用的 Terser 版本及最终压缩选项。打包器可能另带一份依赖,开发服务器又可能根本不做生产压缩;只在开发页检查源码正常,不能排除正式构建的这条路径。

在原压缩入口关闭 unsafe

不依赖这组激进转换时,保留现有其他选项,只将 unsafe 设为 false。下面是传给现有 Terser minify() 的选项片段:

{
  compress: {
    unsafe: false,
  },
}

若原来已有 compress 配置,应在原对象中修改这一项,不能用示例覆盖原有的 dead_code、passes 或其他策略。打包器对 Terser 的封装位置各不相同,要确认修改确实进入失败的生产压缩任务。

关闭 compress.evaluate 也能避开这次求值,但会停掉更广泛的常量计算。除非项目确实需要保留 unsafe,并接受这一取舍,否则优先收窄到 unsafe。两项变化都可能影响产物体积,构建恢复不说明运行性能有所提升。

截至 2026 年 10 月 25 日,当前正式版仍为 5.51.2,对应求值路径没有补入这一对象或绕过该访问的保护。换到后续正式版本时,应以同一输入与项目真实选项复查,不凭版本号变大认定已经修好。

保留运行时读取,再检查原产物

重新构建后,既要确认压缩器正常退出,也要检查产物没有把静态捕获值提前写死。若业务确实依赖这些属性,应在隔离环境保留原来的匹配顺序,再核对读取结果;不能只检查一条没有先行匹配的演示输入。

长期可以评估用正则执行结果数组表达明确的捕获关系,但这涉及业务语义迁移,不是把所有 RegExp.$1 机械替换为某个全局变量。先恢复当前构建,保留配置与锁文件差异;需要回退选项时,也应同时考虑原故障是否会重新进入。