# 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

# 六、现代工程最佳实践

  1. 前端项目(Vue/React):全部使用 ES Modules
  2. Node.js 新项目:开启 "type": "module",用 ESM
  3. 库开发:打包成 ESM + CommonJS + UMD 兼容

# 总结

  1. JS 模块化经历:IIFE → CommonJS/AMD → ESM(官方标准)
  2. ESM 是现在和未来的唯一标准,必须优先使用
  3. CommonJS 仅用于老 Node 项目
  4. 核心解决:**作用域隔离、依赖管理、代码复用

# 七、典型案例

# 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 的问题,无需手动改包。

Last Updated: 6/1/2026, 9:21:31 AM