Skip to content

没有任何 gate 检查 sideEffects 声明与「加载期副作用」是否一致 —— #3899 的 pin 只覆盖 layout 一个包 #3943

Description

@yinlianghui

发现于 #3899 的实现(PR #3940),不在该 PR 处理 —— 那一单的面被 PM 裁决明确收窄为 packages/layout 一个包的清单。这一条是仓级 gate 的缺口,是另一类事实。

机制

#3899 是这样被发现的:一个人在做别的事时顺手注意到 packages/layout/package.json 声明 "sideEffects": false,而 src/index.ts 靠加载期 registerLayout() 注册六个组件 key。实测(PR #3940 正文有数据):纯副作用引入 import '@object-ui/layout'; 在遵守该 flag 的打包器下产出 0 字节 bundle、零注册、退出码 0、无警告;故障远端才现形为红色 Unknown component type 面板(OBJUI-001)。

PR #3940 修了 layout,并加了一条构建级 pin(packages/layout/src/__tests__/side-effects-manifest.test.ts)。但那条 pin 是包内作用域的 —— 它读 packages/layout/package.json、探 layout 自己的入口形态。下一个包重犯同样的错,仓里没有任何东西会变红。

这与 #3663 / #3647 是同一形状的缺口:files 声明与磁盘的漂移也曾靠人手工逐包 diff 才发现(一周内两次),随后才有了 scripts/__tests__/package-files-exist.test.ts 这条派生式仓级 gate。sideEffects 现在正处在「靠人顺手发现」的阶段。

今天的普查(origin/main @ 230ffd8,逐包核实)

  • "sideEffects": true —— packages/componentspackages/fields。诚实(且最保守)。
  • "sideEffects": false —— packages/corepackages/i18npackages/layout(PR fix(layout): declare the load-time registration in sideEffects (#3899) #3940 修正中)、packages/react-runtimepackages/sdui-parserpackages/types。除 layout 外逐个查过 barrel 的顶层语句,均无加载期副作用,因此今天都是诚实的(react-runtime 的 barrel 是 src/index.tsx,注意别被 index.ts 的 glob 漏掉)。
  • 字段缺省(undefined)—— 其余全部,含所有 plugin-*。这是安全默认值:打包器会假定有副作用。PluginLoader 动态 import 的那批包因此从未暴露在这个风险里。

所以除 layout 之外目前没有第二个活的缺陷。这也是本条按 observation-class 归档、不打 pm:queue 的原因。

为什么仍然值得记下来

缺口不是「有没有当前受害者」,而是这类谎言无声。它的三个属性叠在一起正好躲开所有现有检查:

  1. 构建全绿、无警告 —— 打包器认为自己在执行你的声明,不是在报错。
  2. 只有 sideEffects: false(或数组漏掉某个入口形态)+ 加载期副作用同时成立才发作,两半分别看都无可指摘。
  3. 现有消费者只要同时 import 了具名导出,模块就一定被求值 —— 缺陷因此可以潜伏任意长时间。packages/layout: sideEffects: false contradicts the load-time registerLayout() — a side-effect-only import can be tree-shaken away #3899 明确写了「今天没人被打到是巧合,不是设计」。

一个新包(或在现有 false 包里新加一处加载期注册/注册表写入/全局赋值)就能原样重演,且没有任何红灯。

可能的处置(供分诊,未实施)

scripts/__tests__/ 加一条派生式仓级 gate,形状照 package-files-exist.test.ts:遍历 workspace 每个包,对声明了 sideEffects: false 或数组的包,检查其 barrel(含 .ts/.tsx 两种拼写)是否存在顶层副作用语句(裸调用、注册表写入、globalThis 赋值);数组情形另检查是否覆盖 main/module/exports 指向的全部 JS 入口形态。PR #3940 里的推导函数(resolvableEntryPaths())与真打包器探针(含 sideEffects: false 对照,防止 gate 在打包器不摇时空绿)可以直接上提复用,layout 的包内 pin 随之收敛为仓级 gate 的一个 specimen。

⚠️ 一处别踩的坑,PR #3940 实测过:发布路径不是唯一的消费面apps/console/vite.config.ts:122examples/console-starter/vite.config.ts 都把 @object-ui/layout alias 到 packages/layout/src,打包器对这些源文件读的是同一份 package.json;只声明 dist/* 时 console 的 alias 形态依然产出 0 字节 bundle。任何仓级 gate 都必须把 workspace alias 入口一并算进「入口形态」,否则它会给一个仍然会炸的包发绿灯。

退出条件

  • 上述仓级 gate 落地(本条即完成);或
  • 出现第二个实际发作的包 —— 那时这条就不再是 dormant,应升级为具体缺陷。

参考位置:scripts/__tests__/package-files-exist.test.ts(同形状的派生式仓级 gate 先例)、packages/layout/src/__tests__/side-effects-manifest.test.ts(PR #3940 的包内 pin,可上提的推导与探针)。

关联:#3899(发现于此)、#3663 / #3647files 字段的同形状缺口与它的 gate)。

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions