# JS模块化
JS 模块化全解:从远古到现代,一次讲透
JavaScript 模块化的核心作用:解决变量污染、代码混乱、依赖管理混乱,让代码可复用、可维护、可拆分。
JS 模块化经历了 4 个主流阶段,我按历史顺序 + 实用场景给你讲清楚,每个方案都告诉你用法、区别、适用场景。
# 一、远古时代:无模块化(问题根源)
早期 JS 没有模块化,所有代码都写在全局:
<script src="a.js"></script>
<script src="b.js"></script>
致命问题:
- 变量、函数全部挂载在
window上,容易命名冲突 - 依赖关系混乱,不知道谁依赖谁
- 代码无法复用,无法隔离作用域
# 二、第一代模块化:IIFE(立即执行函数)
手动创造私有作用域,是模块化的雏形。
// module.js
const MyModule = (function() {
// 私有变量,外部访问不到
let count = 0;
// 暴露出去的方法
return {
add: () => count++,
getCount: () => count
};
})();
使用:
MyModule.add();
console.log(MyModule.getCount()); // 1
✅ 优点:解决全局污染、实现私有变量 ❌ 缺点:手动管理依赖,无法自动加载,不适合大型项目
# 三、第二代:社区规范(AMD / CommonJS / UMD)
这是 Node.js 和前端早期的标准,现在仍大量使用。
# 1. CommonJS(Node.js 默认)
CommonJS 的核心语法全部依赖 Node 内置全局对象 / 变量
同步加载,用于 Node.js 服务端。
语法:
// 导入
const fs = require('fs');
const { add } = require('./math');
// 导出
module.exports = { add, sub };
// 或简写
exports.add = () => {};
✅ 特点:
- 服务端使用(文件读取快,同步无压力)
- 运行时加载
- 不支持浏览器原生运行
# 2. AMD(RequireJS)
异步加载,专门给 浏览器 用的早期方案。
define(['dep'], function(dep) {
return { func: () => {} };
});
require(['module'], function(mod) {});
❌ 现状:已淘汰,被 ES Modules 取代
# 3. UMD(通用模块化)
兼容 CommonJS + AMD + 全局变量,通用兼容方案。 现在很多老库还在用,目的是同时支持浏览器和 Node。
# 四、第三代:官方标准 ES Modules(ESM)🔥
现代 JS 唯一官方标准,浏览器、Node.js、构建工具(Webpack/Vite)全支持。
也是你现在必须掌握的模块化方案。
# 核心语法
// 导出
export const name = "test";
export function fn() {}
export default obj; // 默认导出
// 导入
import { name } from './module.js';
import myDefault from './module.js';
import * as All from './module.js';
# 浏览器原生使用
必须加 type="module":
<script type="module" src="app.js"></script>
# Node.js 使用
package.json 加一句:
"type": "module"
✅ ESM 最大优势:
- 编译时加载(支持 tree-shaking 剔除无用代码)
- 异步加载,适合浏览器
- 顶层 await 支持
- 官方标准,未来唯一主流
# 五、最关键:CommonJS vs ES Modules(必背区别)
| 特性 | CommonJS (Node) | ES Modules (现代标准) |
|---|---|---|
| 加载方式 | 同步 | 异步 |
| 运行 / 编译时 | 运行时加载 | 编译时静态解析 |
| 导出值 | 值拷贝 | 引用(实时更新) |
| 顶层 this | 指向 module.exports | 指向 undefined |
| 适用环境 | Node | 浏览器 + Node + 构建工具 |
| tree-shaking | 不支持 | 支持 |
一句话总结:
- 老 Node 项目用 CommonJS
- 新项目、前端、现代工程全用 ESM
# 六、现代工程最佳实践
- 前端项目(Vue/React):全部使用 ES Modules
- Node.js 新项目:开启
"type": "module",用 ESM - 库开发:打包成 ESM + CommonJS + UMD 兼容
# 总结
- JS 模块化经历:IIFE → CommonJS/AMD → ESM(官方标准)
- ESM 是现在和未来的唯一标准,必须优先使用
- CommonJS 仅用于老 Node 项目
- 核心解决:**作用域隔离、依赖管理、代码复用
# 七、典型案例
# Cesium资源加载问题
Cesium 在版本1.92.0会出现 css导入BUG, 在node_modules里找到cesium的package.json文件,在exports里增加导出widgets.css
"exports": {
"./package.json": "./package.json",
"./Source/*": "./Source/*",
"./Source/*.js": null,
"./Build/*": "./Build/*",
"./Build/*.js": null,
"./widgets.css": "./Source/Widgets/widgets.css",
".": {
"types": "./Source/Cesium.d.ts",
"require": "./index.cjs",
"import": "./Source/Cesium.js"
}
},
这一行的作用是允许用户从 cesium 包导入 widgets.css,解析放行。
# 错误原因
Cesium 1.92.0 新增了 exports(开启严格模式),但官方漏写了 widgets.css 的导出白名单,所以你正常引入样式直接报错。
# 严格模式
只要一个包的 package.json 里写了 exports 字段,这个包就自动进入「严格导出模式」。
严格模式核心一句话:
白名单机制:只允许导入 exports 里明确写了的文件,所有没声明的文件一律禁止导入。
# 官方修复
Cesium 1.90 ~ 1.94 区间全部存在该 BUG
后续新版本官方补全了 css、worker、资源导出,修复了该问题
1.96+版本官方已修复 exports 漏导出 css 的问题,无需手动改包。
← Hash和History的区别 代码分离 →