0%

JavaScript 模块系统

为什么需要模块?

模块化让代码组织更好,可维护性强。

CommonJS

Node.js 使用。

1
2
3
4
5
6
7
// module.js
const value = 42
function func() { ... }
module.exports = { value, func }

// main.js
const { value, func } = require('./module')

ES6 Modules

现代标准。

1
2
3
4
5
6
// module.js
export const value = 42
export function func() { ... }

// main.js
import { value, func } from './module'

默认导出

1
2
3
4
5
// module.js
export default function() { ... }

// main.js
import func from './module'

动态导入

1
2
3
import('./module.js').then(module => {
// 使用模块
})

模块加载

浏览器

1
<script type="module" src="main.js"></script>

Node.js

1
2
3
4
// package.json
{
"type": "module"
}

工具支持

  • Webpack
  • Rollup
  • Vite

总结

ES6 Modules 是未来趋势。支持静态分析,Tree Shaking 等优化。逐渐替代 CommonJS。

其他模块规范

AMD (Asynchronous Module Definition)

适用于浏览器环境,支持异步加载:

1
2
3
4
5
define(['dep'], function(dep) {
return {
foo: function() { ... }
};
});

UMD (Universal Module Definition)

兼容 CommonJS、AMD 和全局变量,常见于库发布。

1
2
3
4
5
6
7
8
9
10
11
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(factory);
} else if (typeof module === 'object' && module.exports) {
module.exports = factory();
} else {
root.MyLib = factory();
}
}(this, function () {
return { /* ... */ };
}));

SystemJS

一个动态加载模块的加载器,可在浏览器和 Node 中使用。

模块打包工具

  • Webpack:默认支持 ES modules,使用 import 语法。
  • Rollup:专注于库打包,支持 Tree Shaking。
  • Parcel/Vite:零配置,内置 ESM 支持。
  • Babel:可以将 ES6 模块转换为 CommonJS,以兼容旧环境。

模块加载流程

  1. 解析依赖树
  2. 下载/读取模块
  3. 执行模块代码
  4. 缓存模块结果

静态导入在编译阶段解析,动态导入在运行时加载。

模块性能与优化

  • 采用 ES modules 可减少打包体积
  • 使用 import() 做懒加载
  • 合理拆分代码,避免重复依赖
  • 利用浏览器原生缓存

兼容性问题

功能 浏览器 Node.js
静态 import 支持(script type=“module”) 需配置
动态 import() 支持 支持
默认导出 interop 需要 Babel 处理 自动兼容

迁移策略

  1. 逐步将 CommonJS 文件改为 ES modules
  2. 使用工具(cjs-to-esm, babel-plugin-transform-modules-commonjs)
  3. 在 package.json 中添加 "type": "module" 或使用 .mjs 扩展名

未来发展

随着浏览器和 Node 原生支持的普及,模块系统会变得更加统一。标准委员会还在研究模块的加载规范和安全性增强。

附录

  • 模块与命名空间
  • 全局变量污染问题
  • 使用 webpack 的 externals 配置避免重复打包