JavaScript 模块化开发通过拆分代码为独立单元提升可维护性;ESM 是原生标准,支持静态分析与树摇;CommonJS 适用于 Node.js 服务端;模块加载器如 RequireJS 解决动态加载;打包工具如 Webpack、Vite 构建时处理依赖并生成 bundle。

JavaScript 模块化开发通过将代码拆分为独立、可复用的单元来提升可维护性和协作效率;模块加载器负责按需解析依赖、加载脚本、执行并管理模块作用域与导出值。
ES Module(ESM)是现代标准方案
ES6 引入的 import/export 语法是 浏览器 和 Node.js原生支持的模块机制。它基于静态分析——在代码执行前就能确定依赖关系,支持树摇(tree-shaking)和循环依赖检测。
- 使用
export导出变量、函数或类,支持命名导出和默认导出 - 使用
import导入,路径必须是字符串字面量(不能拼接),且只能出现在顶层作用域 - 浏览器中需在
中使用,自动启用严格模式、延迟执行、CORS 校验 - Node.js 中需文件后缀为
.mjs或package.json中设置"type": "module"
CommonJS 适合 Node.js 服务端环境
Node.js 早期采用的模块系统,以 require() 和module.exports为核心,运行时动态加载,支持表达式路径和条件引入。
-
require()立即执行被加载模块,并缓存其module.exports对象 - 每个模块有独立作用域,
exports是module.exports的引用别名 - 不支持浏览器原生运行,需借助打包 工具(如 Webpack)转译或模拟
- 与 ESM 互操作需注意:ESM 中
import xxx from 'cjs-module'实际导入的是default属性
模块加载器(如 SystemJS、RequireJS)解决动态加载问题
在 ESM 普及前,前端 需要在无构建环境下按需加载模块。加载器通过注入 标签、XHR 请求或 Fetch 获取源码,再用 eval 或new Function执行,同时维护模块注册表和依赖图。
立即学习“Java 免费学习笔记(深入)”;
- RequireJS 使用 AMD 规范,依赖前置声明:
define(['a', 'b'], function(a, b) {……}) - SystemJS 更灵活,支持 AMD、CommonJS、ESM 等多种格式,可配置路径映射和包版本
- 现代场景中,这类加载器多被 ESM 动态导入
import()替代,后者返回 Promise,支持懒加载和代码分割
打包工具(如 Webpack、Vite)是模块化的“编译中枢”
它们不是运行时加载器,而是构建时分析整个依赖图,将模块转换为单个或多个 bundle,并注入自己的模块运行时(runtime)来模拟 require 或__webpack_require__。
- Webpack 通过
ModuleGraph追踪导入 / 导出关系,支持 HMR(热更新)和分包策略 - Vite 利用 ESM 原生能力,在开发时由浏览器原生加载模块,仅对需转换的代码(如 Vue/Svelte 组件)进行按需编译
- 打包产物中每个模块被包裹在闭包中,避免全局污染,导出值通过内部模块对象传递