Skip to content

搭配 BabelJS 和 Gulp 使用

Gulp 是一个流行的 JavaScript 任务运行器,可以自动化重复性的开发任务。本章演示如何设置 Gulp 构建流程,使用 Babel 将现代 JavaScript (ES2015+) 转译到 ES5。我们将使用现代的 Gulp 4 语法和最新的 Babel 包。

这种设置适用于已经使用 Gulp 处理其他任务(如 SASS 编译、图像优化)的项目,或者偏好 Gulp 流式处理(stream-based)方式的项目。

首先创建一个新的项目目录,并使用 npm 初始化它:

mkdir gulp-babel-example
cd gulp-babel-example
npm init -y

这将生成一个 package.json 文件。

将 Gulp 和必需的 Babel 包作为开发依赖(devDependencies)安装:

npm install --save-dev gulp gulp-babel @babel/core @babel/preset-env gulp-connect

这些包的说明:

  • gulp:Gulp 任务运行器本身。
  • gulp-babel:一个 Gulp 插件,用于将 JavaScript 文件通过管道(pipe)传递给 Babel 进行处理。
  • @babel/core:Babel 核心转译引擎。
  • @babel/preset-env:用于将现代 JavaScript 编译到你的目标环境(target environments)的标准 Babel 预设(preset)。
  • gulp-connect:一个 Gulp 插件,用于运行一个具备热重载(live reload)功能的本地开发服务器(可选,但很有用)。

你的 package.json 的 devDependencies 部分现在将包含这些包(版本号可能有所不同):

{
// ... package.json 的其他内容 ...
"devDependencies": {
"@babel/core": "^7.x.x",
"@babel/preset-env": "^7.x.x",
"gulp": "^4.x.x",
"gulp-babel": "^8.x.x",
"gulp-connect": "^5.x.x"
}
}

在你的项目根目录创建一个 Babel 配置文件 babel.config.json。这个文件会告诉 gulp-babel 如何转译代码:

babel.config.json
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"browsers": ["> 1%", "last 2 versions", "not dead"]
}
}
]
]
}

这个配置使用 @babel/preset-env,根据常见的浏览器使用统计来设定目标浏览器(target browsers)。

在你的项目根目录创建 gulpfile.js 文件。这个文件将定义你的 Gulp 任务。

// gulpfile.js
const gulp = require('gulp');
const babel = require('gulp-babel');
const connect = require('gulp-connect');
// 源文件和目标路径
const paths = {
scripts: {
src: 'src/**/*.js',
dest: 'dist/js/'
},
html: {
src: 'src/**/*.html',
dest: 'dist/'
}
};
// 转译 JavaScript 文件
function scripts() {
return gulp.src(paths.scripts.src, { sourcemaps: true }) // 启用 source maps
.pipe(babel()) // 默认使用 babel.config.json
.on('error', function(err) {
console.error('[Babel Error]', err.toString());
this.emit('end'); // 防止 Babel 错误导致 Gulp 崩溃
})
.pipe(gulp.dest(paths.scripts.dest))
.pipe(connect.reload()); // 触发热重载
}
// 复制 HTML 文件
function html() {
return gulp.src(paths.html.src)
.pipe(gulp.dest(paths.html.dest))
.pipe(connect.reload());
}
// 监听文件变化
function watchFiles() {
gulp.watch(paths.scripts.src, scripts);
gulp.watch(paths.html.src, html);
}
// 启动本地开发服务器
function server() {
connect.server({
root: 'dist',
livereload: true,
port: 8080
});
}
// 定义复杂任务
const build = gulp.parallel(html, scripts);
const serve = gulp.series(build, gulp.parallel(watchFiles, server));
// 导出任务
exports.scripts = scripts;
exports.html = html;
exports.watch = watchFiles;
exports.build = build;
exports.serve = serve;
exports.default = serve; // 运行 `gulp` 命令时的默认任务

这个 gulpfile.js 文件定义了几个任务:

  • scripts:从 src/ 目录获取 .js 文件,使用 Babel 转译,保存到 dist/js/ 目录,并触发热重载。
  • html:将 HTML 文件从 src/ 复制到 dist/ 目录,并触发热重载。
  • watchFiles:监听 src/ 目录下的文件变化,并重新运行相应的任务。
  • server:使用 gulp-connect 启动一个本地 web 服务器,服务于 dist 目录下的文件。
  • build:一个并行任务,运行 html 和 scripts。
  • serve(和 default):先运行一次 build,然后并行启动 server 和 watchFiles 任务。

创建 src 目录。在其内部创建 index.html 和 js/main.js。

文件 src/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gulp Babel Example</title>
</head>
<body>
<h1>Modern JavaScript with Gulp and Babel</h1>
<p id="message"></p>
<script src="js/main.js"></script>
</body>
</html>

文件 src/js/main.js:

src/js/main.js
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
greet() {
const messageElement = document.getElementById('message');
if (messageElement) {
messageElement.textContent = `Hello, ${this.fullName}! Welcome.`;
}
}
}
const person = new Person('Alex', 'Developer');
person.greet();
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(`Sum of numbers: ${sum}`);

为了方便,向你的 package.json 中添加脚本:

// package.json(scripts 部分)
"scripts": {
"start": "gulp",
"build": "gulp build"
}

构建项目:

npm run build

这将在项目根目录创建一个 dist 文件夹,其中包含转译后的 js/main.js 文件和复制过来的 index.html 文件。

转译后的 dist/js/main.js 文件(示例片段):

"use strict";
function _classCallCheck(instance, Constructor) { /* ... */ }
function _defineProperties(target, props) { /* ... */ }
function _createClass(Constructor, protoProps, staticProps) { /* ... */ }
var Person = /*#__PURE__*/function () {
function Person(firstName, lastName) {
_classCallCheck(this, Person);
this.firstName = firstName;
this.lastName = lastName;
}
_createClass(Person, [{
key: "fullName",
get: function get() {
return "".concat(this.firstName, " ").concat(this.lastName);
}
}, {
key: "greet",
value: function greet() {
var messageElement = document.getElementById('message');
if (messageElement) {
messageElement.textContent = "Hello, ".concat(this.fullName, "! Welcome.");
}
}
}]);
return Person;
}();
var person = new Person('Alex', 'Developer');
person.greet();
var numbers = [1, 2, 3, 4, 5];
var sum = numbers.reduce(function (acc, num) {
return acc + num;
}, 0);
console.log("Sum of numbers: ".concat(sum));
//# sourceMappingURL=main.js.map

启动带有热重载和文件监听功能的开发服务器:

npm start

在浏览器中打开 http://localhost:8080。你应该会看到问候消息。如果你修改 src/js/main.js 或 src/index.html 文件,浏览器将自动重载以显示更改。

  • 现有 Gulp 项目:如果你的项目已经使用 Gulp 处理其他构建任务,集成 Babel 会非常简单。
  • 流处理:如果你更偏好 Gulp 流式处理(stream-based)的文件处理哲学。
  • 更简单的构建需求:对于不需要像 Webpack 那样完整模块打包器复杂性的项目(例如,不严重依赖复杂的模块分割、摇树优化或多样化的资源管理)。
  • 服务器端 JavaScript:Gulp 可以用于转译 Node.js 应用,以适应不支持所有现代 JS 特性的环境。

虽然像 Webpack 或 Parcel 这样的模块打包器因其高级的代码分割和依赖管理等特性,常被青睐用于前端应用,但 Gulp 对于许多构建自动化场景(包括 Babel 转译)来说,仍然是一个强大且灵活的工具。