模块化开发是现代JavaScript工程的底线,因ESM需显式声明type="module"或"type": "module",且CommonJS与ESM加载时机、语法限制、循环引用、构建工具处理逻辑存在根本差异。

模块化开发不是 JavaScript 项目的“加分项”,而是现代工程落地的底线——没有它,node_modules 会失控,import 会报 Cannot find module,多人协作时改一个 utils.js 就可能让三个页面白屏。
为什么 import 和 export 在浏览器里直接报错
原生 ES 模块(ESM)需要显式声明 type="module",否则浏览器按传统脚本执行,不识别 export 语法。Node.js 则依赖 package.json 中的 "type": "module" 或文件后缀(.mjs)来启用 ESM。
- 浏览器中漏写
→SyntaxError: Unexpected token 'export' - Node.js 中没设
"type": "module"却用了export→ReferenceError: exports is not defined - 混用
require()和import在同一文件 → 直接抛ERR_REQUIRE_ESM
CommonJS 和 ESM 的加载时机差异直接影响调试逻辑
CommonJS 是运行时同步加载,require() 可以写在 if 分支里;ESM 是编译时静态分析,所有 import 必须在顶层,且路径必须是字符串字面量。
-
import不能动态拼接路径:import('./' + name + '.js')❌(需用import()动态导入) -
require('./' + path)✅ 可运行,但打包工具(如 Webpack/Vite)无法静态分析,易导致 chunk 错乱 -
export default和module.exports =不等价:前者是命名绑定,后者是值拷贝,循环引用行为不同
Vite 和 Webpack 对 node_modules 中模块的处理逻辑完全不同
Vite 默认将 node_modules 中的 ESM 包直接按原样 serve,而 Webpack 会统一走 loader 链(如 babel-loader + eslint-loader)。这意味着:
立即学习“Java免费学习笔记(深入)”;
- 一个包若只发布
exports字段但没提供main或module字段,Vite 可能找不到入口,报Failed to resolve entry for package - Webpack 可能因
babel配置太激进,把已编译的 ESM 库又转成 CommonJS,引发__esModule冲突 -
resolve.alias在 Vite 中对node_modules内部路径无效,得靠optimizeDeps.exclude或重写exports字段
模块化的真正难点不在语法,而在边界——package.json 的字段优先级、构建工具对 exports 的解析顺序、跨环境(浏览器/Node/SSR)下 process.env.NODE_ENV 对模块选择的影响,这些地方出问题,错误信息往往不指向真实原因。











