meteor-circular-deps
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMeteor circular dependencies and bundle leaks (diagnostic)
Meteor循环依赖与包泄漏(诊断指南)
Meteor bundles ES modules eagerly. Cycles that look fine in a plain Node/Webpack setup can still bite you: evaluation order changes when the graph changes, so a new file can reorder imports and expose a cycle that used to be hidden. A common symptom is a binding that is still when another module reads it ( in stack traces).
undefinedmodule: falsyMeteor会预打包ES模块。在普通Node/Webpack环境中看似正常的循环依赖,在Meteor中仍可能引发问题:当依赖图变化时,模块执行顺序会改变,新增文件可能会重新排序导入顺序,暴露之前隐藏的循环依赖。常见症状是某个模块读取时,对应的绑定仍为(堆栈跟踪中显示)。
undefinedmodule: falsyWhen this is likely (symptoms)
可能出现该问题的场景(症状)
- Stack traces mentioning or
module: falsywhile loading models/mixins.Failed to register array mixin - in React after a refactor, often with a component that imported fine before.
Element type is invalid - immediately after
Cannot read property 'X' of undefinedwhereimport { Foo } from ...should exist.Foo - Failure appears after adding an unrelated file (import order / cycle surface area changed).
- Barrel / bucket files (,
index.js,common.js,client.js) re-exporting most of a domain and being imported from inside that same domain.server.js
- 加载模型/混入(mixin)时,堆栈跟踪中出现**或
module: falsy**。Failed to register array mixin - 重构后React中出现****错误,通常涉及之前导入正常的组件。
Element type is invalid - 执行后立即出现**
import { Foo } from ...**错误,而Cannot read property 'X' of undefined本应存在。Foo - 添加无关文件后出现故障(导入顺序/循环依赖暴露范围发生变化)。
- 桶文件(、
index.js、common.js、client.js)重新导出某个领域的大部分模块,同时该领域内部又导入了这些桶文件。server.js
Step 1 — Map cycles with madge
步骤1 — 使用madge映射循环依赖
From the Meteor app root (where lives):
.meteorbash
npx madge --circular --extensions ts,tsx,js,jsx ./client ./imports ./modules ./packages 2>/dev/null || true
npx madge --circular --extensions ts,tsx,js,jsx .Narrow the path if the repo is huge (e.g. ).
./modules/models/IssuesOptional SVG (good for sharing in a ticket):
bash
npx madge --circular --image graph.svg --extensions ts,tsx,js,jsx .How to read the output: each cycle is a ring of files. Your fix will almost always require breaking one edge on that ring (see Step 4).
If you need richer rules (forbidden deps, layers), mention depcruise as an alternative; it is heavier to configure than madge.
在Meteor应用根目录(所在目录)执行:
.meteorbash
npx madge --circular --extensions ts,tsx,js,jsx ./client ./imports ./modules ./packages 2>/dev/null || true
npx madge --circular --extensions ts,tsx,js,jsx .如果仓库规模很大,可以缩小路径范围(例如)。
./modules/models/Issues可选生成SVG图(便于在工单中分享):
bash
npx madge --circular --image graph.svg --extensions ts,tsx,js,jsx .输出解读:每个循环依赖都是一组文件构成的环。修复时几乎总是需要打破环中的一个依赖关系(见步骤4)。
如果需要更丰富的规则(禁用依赖、分层),可以使用depcruise作为替代方案;它的配置比madge更复杂。
Step 2 — Bundle inspector (client vs server)
步骤2 — 包检查器(客户端 vs 服务器)
After a successful or dev run that produced maps, run the bundled script from this skill (or copy it into the repo):
meteor buildbash
node /path/to/meteor-circular-deps/scripts/bundle-inspector.js --root .Paths default to:
.meteor/local/build/programs/web.browser/app/app.js.map.meteor/local/build/programs/server/app/app.js.map
Use and to encode project-specific leak rules (see script ).
--fail-both <regex>--fail-server-only <regex>--helpInterpretation:
- Shared (both) — normal for isomorphic modules; suspicious if “server-only” concepts appear here.
- Client-only / server-only — helps spot mistaken imports (autocomplete pulling the wrong entry file).
成功执行****或开发运行生成映射文件后,运行本技能提供的打包脚本(或复制到仓库中):
meteor buildbash
node /path/to/meteor-circular-deps/scripts/bundle-inspector.js --root .默认路径为:
.meteor/local/build/programs/web.browser/app/app.js.map.meteor/local/build/programs/server/app/app.js.map
使用和来定义项目特定的泄漏规则(查看脚本获取详情)。
--fail-both <regex>--fail-server-only <regex>--help结果解读:
- Shared(客户端和服务器共享) — 同构模块的正常情况;如果出现“仅服务器端”的概念则需警惕。
- Client-only / server-only(仅客户端/仅服务器) — 有助于发现错误的导入(自动补全拉取了错误的入口文件)。
Step 3 — Tie cycles to the failing stack trace
步骤3 — 将循环依赖与错误堆栈跟踪关联
- Take the deepest app file in the stack (first or
modules/...line underimports/.../moduleLink).fileEvaluate - In the madge cycle list, find a cycle that includes that file or its barrel entry (,
index.js, etc.).common.js - Pick the weakest link: an import that can be replaced with a more specific file, moved behind , or inverted (dependency injection).
import()
- 找到堆栈跟踪中最底层的应用文件(/
moduleLink下的第一个fileEvaluate或modules/...行)。imports/... - 在madge生成的循环依赖列表中,找到包含该文件或其桶文件入口(、
index.js等)的循环依赖。common.js - 选择最弱的依赖链接:可以替换为更具体的文件导入、移至懒加载,或者反转依赖(依赖注入)。
import()
Step 4 — Targeted fixes (prefer small diffs)
步骤4 — 针对性修复(优先小改动)
A. Barrel / bucket anti-pattern (most common in domain folders)
- Inside a domain, import concrete modules (,
./foo.js), not the domain’s./helpers/bar.js/index.js/client.jsre-export that also pulls in the consumer.server.js - Keep bucket files for external entry points only (other packages, startup, routes).
B. Break cycles without a big rewrite
- Move shared types/constants to a leaf file that imports nothing from the cycle.
- Lazy for heavy or optional branches that create a back-edge (use where ordering must not run at module top-level).
import() - Constructor / function injection instead of importing a singleton at module scope (e.g. pass registry into if your ORM allows it).
registerMixins
C. React “invalid element”
- Often the same issue: default export is because the module did not finish evaluating. Fix the cycle at the root before reaching for
undefined.React.lazy
D. Model / mixin
module: falsy- The mixin array entry is literally because the mixin module’s export was not initialized yet. Trace which mixin file is at the failing index; run madge on the path from Model → that mixin → back to Model (or Requests/Messages index barrels).
undefined
A. 桶文件反模式(领域文件夹中最常见)
- 在领域内部,导入具体模块(、
./foo.js),而非该领域的./helpers/bar.js/index.js/client.js重新导出文件(这些文件会同时引入当前消费者模块)。server.js - 桶文件仅用于外部入口点(其他包、启动脚本、路由)。
B. 无需大规模重写即可打破循环依赖
- 将共享类型/常量移至不依赖循环中任何模块的叶子文件。
- 对导致反向依赖的重型或可选分支使用懒加载(用于模块顶层不能执行顺序敏感代码的场景)。
import() - 使用构造函数/函数注入替代模块作用域导入单例(例如,如果ORM允许,将注册表传入)。
registerMixins
C. React“无效元素”错误
- 通常是同一问题:默认导出为,因为模块未完成执行。在尝试使用
undefined之前,先修复根源的循环依赖。React.lazy
D. 模型/混入错误
module: falsy- 混入数组条目实际为,因为混入模块的导出尚未初始化。找出错误索引对应的混入文件;对从Model到该混入再回到Model(或Requests/Messages索引桶文件)的路径运行madge分析。
undefined
Step 5 — Verify
步骤5 — 验证修复
- Re-run madge — the reported cycle involving the touched files should be gone or shortened.
- Re-run bundle inspector if the change touched client/server boundaries.
- Run a normal rebuild (a full reset is unnecessary).
- 重新运行madge — 涉及修改文件的循环依赖应已消失或缩短。
- 如果修改涉及客户端/服务器边界,重新运行包检查器。
- 执行常规重建(无需完全重置)。
Related project conventions
相关项目约定
If the repo’s discourages barrel imports for React/runtime objects, treat that as reinforcement: barrel files are both a bundle-shape problem and a circular-dep amplifier.
AGENTS.md如果仓库的禁止对React/运行时对象使用桶导入,这进一步印证了:桶文件既是包结构问题,也是循环依赖的放大器。
AGENTS.md