<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>模块系统 | 锤子前端</title><description>Now vibe coding, so learning hammer FE ?</description><link>https://channel.meo-ai.com</link><item><title>《你的模块在骗你：ESM 与 CommonJS 的本质差异与陷阱全解析》</title><link>https://channel.meo-ai.com/posts/701</link><guid isPermaLink="true">https://channel.meo-ai.com/posts/701</guid><pubDate>Fri, 28 Aug 2026 01:13:02 GMT</pubDate><content:encoded>&lt;span class=&quot;post-title-source&quot;&gt;《你的模块在骗你：ESM 与 CommonJS 的本质差异与陷阱全解析》&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;标签：&lt;br /&gt;&lt;a href=&quot;/search/result?q=%23JavaScript&quot; title=&quot;#JavaScript&quot;&gt;#JavaScript&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23NodeJS&quot; title=&quot;#NodeJS&quot;&gt;#NodeJS&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23ESM&quot; title=&quot;#ESM&quot;&gt;#ESM&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23CommonJS&quot; title=&quot;#CommonJS&quot;&gt;#CommonJS&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E6%A8%A1%E5%9D%97%E7%B3%BB%E7%BB%9F&quot; title=&quot;#模块系统&quot;&gt;#模块系统&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E5%89%8D%E7%AB%AF%E5%B7%A5%E7%A8%8B%E5%8C%96&quot; title=&quot;#前端工程化&quot;&gt;#前端工程化&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;总结：&lt;br /&gt;&lt;br /&gt;本文深入剖析了 ESM 和 CommonJS 两种模块系统在底层机制上的根本差异——ESM 通过&quot;活绑定&quot;（live bindings）在模块间共享变量引用，而 CommonJS 通过 &lt;code&gt;module.exports&lt;/code&gt; 返回一个普通值（通常是对象）。这一差异导致了同名导入在两种系统下行为截然不同：ESM 的命名导入能观察到导出模块的变量重新赋值，CommonJS 的解构赋值则只复制了属性的当前值。文章进一步系统讲解了评估顺序、缓存机制、循环依赖处理、跨系统互操作、双包实例风险等关键话题，并提供了 9 条实践规则和调试清单。&lt;br /&gt;&lt;br /&gt;文章要点：&lt;br /&gt;&lt;br /&gt;1. 活绑定 vs 值复制：最经典的陷阱 — ESM 的 &lt;code&gt;import { status }&lt;/code&gt; 是活绑定，导出模块重新赋值后导入方自动看到新值；CommonJS 的 &lt;code&gt;const { status } = require()&lt;/code&gt; 是解构赋值，只复制了对象属性的当前值，后续变化不可见。只有保留整个对象 &lt;code&gt;const state = require()&lt;/code&gt; 才能观察到属性变更。&lt;br /&gt;&lt;br /&gt;2. ESM 的导入会被提升，CommonJS 按执行顺序 — ESM 静态导入在模块体执行前就已经解析、链接并评估依赖，所以 &lt;code&gt;import&lt;/code&gt; 写在代码中间也不影响执行顺序；CommonJS 的 &lt;code&gt;require()&lt;/code&gt; 是普通函数调用，走到哪行才执行哪行。&lt;br /&gt;&lt;br /&gt;3. 两种系统有独立的缓存 — ESM 和 CommonJS 各自维护自己的模块缓存，URL 查询参数（如 &lt;code&gt;?mode=one&lt;/code&gt;）会让同一文件被当作不同模块实例加载两次。条件导出（&lt;code&gt;&quot;import&quot;&lt;/code&gt; / &lt;code&gt;&quot;require&quot;&lt;/code&gt;）指向不同文件时，也会产生两个独立的模块实例。&lt;br /&gt;&lt;br /&gt;4. 循环依赖的处理方式天差地别 — CommonJS 允许在模块未完全初始化时就返回 &lt;code&gt;exports&lt;/code&gt; 对象，因此循环依赖中的模块能看到对方&quot;半成品&quot;状态；ESM 则先创建绑定再执行模块体，如果在初始化前读取对方绑定会抛出 &lt;code&gt;ReferenceError: Cannot access before initialization&lt;/code&gt;。&lt;br /&gt;&lt;br /&gt;5. 跨系统互操作的隐藏复杂性 — ESM 导入 CJS 时，&lt;code&gt;module.exports&lt;/code&gt; 作为 &lt;code&gt;default&lt;/code&gt; 导出最可靠，命名导出是 Node 静态分析的&quot;快照&quot;，不会跟踪后续属性变更；CJS 通过 &lt;code&gt;require()&lt;/code&gt; 加载 ESM 时返回的是命名空间对象，需通过 &lt;code&gt;.default&lt;/code&gt; 访问默认导出。&lt;code&gt;__esModule&lt;/code&gt; 只是工具链约定，不是语言特性。&lt;br /&gt;&lt;br /&gt;6. 双包实例风险（Dual-Package Hazard） — 当 &lt;code&gt;&quot;import&quot;&lt;/code&gt; 和 &lt;code&gt;&quot;require&quot;&lt;/code&gt; 指向不同构建文件时，同一个类会被实例化为两个不同的构造函数，&lt;code&gt;instanceof&lt;/code&gt; 会返回 &lt;code&gt;false&lt;/code&gt;，共享状态（如计数器、注册表）也会分裂成两份。&lt;br /&gt;&lt;br /&gt;7. 发布库的最佳实践 — 用 &lt;code&gt;.mjs&lt;/code&gt;/&lt;code&gt;.cjs&lt;/code&gt; 明确文件格式；&lt;code&gt;package.json&lt;/code&gt; 中 &lt;code&gt;&quot;type&quot;&lt;/code&gt; 字段决定 &lt;code&gt;.js&lt;/code&gt; 的解析方式；相对 ESM 导入必须带文件扩展名；用 &lt;code&gt;&quot;exports&quot;&lt;/code&gt; 条件导出为不同系统提供入口，但要警惕实例分裂。&lt;br /&gt;&lt;br /&gt;8. 调试模块问题的检查清单 — 从导入文件的格式、解析到的入口点、返回值形状、本地变量持有的是绑定还是副本、评估是否完成、是否存在循环依赖、模块身份是否一致、是否经过构建工具转换、是否通过打包后的 tarball 测试等 9 个维度系统排查。&lt;br /&gt;&lt;br /&gt;9. 九条实践规则 — 新项目优先用 ESM；库优先用命名导出；可变导出视为共享进程状态；CJS 属性会变时保留对象而非解构；移除循环依赖而非绕开；条件/延迟加载用动态 &lt;code&gt;import()&lt;/code&gt;；包边界显式声明文件格式；假设不同导出目标是不同实例；通过包名而非源码路径测试。&lt;br /&gt;&lt;br /&gt;URL：&lt;br /&gt;&lt;a href=&quot;https://blog.gaborkoos.com/posts/2026-08-14-Your-Modules-Are-Lying-to-You/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;https://blog.gaborkoos.com/posts/2026-08-14-Your-Modules-Are-Lying-to-You/&quot;&gt;https://blog.gaborkoos.com/posts/2026-08-14-Your-Modules-Are-Lying-to-You/&lt;/a&gt;&lt;a class=&quot;tgme_widget_message_link_preview&quot; href=&quot;https://blog.gaborkoos.com/posts/2026-08-14-Your-Modules-Are-Lying-to-You&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;ESM and CommonJS expose values through different contracts. Learn how bindings, object references, evaluation order, caching, cycles, and interop shape module behavior in Node.js.&quot;&gt;
  
  &lt;div class=&quot;link_preview_site_name accent_color&quot;&gt;Gaborkoos&lt;/div&gt;
  &lt;img class=&quot;link_preview_image&quot; alt=&quot;Your Modules Are Lying to You&quot; src=&quot;/static/https://cdn4.telesco.pe/file/in4_ukS7CHW4JkfaPzwpRy_xaEUC6hkaOVOeiHHAbDOPUAM9KYDjbtXHuDaIouRG3zaMHPRB2Xu2qesYdWEYrIPtHZOa15cjevFUQNZ9J-vxMLlIGozxzVZvTMF02G3duAhiQGsye5zIsJ2rLQ7CjxzqB6v159SeR6OoFkDr7d0XWjW9O8nIhXUN3LD2vA_ITTv-Z8yLdWH0so5tnKcCcKHWVcNftxEOTZNy_8m7ROyd-9gYP_u2tFtY3C2eMfrjtmofAxeXIc1uJ3b9Q_xsUZjSmE9thIKYKkILvZXrFDmrwlYRw8FdCnRaQKMigZGtFXJ_vq3A13DKEuzV8mBlLQ.jpg&quot; width=&quot;1200&quot; height=&quot;630&quot; loading=&quot;eager&quot; /&gt;
  &lt;div class=&quot;link_preview_title&quot;&gt;Your Modules Are Lying to You&lt;/div&gt;
  &lt;div class=&quot;link_preview_description&quot;&gt;ESM and CommonJS expose values through different contracts. Learn how bindings, object references, evaluation order, caching, cycles, and interop shape module behavior in Node.js.&lt;/div&gt;
