Skip to content

将 ES6 模块转译到 ES5

ECMAScript 2015 (ES6) 为 JavaScript 引入了标准化的模块系统,使用 import 和 export 语句。这使得开发者能够将代码组织成可复用、独立的单元。本章演示如何使用 Babel 将 ES 模块转译成与旧环境兼容的格式,通常会结合 Webpack 等模块打包器或 Gulp 与 Browserify 等任务运行器。

模块本质上就是一个 JavaScript 文件。在模块内部定义的变量、函数或类在该模块之外是私有的,除非被显式地导出(export)。其他模块可以通过导入(import)来使用这些导出的成员。

这套系统促进了代码组织、可复用性,并有助于管理大型应用中的依赖关系。

我们来创建一个包含几个模块的简单项目。

创建文件 src/math/add.js:

src/math/add.js
export const add = (x, y) => {
return x + y;
};
export const PI = 3.14159;

创建文件 src/math/multiply.js:

src/math/multiply.js
const multiply = (x, y) => {
return x * y;
};
export default multiply; // 这是一个默认导出的例子

创建文件 src/main.js(我们的入口文件):

src/main.js
import multiplyByTwo, { PI as MathPI } from './math/multiply.js'; // 导入默认导出和命名导出
import { add } from './math/add.js';
const num1 = 10;
const num2 = 20;
const sum = add(num1, num2);
const product = multiplyByTwo(num1, num2); // 使用导入的默认导出
console.log(`The sum of ${num1} and ${num2} is ${sum}.`);
console.log(`PI is approximately ${MathPI}.`);
console.log(`The product of ${num1} and ${num2} (using default export) is ${product}.`);

注意,使用 export const 进行命名导出,使用 export default 进行默认导出,以及使用 import 语句来导入它们。as 关键字可以用于给导入的内容起别名(alias)。

浏览器和 Node.js 对原生 ES 模块的支持程度各不相同。为了实现广泛的兼容性,尤其是在旧浏览器或当目标环境是 CommonJS(例如旧版 Node.js)时,我们需要对这些模块进行转译(transpile)和打包(bundle)。

Webpack 是一个流行的模块打包器。它可以处理你的 ES 模块,使用 Babel 进行转译,并输出一个或多个打包后的文件。

  1. 项目设置:

如果你的项目还没有初始化,请先初始化并安装 Babel(参考“使用 Babel 7+ 进行项目设置”章节)。然后,安装 Webpack 及相关包:

npm init -y # 如果是新项目
npm install --save-dev webpack webpack-cli babel-loader @babel/core @babel/preset-env

你的 package.json 文件的 devDependencies 部分应该包含这些依赖。请确保你有一个 babel.config.json 文件,内容如下:

babel.config.json
{
"presets": ["@babel/preset-env"]
}
  1. Webpack 配置:

在你的项目根目录创建 webpack.config.js 文件:

// webpack.config.js
const path = require('path');
module.exports = {
mode: 'development', // 或 'production' 用于优化构建
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
// Babel 配置也可以在这里,但更推荐使用 babel.config.json 文件
// presets: ['@babel/preset-env']
}
}
}
]
},
devtool: 'source-map' // 可选:用于更好的调试
};

此配置告诉 Webpack:

  • 入口文件是 src/main.js。
  • 输出的打包文件将是 dist/bundle.js。
  • 对于任何 .js 文件(排除 node_modules 目录下的),使用 babel-loader 进行转译。
  1. 添加构建脚本:

在你的 package.json 中,添加一个用于运行 Webpack 的脚本:

// package.json(scripts 部分)
"scripts": {
"build": "webpack"
}
  1. 构建:

运行构建命令:

npm run build

Webpack 将处理 src/main.js,追踪其导入的模块,使用 Babel 转译所有 JavaScript 文件,并创建 dist/bundle.js。然后可以将此 bundle.js 文件包含在 HTML 文件中。

  1. HTML 文件:

创建文件 dist/index.html:

<!DOCTYPE html>
<html>
<head>
<title>ES Modules with Webpack & Babel</title>
</head>
<body>
<h1>Check the console!</h1>
<script src="bundle.js"></script>
</body>
</html>

在浏览器中打开 dist/index.html 文件。控制台将显示 src/main.js 的输出内容。

dist/bundle.js 文件将包含你所有模块的代码,经过转译和打包,以及 Webpack 用于管理模块的运行时代码。

使用 Gulp、Browserify 和 Babelify 转译 ES 模块

Section titled “使用 Gulp、Browserify 和 Babelify 转译 ES 模块”

Gulp 是一个任务运行器。Browserify 可以通过打包所有依赖项,让你在浏览器中使用 require('modules')。Babelify 是一个使用 Babel 的 Browserify 转换(transform)。

  1. 项目设置:

安装 Gulp 及相关包:

npm install --save-dev gulp browserify babelify vinyl-source-stream vinyl-buffer @babel/core @babel/preset-env

确保你有一个 babel.config.json 文件,内容如 Webpack 部分所示。

  1. Gulp 配置:

在你的项目根目录创建 gulpfile.js 文件:

// gulpfile.js
const gulp = require('gulp');
const browserify = require('browserify');
const babelify = require('babelify');
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');
gulp.task('scripts', function () {
return browserify({
entries: './src/main.js',
debug: true // 启用 source maps
})
.transform(babelify, { presets: ['@babel/preset-env'] }) // Babelify 转换
.bundle()
.on('error', function (err) {
console.error(err.toString());
this.emit('end');
})
.pipe(source('bundle.js')) // 输出文件名
.pipe(buffer()) // 转换为缓冲的 vinyl 对象(可选,用于其他插件)
.pipe(gulp.dest('./dist_gulp')); // 输出目录
});
gulp.task('watch', function() {
gulp.watch('./src/**/*.js', gulp.series('scripts'));
});
gulp.task('default', gulp.series('scripts', 'watch'));

这个 Gulp 任务:

  • 使用 Browserify,并以 src/main.js 作为入口文件。
  • 应用 babelify 转换,配置为使用 @babel/preset-env。
  • 打包代码。
  • 将 bundle.js 输出到 dist_gulp 目录。

注意:Gulp 4 使用 gulp.series(串行)和 gulp.parallel(并行)来组合任务。

  1. 添加构建脚本:

在 package.json 中:

// package.json(scripts 部分)
"scripts": {
"build:webpack": "webpack",
"build:gulp": "gulp scripts",
"start:gulp": "gulp"
}
  1. 构建:
npm run build:gulp

这将创建 dist_gulp/bundle.js 文件。然后你可以像 Webpack 示例一样,在 HTML 文件中使用它,将脚本源指向 dist_gulp/bundle.js。

运行 npm run start:gulp 将先执行构建,然后监听文件变化。

转译 ES 模块对于以下情况至关重要:

  • 大型应用:维护结构清晰、依赖明确的代码库。
  • 库开发:创建可在各种项目和环境中使用的可复用 JavaScript 库。
  • 浏览器兼容性:确保现代的基于模块的代码能在缺乏原生 ES 模块支持或实现不完整的旧浏览器中运行。
  • Node.js 开发:虽然现代 Node.js 对 ES 模块支持良好,但你可能需要针对旧版本,或者需要与 CommonJS 模块互操作,这时转译会很有益处。

像 Webpack 和 Rollup 这样的工具通常因其广泛的功能(如代码分割、摇树优化和资源管理)而更受青睐用于复杂的应用打包。而 Gulp 与 Browserify 组合仍然是处理更简单的构建流程或已在使用 Gulp 的项目的可行选择。