背景
前端经历了一系列的发展,各种标准和工具百花齐放,自从2009年的Node.js
诞生,前端先后出现了CommonJS
、AMD
、CMD
、UMD
和ES Module
等模块规范,底层规范的发展催生出了一系列工具链的创新,比如AMD
规范提出时社区诞生了模块加载工具requireJS
,基于CommonJS
规范的模块打包工具browserify
,还有能让用户提前用上ES Module
语法的JS编译器Babel
、兼容各种模块规范的重量级打包工具webpack
以及基于浏览器原生ES Module
支持而实现的no-bundle
构建工具Vite
等等。
模块化的起点:直接引入脚本
最早的前端开发依赖简单的 <script>
标签来引入 JavaScript 文件
CommonJS规范
CommonJS是业界最早正式提出的JavaScript模块规范,主要用于服务端,随着Node.js越来越普及,这个规范也被业界广泛应用,对于模块规范而言,一般会包含两个方面的内容:
- 统一的模块化代码规范
- 实现自动加载模块的加载器(也称之为
loader
)
代码中使用了require
来导入一个模块,用module.exports
来导入一个模块。对于ConnonJS而言,一方面它定义了一套完整的模块化代码规范,另一方面Node.js
为之实现了自动加载模块的loader
,看上去是一个不错的模块规范,但是也存在一些问题:模块加载器由Node.js
提供,依赖了Node.js
本身的功能实现,比如文件系统,如果CommonJS模块直接放到浏览器中是无法执行的
AMD规范
AMD
全称为Asynchronous Module Definition
,即异步模块定义规范,模块根据这个规范,在浏览器环境中被异步加载,而不会像CommonJS
规范进行同步加载,也就不会产生同步请求导致的浏览器解析过程阻塞的问题了
CMD规范
同期出现的规范当中也有CMD规范,这个规范是由淘宝出品的SeaJS
实现的,解决的问题和AMD
一样,不过随着社区的不断发展,SeaJS已经被requireJS
兼容了。
UMD:统一模块定义
UMD(Universal Module Definition) 兼容 CommonJS 和 AMD,为模块在多种环境下的运行提供支持
ES6 Module
ES6 Module也被称作ES Module
或者ESM
,是由ECMAScript官方提出的模块化规范,作为一个官方提出的规范,ES Module
已经得到了现代浏览器的内置支持,在现代浏览器中,如果在HTML中加入含有type='module'
属性的script标签,name浏览器会按照ESModule规范来进行依赖加载和模块解析,这也是vite在开发阶段实现no-bundle的原因,由于模块加载的任务交给了浏览器,即使不打包也可以顺序运行模块代码。
工具链的发展
随着模块规范的演进,各种工具不断创新,推动前端开发的工程化:
- RequireJS:基于 AMD,用于模块加载。
- Browserify:基于 CommonJS,将 Node.js 模块打包到浏览器中。
- Webpack:支持多种模块规范,提供强大的打包能力,成为行业标准。
- Babel:允许开发者提前使用 ES Module 语法,将其转为兼容的代码。
- Vite:基于浏览器原生 ES Module 支持,优化开发体验,无需预打包。
总结
前端模块化经历了从混乱到规范化的过程,推动了前端生态的繁荣发展。从最初的 CommonJS 和 AMD 到官方的 ES Module,每一代规范都解决了特定场景下的问题。如今,ES Module 已成为行业标准,而工具链如 Webpack 和 Vite 进一步提升了开发效率。模块化的发展不仅提高了代码可维护性,也为复杂前端项目的实现奠定了基础。