将 ES6 模块转译到 ES5
BabelJS - 转译 ES 模块
Section titled “BabelJS - 转译 ES 模块”ECMAScript 2015 (ES6) 为 JavaScript 引入了标准化的模块系统,使用 import 和 export 语句。这使得开发者能够将代码组织成可复用、独立的单元。本章演示如何使用 Babel 将 ES 模块转译成与旧环境兼容的格式,通常会结合 Webpack 等模块打包器或 Gulp 与 Browserify 等任务运行器。
理解 ES 模块
Section titled “理解 ES 模块”模块本质上就是一个 JavaScript 文件。在模块内部定义的变量、函数或类在该模块之外是私有的,除非被显式地导出(export)。其他模块可以通过导入(import)来使用这些导出的成员。
这套系统促进了代码组织、可复用性,并有助于管理大型应用中的依赖关系。
示例模块结构
Section titled “示例模块结构”我们来创建一个包含几个模块的简单项目。
创建文件 src/math/add.js:
export const add = (x, y) => { return x + y;};
export const PI = 3.14159;创建文件 src/math/multiply.js:
const multiply = (x, y) => { return x * y;};
export default multiply; // 这是一个默认导出的例子创建文件 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 和 Babel 转译 ES 模块
Section titled “使用 Webpack 和 Babel 转译 ES 模块”Webpack 是一个流行的模块打包器。它可以处理你的 ES 模块,使用 Babel 进行转译,并输出一个或多个打包后的文件。
- 项目设置:
如果你的项目还没有初始化,请先初始化并安装 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 文件,内容如下:
{ "presets": ["@babel/preset-env"]}- Webpack 配置:
在你的项目根目录创建 webpack.config.js 文件:
// webpack.config.jsconst 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进行转译。
- 添加构建脚本:
在你的 package.json 中,添加一个用于运行 Webpack 的脚本:
// package.json(scripts 部分)"scripts": { "build": "webpack"}- 构建:
运行构建命令:
npm run buildWebpack 将处理 src/main.js,追踪其导入的模块,使用 Babel 转译所有 JavaScript 文件,并创建 dist/bundle.js。然后可以将此 bundle.js 文件包含在 HTML 文件中。
- 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)。
- 项目设置:
安装 Gulp 及相关包:
npm install --save-dev gulp browserify babelify vinyl-source-stream vinyl-buffer @babel/core @babel/preset-env确保你有一个 babel.config.json 文件,内容如 Webpack 部分所示。
- Gulp 配置:
在你的项目根目录创建 gulpfile.js 文件:
// gulpfile.jsconst 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(并行)来组合任务。
- 添加构建脚本:
在 package.json 中:
// package.json(scripts 部分)"scripts": { "build:webpack": "webpack", "build:gulp": "gulp scripts", "start:gulp": "gulp"}- 构建:
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 的项目的可行选择。