&lt;/a&gt;</content:encoded></item><item><title>《npm 上 ESM 与 CJS 的占比变迁数据》</title><link>https://channel.meo-ai.com/posts/661</link><guid isPermaLink="true">https://channel.meo-ai.com/posts/661</guid><pubDate>Fri, 12 Jun 2026 09:14:29 GMT</pubDate><content:encoded>&lt;span class=&quot;post-title-source&quot;&gt;《npm 上 ESM 与 CJS 的占比变迁数据》&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;标签：&lt;a href=&quot;/search/result?q=%23JavaScript&quot; title=&quot;#JavaScript&quot;&gt;#JavaScript&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23NodeJS&quot; title=&quot;#NodeJS&quot;&gt;#NodeJS&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23ESM&quot; title=&quot;#ESM&quot;&gt;#ESM&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23CommonJS&quot; title=&quot;#CommonJS&quot;&gt;#CommonJS&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23npm&quot; title=&quot;#npm&quot;&gt;#npm&lt;/a&gt; &lt;a href=&quot;/search/result?q=%23%E6%A8%A1%E5%9D%97%E7%B3%BB%E7%BB%9F&quot; title=&quot;#模块系统&quot;&gt;#模块系统&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;总结：&lt;br /&gt;该项目持续追踪 npm 高影响力（热门）包中 ESM、CJS、Dual（双模式）及 Faux（伪 ESM）的占比变化。数据显示，纯 ESM 包从 2021 年 8 月的 6% 增长至 2026 年 6 月的 16%；Dual 模式包增长最为迅猛（从 1.7% 到 22%），成为主流过渡方案；而纯 CJS 虽仍占最大份额（52%），但占比持续下降。2025 年底样本量骤增，反映 npm 生态整体扩张。&lt;br /&gt;&lt;br /&gt;文章要点：&lt;br /&gt;1. &lt;b&gt;纯 ESM 稳步增长但尚未过半**：从 2021 年 341 个包（6.1%）增至 2026 年 2590 个（16.0%），五年增长约 2.6 倍，但仍是少数派&lt;br /&gt;2. **Dual 模式成为最大赢家**：从 95 个（1.7%）暴涨至 3574 个（22.0%），说明&quot;同时支持 ESM 和 CJS&quot;已成为库作者最务实的选择&lt;br /&gt;3. **纯 CJS 仍是主流但份额萎缩**：从 77.4% 降至 51.6%，虽然绝对数量增加，但相对占比持续被侵蚀&lt;br /&gt;4. &lt;/b&gt;&quot;伪 ESM&quot;（Faux）长期僵持**：表面用 ESM 语法但实际编译为 CJS 的包，占比一直维持在 10% 左右，说明彻底转型仍有阻力&lt;br /&gt;5. **生态规模急剧扩张**：样本包总数从 5617 个增至 16231 个，2025 年底几乎翻倍，反映 npm 整体生态的蓬勃发展&lt;br /&gt;6. **数据方法论透明**：基于 &lt;code&gt;npm-high-impact&lt;/code&gt; 热门包分析，爬取 &lt;code&gt;package.json&lt;/code&gt; 的 &lt;code&gt;latest&lt;/code&gt; 版本，约 15 分钟完成，结果以 CSV 和 SVG 可视化呈现&lt;br /&gt;&lt;br /&gt;URL：&lt;br /&gt;&lt;a href=&quot;https://github.com/wooorm/npm-esm-vs-cjs#data&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;https://github.com/wooorm/npm-esm-vs-cjs#data&quot;&gt;https://github.com/wooorm/npm-esm-vs-cjs#data&lt;/a&gt;&lt;a class=&quot;tgme_widget_message_link_preview&quot; href=&quot;https://github.com/wooorm/npm-esm-vs-cjs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; title=&quot;Data on the share of ESM vs CJS on the public npm registry - wooorm/npm-esm-vs-cjs&quot;&gt;
  
  &lt;div class=&quot;link_preview_site_name accent_color&quot;&gt;GitHub&lt;/div&gt;
  &lt;img class=&quot;link_preview_image&quot; alt=&quot;GitHub - wooorm/npm-esm-vs-cjs: Data on the share of ESM vs CJS on the public npm registry&quot; src=&quot;/static/https://cdn4.telesco.pe/file/ln-Z6zE5Y0Ce_jyrudJ2ZLEcOgnWehDyRmHuF498FWKuIoyAh_zy5m0ywaYBpBcd_CwWsKmt5BhF8zD-rg_rGFbI9O91_tNd8b4oEbUys9wyf4q8htl2vXhkKfbTHCgb9l5M5ODQFVas7koEfICxqncizeplng0qH9sz-SXRNeD9T859MdIb6jZFIVr4sUARP63e_2fxLi-H7icx1KZcfrLjuAX8cx7QxZBFtVKwBMdhRWkVpjc6lHTin4IYoDExT-8bnNHmDWZXrAd26QpKKaVNHgQJwY_FjTHjiUFeMhsh07iJSkOuEPpRZ-IPi1GMzNZ9bCA1mDRBy8DDDRtTJQ.jpg&quot; width=&quot;1200&quot; height=&quot;630&quot; loading=&quot;eager&quot; /&gt;
  &lt;div class=&quot;link_preview_title&quot;&gt;GitHub - wooorm/npm-esm-vs-cjs: Data on the share of ESM vs CJS on the public npm registry&lt;/div&gt;
  &lt;div class=&quot;link_preview_description&quot;&gt;Data on the share of ESM vs CJS on the public npm registry - wooorm/npm-esm-vs-cjs&lt;/div&gt;
&lt;/a&gt;</content:encoded></item></channel></rss>