DEBUG.WIKI
OnlineSIM:在线接收短信,虚拟号码租用
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →
RackNerd;$21.99/年 · 1GB KVM

date-fns 生产构建报读取 M 失败,检查 Parcel 格式化器产物

date-fns 4.1.0 与 Parcel 2.9.3 的扩展构建出现格式化器 undefined,保留合法 token,对照优化产物和实际扩展运行路径。

浏览器扩展开发环境正常,Parcel 生产构建后执行 date-fns 的 format() 却报 Cannot read properties of undefined (reading 'M')。若组合是 date-fns 4.1.0、Parcel 2.9.3,以及通过 Plasmo 0.90.5 构建的扩展,应对照优化产物里的格式化器依赖,先不要更改合法日期或把 MMM 换成另一套格式字符。

这类错误需要与无效日期、未知格式 token 分开。MMM dd 配合有效日期和 enUS 是正常用法;这里的问题发生在读取格式化器时,不能据错误中的字母 M 就认定月份 token 不受支持。

看最终产物,不只看源码导入

date-fns 4.1.0 的 format 实现会导入格式化器对象,再按 token 首字符索引取函数。已核对的 4.4.0 正式包仍有相应导入与动态属性访问;动态访问本身是正常 JavaScript,不足以证明所有打包器都会错误删除依赖。

先记录真正加载的 date-fns、Parcel 和扩展框架版本,比较开发与生产构建。检查 source map 对应的位置,以及格式化器对象在最终 bundle 中是否保留和正确绑定。没有查到产物异常前,不应把同样的 TypeError 都归为 tree-shaking。

用于隔离的调用可以保持原来的导入与 locale:

import { format } from 'date-fns';
import { enUS } from 'date-fns/locale/en-US';

const label = format(new Date(2026, 9, 23), 'MMM dd', { locale: enUS });

在扩展原来的执行位置使用这段最小调用,不要换成 Node 脚本通过后就认定浏览器构建恢复。

用有边界的构建对照定位优化阶段

项目直接使用 Parcel CLI 时,可以为同一入口单独构建一份关闭 scope hoisting 的对照产物:

parcel build <原入口> --no-scope-hoist

<原入口> 必须替换为项目已有入口,保留原目标与其他必要选项;这不是让 Plasmo 项目另外运行一条不相干的 Parcel 命令。经框架封装时,应先核对框架实际支持的配置入口和最终命令,不能假定任意 CLI 参数都会传递进去。

如果对照产物恢复,再在原构建链内缩小到 scope hoisting、压缩等阶段,评估临时关闭相应优化对包体和加载的影响。若仍报错,这个对照没有证明优化是原因,应回到实际加载路径、依赖副本和堆栈继续检查。

显式导入 formatters 后只写一个无可观察作用的空判断,不是可靠的保留保证,优化器仍可能消去它。也不要直接把依赖包的 sideEffects 全部改为 true 当成确定修复;这会扩大产物,还没有解决构建器为何生成错误引用的问题。

验收应安装新的扩展构建,覆盖原来失败的月份格式、locale 长格式和正常日期,确认没有加载旧 bundle。升级 date-fns 或 Parcel 后仍要检查同一条生产路径;仅正式包版本变大,不证明这一组工具链问题已经修复。