require
和
module.exports
机制实现模块的导入和导出。
CommonJS 是一种用于 JavaScript 的模块系统规范,最初由 Node.js 引入并广泛使用,它定义了一个简单的模块加载机制,允许开发者将代码拆分成多个文件,每个文件作为一个模块,从而实现代码的重用和模块化开发。
在 CommonJS 中,一个模块通常包含以下部分:
1、模块导出(exports):
使用module.exports
或exports
对象来导出模块的公共接口。
module.exports
可以是一个值的引用,而exports
是该值的一个快捷方式,但推荐直接使用module.exports
以避免混淆。
2、模块导入(require):
使用require()
函数来导入其他模块。
require()
返回的是被导入模块的module.exports
属性的值。
3、模块缓存:
Node.js 会缓存所有被加载的模块,确保每个模块只被加载一次,提高性能。
虽然 CommonJS 本身不涉及编译过程(它是运行时的模块加载机制),但在实际应用中,我们经常需要将 CommonJS 模块转换为其他格式(如 ES6 模块或浏览器可执行的格式),这时就需要用到编译工具,以下是常见的编译步骤和工具:
1. Babel 转译
Babel 是一个广泛使用的 JavaScript 编译器,可以将 ES6+ 代码转换为向后兼容的 JavaScript 代码,它也支持将 CommonJS 模块转换为 ES6 模块。
安装 Babel:
npm install --save-dev @babel/core @babel/cli @babel/preset-env
配置 Babel:
创建或更新.babelrc
文件,指定预设:
{ "presets": ["@babel/preset-env"] }
编译命令:
npx babel src --out-dir lib
这将把src
目录下的 CommonJS 模块转换为 ES6 模块并输出到lib
目录。
2. Webpack 打包
Webpack 是一个强大的模块打包器,可以将 CommonJS 模块及其依赖打包成一个或多个浏览器可执行的文件。
安装 Webpack:
npm install --save-dev webpack webpack-cli
配置 Webpack:
创建或更新webpack.config.js
文件,指定入口文件和输出配置:
const path = require('path'); module.exports = { entry: './src/index.js', // 入口文件 output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, mode: 'development' // 或 'production' };
运行 Webpack:
npx webpack
这将根据配置打包src/index.js
及其依赖,生成dist/bundle.js
。
四、CommonJS 与 ES6 模块的区别
特性 | CommonJS | ES6 模块 |
导出方式 | module.exports 或exports |
export 关键字 |
导入方式 | require() |
import 关键字 |
加载时机 | 同步加载,运行时解析 | 异步加载,编译时解析 |
循环引用 | 支持,但可能导致问题 | 不支持,会抛出错误 |
模块缓存 | 有,Node.js 实现 | 无,每次导入都是新的实例 |
Q1: CommonJS 模块可以在浏览器中直接使用吗?
A1: 不可以,CommonJS 是 Node.js 的模块系统,依赖于 Node.js 的require()
和module.exports
,这些在浏览器环境中是不可用的,如果需要在浏览器中使用 CommonJS 模块,需要先使用编译工具(如 Webpack 或 Browserify)将其转换为浏览器可执行的格式(如 ES6 模块或 IIFE)。
Q2: CommonJS 和 ES6 模块有什么区别,我应该选择哪一个?
A2: 选择取决于你的项目需求和目标环境,如果你的项目主要运行在 Node.js 环境中,或者需要支持老旧的浏览器,CommonJS 是一个不错的选择,如果你的项目是面向现代浏览器的,或者你希望利用 ES6+ 的新特性(如静态导入、异步加载等),ES6 模块可能更适合你,随着 JavaScript 社区的发展,越来越多的工具和框架开始支持 ES6 模块,因此它是一个值得考虑的未来趋势,但请注意,ES6 模块目前在一些老旧的浏览器中可能不受支持,需要通过 Babel 等工具进行转译。