转载

[译] Gulp 4 入门指南

[译] Gulp 4 入门指南

  • Original: gulp 4
  • Translated by:@Leooonard &@cssmagic

[译] Gulp 4 入门指南

Introduction

介绍

gulp is a JavaScript-based build tool for automating the execution of web development tasks. Actually, gulp can automate anything that may be done from Node.js. Since Node.js can run shell commands, gulp may be used to automate any task. However, in practice, gulp is primarily used for tasks associated with web development.

Gulp 是一款基于 JavaScript 的构建工具,它主要用于自动化运行 Web 开发中的各项任务。但其实 Node.js 所能做的任何事情都可以通过 Gulp 实现自动化。由于 Node.js 可以执行 shell 命令,因此,Gulp 几乎可以自动化所有任务。不过在实际使用中,Gulp 主要还是在 Web 开发领域用得更多一些。

Gulp 与 Grunt

gulp competes with tools like Grunt, which (like gulp) is also free and open source. Other contenders (far less popular) include: Broccoli, Brunch, Cake, and Jake.

Gulp 的主要竞争对手是 Grunt,它和 Gulp 一样是免费开源的。其他不怎么火的竞争者还有 Broccoli、Brunch、Cake 和 Jake 等等。

One major difference between gulp and Grunt is the way each is configured. Both use a JavaScript source file: one named gulpfile.js and the other Gruntfile.js . Configuration for gulp is accomplished with calls to various functions. Grunt configuration is primarily done by passing a rather large object literal to one function.

Gulp 和 Grunt 之间的一大差异在于它们的配置方式。它们都需要一个 JavaScript 文件来进行配置,比如 Gulp 的配置文件叫作 gulpfile.js ,而 Grunt 用的是 Gruntfile.js 。Gulp 是通过调用多个不同的函数来完成配置的,而 Grunt 则需要把一坨巨大的对象字面量传给一个函数来完成配置。

As a rule, gulp runs faster than Grunt due to its use of streams. The alternative, used by Grunt, is creating many temporary files that are used to make data available to subsequent steps. Using streams allows subsequent steps to begin earlier, as soon as data is available in a stream, instead of waiting for a file to be completely written.

在正常情况下,Gulp 的运行速度比 Grunt 要快,这归功于 “流”(stream)的使用。在运行连续任务时,Grunt 所采用的方式是生成大量的临时文件,以便向后续步骤传递数据。而采用流则允许后续步骤更早地开始,只要流中存在有效的数据即可开始,无需等待整个文件被写完。

Gulp 与 Node.js

To run gulp, Node.js must be installed. It can also run on io.js, which is a fork of Node.js that uses a newer version of the Chrome V8 JavaScript engine and releases new versions more frequently. Like Node.js itself, gulp may be used in Windows, Mac OS X, and *nix operating systems.

如果要使用 Gulp,就必须安装 Node.js。由于 Node.js 是跨平台的,Gulp 也可用于多种平台,包含 Windows、Mac OS X 和 *nix 操作系统。

With both Node.js and io.js, some ES6 (a.k.a ES 2015) features may be used if the --harmony flag is set. To get gulp to use this in a *nix environment, create an alias like the following: alias gulp6='node --harmony $(which gulp)' . This may be placed in .bashrc so it is always available. After this, run gulp commands with gulp6 instead of gulp . In a Windows environment, consider using the doskey command to define something similar to a *nix alias.

如果 Node.js 打开了 --harmony 开关,我们还可以使用 ES6(也就是 ES 2015)的部分特性。如何让 Gulp 用上 ES6 呢?如果你是在 *nix 环境下,那就需要像这样创建一个别名: alias gulp6='node --harmony $(which gulp)' 。你最好把这行代码放进 .bashrc 文件中,这样你在每次打开终端时都可以直接使用这个别名。以后记得用 gulp6 来代替 gulp 命令,以便享受 ES6 带来的新特性。而在 Windows 环境下,你可以尝试 doskey 命令来实现类似的别名效果。

(译注:在较新的 Node 版本中,很多 ES6 特性已经是默认开启的了。)

One ES6 feature, used in some examples in this article, is the arrow function expression. This feature provides a more concise way to write anonymous functions, and it has other benefits ("lexical this"). For purposes of this article, all you need to know is that function () { return *expression*; } in ES5 is roughly equivalent to () => *expression* in ES6. For a thorough discussion of ES6 features, please visit these slides.

本文的某些例子将用到 ES6 的一项新特性,也就是箭头函数表达式。这个特性允许我们使用一种更简洁的方式来书写匿名函数,并且它还有其他的优点(比如:词法作用域的 this )。对于本文,你只需知道 ES5 语法中的 function () { return expression; } 大体上等价于 ES6 中的 () => expression 。关于 ES6 特性的详细讨论,可参考 这组幻灯片 。

插件生态

Typically, plugins are used in the implementation of gulp tasks. A large number of plugins are available: 1,711 as of 5/25/15. To get an updated count in a *nix environment, run

一般来说,我们会用到插件来实现各种 Gulp 任务。截止到 2015 年 5 月 25 日,已经有 1711 个 Gulp 插件可供使用。在 *nix 环境下,你可以执行如下命令来查询最新的插件数量:

npm search gulpplugin | wc-l

Common tasks that may be run using gulp include:

我们可以使用 Gulp 来完成以下常见任务:

  • validating/linting HTML, CSS, JavaScript, and JSON files
  • compiling ES6 JavaScript code to ES5 (using Babel, Traceur, or TypeScript)
  • running unit tests and end-to-end tests
  • concatenating and minimizing CSS and JavaScript files
  • serving static files via HTTP
  • executing shell commands
  • watching specific files or file types for changes and running specific tasks when they do
  • reloading a web browser after modified files have been processed (livereload)
  • 校验 HTML、CSS、JavaScript 和 JSON 文件的语法。
  • 将 ES6 JavaScript 代码编译为 ES5(通过使用 Babel、Traceur 或者 TypeScript)。
  • 运行单元测试和端到端测试。
  • 合并和压缩 CSS、JavaScript 文件。
  • 通过 HTTP 来提供静态文件服务。
  • 执行 shell 命令。
  • 监听特定文件(或特定文件类型)的变动,当发现文件改变时运行特定任务。
  • 当这些有变化的文件被处理后刷新浏览器(LiveReload)。

(译注:关于 Gulp 插件,下文将会详述。)

At the time of writing, the current stable version of gulp was 3. New development should use version 4, which is the version this article targets. Version 4 is not backward-compatible with version 3. Changes to gulpfile.js files are required. However, most plugins written for version 3 should work with version 4.

在撰写这篇文章时,Gulp 最新的稳定版本为 3。本文介绍的目标是最新的开发版本 4。 Gulp 4 并不向后兼容 3 ,因此升级后你需要修改 gulpfile.js 。当然,大部分面向 v3 的插件仍然可以在 v4 中正常使用。

Throughout this article, references to "terminal" may be replaced by "Command Prompt" when using Windows.

如果你用的是 Windows,那么本文所述的 “终端” 实际上对你来说就是 “命令提示符(Command Prompt)” 程序了。

Installing gulp

安装 Gulp

To make the gulp command available from a terminal, enter npm install -g gulp . This installs the current, stable version.

在执行 npm install -g gulp 之后,就可以在命令行使用 gulp 命令了。这个操作将安装最新的稳定版本。

Until version 4 becomes the stable version, follow these steps to install it:

不过本文是在讨论 Gulp 4,而它还没有正式发布成为稳定版,因此我们需要通过以下步骤来安装它:

  1. Open a terminal.
  2. Verify that git is installed.
  3. If a previous version of gulp is installed, uninstall it with npm uninstall -g gulp
  4. Install version 4 with npm install -g gulpjs/gulp-cli#4.0
  1. 打开终端。
  2. 确定已正确安装 Git。(译注:Mac OS X 自带 Git。)
  3. 如果你之前安装过 Gulp,则需要使用 npm uninstall -g gulp 命令来卸载旧版本。
  4. 执行 npm install -g gulpjs/gulp-cli#4.0 命令,安装 Gulp 4。

To configure a project to use gulp 4:

如果你只想在某个项目的范围之内使用 Gulp 4,那就这样做:

  1. Open a terminal.
  2. cd to the top project directory.
  3. If no package.json file exists, create one by running npm init and answering the questions it asks.
  4. Install gulp locally and add it as a dependency in package.json by running npm install gulp --save-dev
  5. If a previous version of gulp is installed, uninstall it with npm uninstall gulp
  6. npm install gulpjs/gulp.git#4.0 --save-dev
  7. Create gulpfile.js (described later).
  1. 打开终端。
  2. 进入这个工作项目的顶层目录。
  3. 如果该项目还没有 package.json 文件,则需要通过 npm init 命令来新建一个。在此过程中会有一些命令行交互。
  4. 如果之前该项目已安装过低于 4.x 版本的 Gulp,那么先使用 npm uninstall gulp --save-dev 指令卸载它,再安装 Gulp 4。
  5. 以 “局部安装” 的方式把 Gulp 作为一个依赖添加到 package.json 文件中,命令如下: npm install gulpjs/gulp.git#4.0 --save-dev (译注:原文所述步骤有误,译文已作修正。)
  6. 创建 gulpfile.js (后面会详细介绍)。

The --save-dev option of npm install adds a development dependency to package.json . This allows other developers on the team to install all of the project dependencies by running npm install .

npm install--save-dev 参数将在 package.json 中添加一个开发依赖。这使得团队内的其他开发者可以通过 npm install 命令来安装该项目所需的所有依赖。

Running gulp

运行 Gulp

Before attempting to run a gulp task that is defined in the project gulpfile.js , cd to the top project directory or a subdirectory.

各项 Gulp 任务都是由 gulpfile.js 来定义的。在尝试运行各项任务之前,我们不妨进入这个工作项目的顶层目录或某个子目录内,先来熟悉一下 Gulp 的基本操作。

To get basic help on gulp options, enter gulp --help or gulp -h .

执行 gulp --helpgulp -h 可以获取基本的帮助信息。

To see the version of gulp that is installed, enter gulp --version or gulp -v . This shows the versions of the globally-installed command-line interpreter (CLI) and the project-specific, locally installed version.

执行 gulp --versiongulp -v 可以查看本机安装的 Gulp 版本号。此命令会同时显示(以全局方式安装的)命令行程序的版本号和该项目自身(以局部方式安装)的 Gulp 的版本号。

To see a list of the tasks defined in gulpfile.js for the current project, enter gulp --tasks or gulp -T . This outputs a task dependency tree. To see a flat list of tasks in the order they are defined, enter gulp --tasks-simple .

执行 gulp --tasksgulp -T 可以查看 gulpfile.js 文件所定义的所有任务。此命令将以依赖树的形式呈现所有任务。如果你希望按照定义顺序、以平铺的方式来查看任务列表,请执行 gulp --tasks-simple

To check for usage of blacklisted plugins, enter gulp --verify . This examines the dependencies listed in the project's package.json file.

执行 gulp --verify 可以检查当前项目是否用到了被列入黑名单的 Gulp 插件。此命令将检查 package.json 文件指定的所有依赖。

To run tasks defined in gulpfile.js , enter gulp [options] task1 task2... . While there are options that may be specified when running tasks, typically none is used. When multiple tasks are specified, they run in parallel. If they need to be run sequentially, define a task that does that, and run that one task. If no task is specified, the default task is run. We'll see how to define a default task later. If no task is specified and no default task is defined, an error message is displayed.

执行 gulp [options] task1 task2... 可以运行 gulpfile.js 所定义的任务。除了任务名外,我们还可以附加一些可选的选项(译注:即 [options] 这个部分),不过通常来说用不到。

如果我们同时指定了多个任务名,则它们将被并行运行。如果多个任务需要以串行的方式运行,那么我们就需要在 gulpfile.js 中定义一个新任务来指定这几个任务的运行顺序,然后在命令行中单独运行这个新任务。

如果没有指定任务名,则会有一个默认任务被运行,稍后我们会讨论如何定义一个默认任务。如果不指定具体的任务,并且没有定义 default 任务,那会显示一条错误信息。

Most tasks run to completion and gulp exits. Some tasks such as connect (for serving files using HTTP) and watch (for watching for file changes) run until cancelled, and gulp does not exit on its own. To cancel a task and exit gulp, press ctrl-c.

大部分任务运行结束后 Gulp 将退出。但某些任务是例外,例如 connect (用于提供 HTTP 静态资源服务)和 watch (用于监听文件是否有改动)等等,Gulp 将不会自动退出,这些任务会一直运行,直到被中止(译注:或者任务自己出错退出)。你可以按 Ctrl-C 组合键来中止任务并让 Gulp 退出。

gulp Plugins

Gulp 插件

The large number of available plugins can make finding good ones challenging. To get you started, here is a list of recommended plugins:

Gulp 拥有大量的插件可供选用,为了缓解你的选择困难症,我直接推荐一些优秀插件给你吧:

  • gulp-babel - compiles ES6 to ES5
  • gulp-changed - only processes (pipes through) src files that are newer than dest files
  • gulp-concat - concatenates CSS and JavaScript files
  • gulp-csslint - validates CSS files
  • gulp-eslint - validates JavaScript files using ESLint
  • gulp-jasmine - runs Jasmine tests
  • gulp-jshint - validates JavaScript files using JSHint
  • gulp-jscs - checks JavaScript code style using JSCS
  • gulp-less - compiles LESS files to CSS
  • gulp-livereload - reloads a web browser listening for livereload requests when the livereload method is called
  • gulp-plumber - allows gulp to continue running after errors
  • gulp-sourcemaps - generates sourcemap files that allow debugging in files (ES6, CoffeeScript, TypeScript, ...) that are compiled to the ES5 JavaScript running in the browser
  • gulp-uglify - minimizes JavaScript files
  • gulp-usemin - replaces HTML link / script tags that refer to individual .css and .js files with single tags that refer to concatenated/minimized versions
  • gulp-watch - watches files for changes and runs specified tasks when they do
  • gulp-babel - 将 ES6 编译为 ES5。
  • gulp-changed - 过滤掉比目标文件旧的文件(只处理有更新的文件)。
  • gulp-concat - 合并 CSS 和 JavaScript 文件。
  • gulp-csslint - 校验 CSS 代码质量。
  • gulp-eslint - 使用 ESLint 来校验 JavaScript 代码质量。
  • gulp-jasmine - 运行 Jasmine 测试。
  • gulp-jshint - 使用 JSHint 来校验 JavaScript 代码质量。
  • gulp-jscs - 使用 JSCS 来校验 JavaScript 代码风格。
  • gulp-less - 将 LESS 文件编译为 CSS。
  • gulp-livereload - 当调用 livereload 方法时,刷新监听 livereload 事件的浏览器。
  • gulp-plumber - 允许 Gulp 在发生错误之后继续运行。
  • gulp-sourcemaps - 和成 sourcemap 文件,便于调试源码(因为 ES6、CoffeeScript、TypeScript 等格式的源码需要编译为 ES5 才能在浏览器中运行)。
  • gulp-uglify - 压缩 JavaScript 文件。
  • gulp-usemin - 将 HTML 文件中 CSS 和 JS 文件的路径替换为对应的 min 版本(已经合并、压缩过的版本)。
  • gulp-watch - 监听文件是否被修改,并且在文件修改时运行指定任务。

In addition, the npm module del is commonly used. This deletes specified directories and files.

此外,有个叫 del 的 npm 包也十分常用。我们可以用它来删除指定的目录和文件。

One way to search for gulp plugins is to browse http://gulpjs.com/plugins . Plugins that are published to npm with the "gulpplugin" keyword are automatically cataloged at this site. Using this site has the advantage of being able to click the name of a plugin to browse its documentation page. Another way to search for a plugin is the npm search command. For example, to get a list of all gulp plugins that perform some kind of linting, enter npm search gulpplugin lint .

我们可以在 http://gulpjs.com/plugins 这个页面搜索 Gulp 插件。所有以 "gulpplugin" 关键词发布到 npm 的插件都会自动被收录到这个页面。这个页面的好处在于,点击任一插件名均可跳至该插件的文档页面。搜索插件的另外一条路是使用 npm search 命令。比如说,执行 npm search gulpplugin lint 即可找到所有具有 linting 功能的插件。

To install a plugin, enter npm install plugin-name --save-dev . This installs the plugin in the project node_modules directory. Once the plugin is installed, modify gulpfile.js to "require" the plugin and use it in one or more tasks. For example, var foo = require('gulp-foo');

执行 npm install plugin-name --save-dev 即可安装一个插件。插件将被安装到项目的 node_modules 目录。一旦某个插件安装好之后,我们就可以在 gulpfile.js 文件中引入( require )该插件,并将它运用到一个或多个任务中。比如像这样: var foo = require('gulp-foo');

A better way to "require" plugins is to use the gulp-load-plugins plugin. This makes it unnecessary to add a require for each plugin to gulpfile.js . The function provided by this plugin returns an object with properties that are the base names of the plugins. It loads dependencies in package.json whose names start with " gulp- ". Plugin loading is done lazily, which means that plugins are not loaded until their first use. Unused plugins are never loaded.

其实还有一种更好的办法来 require 插件,就是使用 gulp-load-plugins 这个库。有了它之后,我们就不必为每个插件添加一行 require 语句了。这个小工具可以自动加载 package.json 中所有以 gulp- 开头的依赖项(译注:当然,除了它自己以外),并返回一个对象,对象的各个属性就对应了各项依赖。它还具有懒加载的特性——各个插件只有在被用到时才会真正加载,而没有用到的插件是不会被加载的。

var pi = require('gulp-load-plugins')();

Reference plugins from within task definitions using pi.name .

在拿到 pi 这个对象后,我们在定义任务时就可以使用 pi.name 来引用某个名为 gulp-name 的插件。

gulp Methods

Gulp 的 API

(译注:以下 API 均为以 Gulp 4.0 版本为准。)

The JavaScript methods provided by gulp are defined in two JavaScript classes, Gulp and Undertaker .

Gulp 所提供的 JS API 是由 GulpUndertaker 这两个类所提供的。

The Gulp class provides the src , dest , and watch methods. It is defined in the index.js file at the top of the gulp GitHub repo (currently https://github.com/gulpjs/gulp/tree/4.0 ). This class inherits from the Undertaker class.

Gulp 这个类提供了 srcdestwatch 方法。这个类的源码位于 Gulp 项目根目录的 index.js 文件中(对 Gulp 4 来说,项目根目录就是 https://github.com/gulpjs/gulp/tree/4.0 )。这个类继承自 Undertaker 这个类。

The Undertaker class provides the task , series , parallel , get , set , tree , and registry methods. It is defined in the index.js file at the top of the Undertaker GitHub repo ( https://github.com/phated/undertaker ). The Undertaker class inherits from the Node core EventEmitter class ( https://nodejs.org/api/events.html ).

Undertaker 这个类提供了 taskseriesparallelgetsettreeregistry 方法。这个类的源码位于 Undertaker 项目根目录的 index.js 文件中(根目录在这里: https://github.com/phated/undertaker )。Undertaker 类继承自 Node 的核心类 EventEmitter ( https://nodejs.org/api/events.html )。

[译] Gulp 4 入门指南

It is not necessary to know about this inheritance hierarchy in order to use gulp, but it is important to understand how to use some of these methods.

如果只是为了使用 Gulp,不一定要了解这些继承关系;但理解这些关系将有助于我们理解其中某些方法的使用。

Another important npm module used by gulp is vinyl-fs . This uses Vinyl objects to hold metadata that describes a file. Vinyl adapters provide access to the content of Vinyl objects through streams. "The src stream produces file objects, and the dest stream consumes file objects." For more detail, see https://github.com/wearefractal/vinyl-fs , https://github.com/wearefractal/vinyl , and https://medium.com/@contrahacks/gulp-3828e8126466 .

Gulp 还用到了另一个重要的 npm 模块,就是 vinyl-fs 。这个模块使用 Vinyl 对象来存储元数据,这些元数据用于描述文件。Vinyl 适配器使得我们可以以 “流” 的方式来读写 Vinyl 对象的内容。“源文件流负责生产文件对象,目标文件流负责消费文件对象。” 更具体的信息可以参考 https://github.com/wearefractal/vinyl-fs 、 https://github.com/wearefractal/vinyl 和 https://medium.com/@contrahacks/gulp-3828e8126466 。

A Gulp object is obtained by the following line:

下面这行代码可以获取 Gulp 对象:

var gulp = require('gulp');

This object supports all the methods in the Gulp , Undertaker , and EventEmitter classes.

这个对象支持 Gulp 类、 Undertaker 类和 EventEmitter 类所定义的所有方法。

Several of the methods take a glob pattern argument. This may be a string or an array of strings. The strings may contain wildcard characters. The underlying implementation is provided by the npm module node-glob . For details on the syntax, see "Glob Primer" at https://github.com/isaacs/node-glob . The basics are:

在介绍具体的方法之前,我们需要简单理解一下 glob(文件匹配符)。Gulp 的很多方法都接受 glob 作为参数,这个参数可以是一个字符串,或是一个字符串数组。字符串中可以包含我们比较熟悉的通配符。Glob 的底层实现是由 npm 模块 node-glob 来提供的。更详细的语法请自行查阅《Glob Primer》这篇文档。其基本语法包括:

  • ? means one of any character
  • * means zero or more of any character
  • ** in a path portion, means any number of directories
  • ? 代表任意一个字符。
  • * 代表 0 个或多个任意字符。
  • ** 作为路径的一部分,它表示任意数量层级的目录。

src 方法

The src method produces a stream of Vinyl objects that may be piped to plugins. It takes a glob pattern and an options object. The glob pattern specifies the input files to be processed. Options are passed to the glob module. For details on options, see https://github.com/gulpjs/gulp/blob/master/docs/API.md#gulpsrcglobs-options and https://github.com/isaacs/node-glob . Typically no options are passed and that argument may be omitted.

src 方法会提供一个由 Vinyl 对象组成的流,这些流将通过管道传递(pipe)给插件处理。这个方法接受一个 glob 和一个选项对象作为参数。Glob 用于指定输入文件,以备处理;而选项参数则用于传递给 node-glob 模块。关于这个选项参数的详细信息请参见 https://github.com/gulpjs/gulp/blob/master/docs/API.md#gulpsrcglobs-options 和 https://github.com/isaacs/node-glob 。一般来说我们不需要指定特别的选项,而且这个参数也是可以省略的。

dest 方法

The dest method accepts piped data and outputs it to files. All data piped to it is re-emitted, which allows dest to be used more than once in order to write to multiple files. It takes an output path and an options object. The output path specifies an output file or directory. For details on options, see https://github.com/gulpjs/gulp/blob/master/docs/API.md#gulpdestpath-options . Typically no options are passed and that argument may be omitted.

dest 方法接受管道传递过来的流,并将流数据输出至文件。所有传递给它的数据都会被重新转发,这允许我们多次调用 dest 方法来将数据输出至多个位置。他接受一个目标路径和一个选项对象作为参数。目标路径用于指定了输出文件的路径。而关于选项参数的详细信息请参见 https://github.com/gulpjs/gulp/blob/master/docs/API.md#gulpdestpath-options 。一般来说我们不需要指定特别的选项,而且这个参数也是可以省略的。

watch 方法

The watch method watches files and calls a function when they are modified. It takes a glob pattern, an options object, and a function. The glob pattern specifies the files to be watched. This is actually implemented by the npm module gaze . For details on options, see the options for the gaze.Gaze constructor at https://github.com/shama/gaze . Typically no options are passed and that argument may be omitted.

watch 方法可以监听文件,当文件被改动时可以运行指定的任务(调用某个函数)。它接受一个 glob、一个选项对象和一个函数作为参数。Glob 用于指定哪些文件需要被监听。这个方法实际上是通过一个名为 gaze 的 npm 模块来实现的。关于那个选项参数,请在 https://github.com/shama/gaze 查阅 gaze.Gaze 构造函数的选项。一般来说我们不需要指定特别的选项,而且这个参数也是可以省略的。(译注:后来 Gulp 4 在底层把 gaze 换成了 chokidar 。)

task 方法

The task method defines a task. It takes a string name and a function. When the task is run, the function is run. The function may be anonymous, or the name of a function defined elsewhere. If the function is omitted, it acts as a getter for the function previously associated with the task name.

task 方法用来定义任务。它接受一个字符串(任务名)和一个函数作为参数。当运行某个任务时,该任务对应的函数就将被调用。这个函数可以是匿名函数,也可以是在别处已经声明过的函数。如果在调用 task 方法时没有传入函数,则它的作用相当于一个 getter,返回先前为某个任务名定义的任务函数。

series 方法

The series method returns a function that, when called, executes specified tasks in series. It takes any number of arguments that may be any combination of string task names and functions. Since this method returns a function, calls may be nested.

series 方法会返回一个函数。这个函数被调用时,将会以串行的方式运行指定的任务。它接受任意数量的参数,参数可以是任务名,也可以是函数。由于它返回一个函数,因此它在调用时通常是作为参数传递给其他方法(比如 task 方法)的。

parallel 方法

The parallel method returns a function that, when called, executes specified tasks in parallel. It takes any number of arguments that may be any combination of string task names and functions. Since this method returns a function, calls may be nested.

parallel 方法会返回一个函数。这个函数被调用时,将会以并行的方式运行指定的任务。它接受任意数量的参数,参数可以是任务名,也可以是函数。由于它返回一个函数,因此它在调用时通常是作为参数传递给其他方法(比如 task 方法)的。

The remaining methods in the Undertaker class described below are not typically used directly in gulpfile.js files.

接下来我们来看一下 Undertaker 类所定义的方法,这些方法通常并不会在 gulpfile.js 中直接使用。

The get method returns the function associated with a given task name. It takes a string task name.

get 方法接受一个任务名(字符串)作为参数,返回与该任务名对应的函数。

The set method sets or changes the function associated with a given task name. It takes a string task name and a function. If the task is already defined, its function is replaced.

set 方法用于设置(或修改)某个给定任务名所对应的函数。它接受一个任务名(字符串)和一个函数作为参数。如果某个任务名已经定义,那么原先设置的函数将被替换掉。

The tree method returns an array of defined task name strings. It takes an options object. If the deep option is set to true, it returns an array of objects that provide task names and their dependencies. This method is used by the gulp command-line options --tasks and --tasks-simple .

tree 方法返回一个数组,该数组由已定义的任务名字符串所组成。它接受一个选项对象作为参数。如果 deep 选项设置为 true ,那么返回的数组将由多个对象组成,这些对象展现了每项任务的依赖关系。Gulp 的命令行选项 --tasks--tasks-simple 其实就用到了这个方法。

The registry method gets or sets a map of task names to functions.

registry 方法可以获取(或设置)任务名和任务函数之间的映射关系。

Defining gulp Tasks

定义 Gulp 任务

Since gulp runs on top of Node.js, gulpfile.js may contain any code that Node.js can process. This means all Node.js core modules and all npm modules may be used.

Gulp 是运行在 Node.js 上的,因此 gulpfile.js 中可以包含任何 Node.js 可以处理的代码。这意味着所有的 Node.js 核心模块和 npm 模块都可以使用。

Here is the simplest example of a gulp task definition:

如下所示,定义一个 Gulp 任务其实就是这么简单:

var gulp = require('gulp');  gulp.task('hello', function () {     console.log('Hello, World!'); });

Here is the same gulp task implemented using ES6.

而这个任务如果用 ES6 来写,会是这样的:

let gulp = require('gulp');  gulp.task('hello', () => console.log('Hello, World!'));

To run this enter

如果要运行这个任务,执行以下命令就可以了:

gulp hello 

Typically gulp task definitions take one of three forms:

定义 Gulp 任务通常有以下三种形式:

gulp.task(name, function () { ... });  gulp.task(name, gulp.series(...));  gulp.task(name, gulp.parallel(...));

A task often reads specific files, performs one or more actions or transformations on the contents, and produces one or more output files. The general form of such a task is shown below.

一个 Gulp 任务往往需要读取特定的文件,对文件内容采取一个或多个的操作,然后生成一个或多个输出文件。这类任务通常看起来会是下面这个样子:

gulp.task(name, function () {     return gulp.src(srcPath).         pipe(somePluginFn()).         pipe(anotherPluginFn()).         pipe(gulp.dest(destPath)); });

In ES6 this could be written as follows:

在 ES6 环境下,我们也可以这么写:

gulp.task(name, () =>     gulp.src(srcPath).         pipe(somePluginFn()).         pipe(anotherPluginFn()).         pipe(gulp.dest(destPath)));

Serving Files From gulp

通过 Gulp 提供静态资源服务

There are several npm modules that serve static files using HTTP. One popular option is connect at https://github.com/senchalabs/connect . The commands to install the required modules follow:

有许多 npm 模块可以通过 HTTP 协议来向外提供静态文件服务。一个常见的选择是 connect (该项目位于 https://github.com/senchalabs/connect )。以下命令可以安装必要的模块:

npm install connect --save npm install serve-static -save

Below is an example of a gulp task that serves static files from the top project directory.

下面这个 Gulp 任务将在项目的顶层目录向外提供静态文件服务:

var connect = require('connect'); var http = require('http'); // a Node.js core module var serveStatic = require('serveStatic'); gulp.task('connect', function () {     var app = connect();     app.use(serveStatic(__dirname));     var port = 8080;     http.createServer(app).listen(port); });

__dirname is a Node.js variable that holds the path to the current directory. If there is an index.html file in that directory, it can be viewed by browsing http://localhost:8080.

__dirname 是一个 Node.js 变量,它的值就是当前路径。如果在当前目录下有一个 index.html 文件,那么我们在浏览器地址栏键入 http://localhost:8080 应该就可以访问到它。

To run this enter gulp connect

如果要运行这个任务,执行 gulp connect 即可。

Watching For File Changes

监听文件的变更

gulp can be configured to run specified tasks when new files are created or existing files are modified. If gulpfile.js is modified, gulp must be restarted for the changes to take effect.

Gulp 可以监听文件的改变或新文件的创建。但如果 gulpfile.js 文件本身被改动了,那只有重启 Gulp 才能让修改过的 gulpfile.js 生效。

Below is an example of a gulp task that watches for changes to LESS files. When changes are detected, it runs the less and csslint tasks which we'll see later.

下面这个 Gulp 任务用于监听 LESS 文件的变动。一旦侦测到了文件变更,Gulp 就会运行我们预先定义好的 lesscsslint 任务。

gulp.task('watch', function () {     gulp.watch('styles/*.less', gulp.series('less', 'csslint')); })

Live Reload

实时刷新(Live Reload)

gulp can trigger a web browser to reload, which is useful after changes to HTML, CSS, JavaScript, and other files loaded by the browser. There are several gulp plugins that support this. A popular choice is gulp-livereload , at https://github.com/vohof/gulp-livereload . This works best with Chrome and requires installing the livereload Chrome extension. To install this Chrome extension, browse https://chrome.google.com/webstore/category/apps and enter "livereload" in the search field.

Gulp 还可以让浏览器自动刷新。当我们在修改 HTML、CSS、JavaScript 等等由浏览器加载的文件时,这个功能尤为实用。有不少 Gulp 插件支持这个功能。最常见的选择是 gulp-livereload (该项目位于 https://github.com/vohof/gulp-livereload )。这个插件与 Chrome 浏览器的配合最为顺滑,不过你需要提先装好 livereload 的 Chrome 扩展。我们在 https://chrome.google.com/webstore/category/apps 这个页面搜索 “livereload” 就可以找到这个扩展了。

To use this plugin, follow these steps:

请按照以下步骤来配置这个插件:

  1. Install the gulp-livereload plugin.
  2. Add the following script tag to the main HTML file: <script src="http://localhost:35729/liverload.js"</script>
  3. Call livereload.listen() in the watch task.
  4. Call livereload() after every file change that should trigger a reload.
  1. 安装 gulp-livereload 插件。
  2. 在 HTML 入口文件中添加这个 script 标签: <script src="http://localhost:35729/liverload.js"></script>
  3. watch 任务内调用 livereload.listen() 函数。
  4. 在文件有改动且需要刷新浏览器时,调用 livereload() 函数。

The example gulpfile.js below demonstrates the last two of these steps. It defines a series of gulp tasks that are useful for typical web applications.

下面有一个 gulpfile.js 文件的示例,它展示了上述步骤的最后两步。这个文件定义了多个 Gulp 任务,这些任务在日常的 Web 开发中十分实用。

Example gulpfile.js

gulpfile.js 示例

var connect = require('connect'); var del = require('del'); var gulp = require('gulp'); var http = require('http'); var pi = require('gulp-load-plugins')(); var serveStatic = require('serve-static');  var paths = {     build: 'build',     css: 'build/**/*.css',     html: ['index.html', 'src/**/*.html'],     js: ['src/**/*.js'],     jsPlusTests: ['src/**/*.js', 'test/**/*.js'],     less: 'src/**/*.less',     test: 'build/**/*-test.js' };  // This just demonstrates the simplest possible task. // 这是一个最简单的 Gulp 任务。 gulp.task('hello', function () {     console.log('Hello, World!')); });  // This deletes all generated files. // In tasks that do something asynchronously, the function // passed to task should take a callback function and // invoke it when the asynchronous action completes. // This is how gulp knows when the task has completed. // 这个任务会删除所有构建生成的文件。 // 在定义异步任务时,任务函数应该接受一个回调函数, // 任务函数在运行完毕后需要调一下这个回调函数, // 这样 Gulp 才知道这个任务已经结束了。 gulp.task('clean', function (cb) {     del(paths.build, cb); });  // This starts a simple HTTP file server. // 这个任务会启动一个简单的 HTTP 文件服务器。 gulp.task('connect', function () {     var app = connect();     app.use(serveStatic(__dirname));     http.createServer(app).listen(1919); });  // This validates all CSS files. // In this example, the CSS files are generated from LESS files. // 这个任务会校验所有的 CSS 文件。 // 在这个例子中,CSS 文件都是由 LESS 文件编译生成的。 gulp.task('csslint', function () {     return gulp.src(paths.css).         pipe(pi.csslint({ids: false})).         pipe(pi.csslint.reporter()); });  // This validates JavaScript files using ESLint. // 这个任务会调用 ESLint 来校验 JavaScript 文件。 gulp.task('eslint', function () {     return gulp.src(paths.jsPlusTests).         pipe(pi.changed(paths.build)).         pipe(pi.eslint({             envs: ['browser', 'ES6', 'node'],             rules: {                 curly: [2, 'multi-line'],                 indent: [2, 2]             }         })).         pipe(pi.eslint.format()); });  // This is used by the "watch" task to // reload the browser when an HTML file is modified. // 这个任务是用来被 "watch" 任务触发的, // 从而实现当 HTML 被修改时自动刷新浏览器的效果。 gulp.task('html', function () {     return gulp.src(paths.html).         pipe(pi.livereload()); });  // This validates JavaScript files using JSHint. // 这个任务会调用 JSHint 来校验 JavaScript 文件。 gulp.task('jshint', function () {     return gulp.src(paths.jsPlusTests).         pipe(pi.changed(paths.build)).         pipe(pi.jshint()).         pipe(pi.jshint.reporter('default')); });  // This compiles LESS files to CSS files. // 这个任务会把 LESS 文件编译成 CSS 文件。 gulp.task('less', function () {     return gulp.src(paths.less).         pipe(pi.changed(paths.build)).         pipe(pi.less()).         pipe(gulp.dest(paths.build)).         pipe(pi.livereload()); });  // This compiles ES6 JavaScript files to ES5 JavaScript files. // "transpile" is a term used to describe compiling // one syntax to a different version of itself. // Compiling ES6 code to ES5 fits this description. // 这个任务会把 ES6 的 JavaScript 文件编译成 ES5 的 JavaScript 文件。 // "transpile"(转译)这个术语表示把一种语法编译为这种语法的另一个版本。 // 把 ES6 代码编译成 ES5 正好符合这种情况。 gulp.task('transpile-dev', function () {     return gulp.src(paths.jsPlusTests).         pipe(pi.changed(paths.build)).         pipe(pi.sourcemaps.init()).         pipe(pi.babel()).         pipe(pi.sourcemaps.write('.')).         pipe(gulp.dest(paths.build)).         pipe(pi.livereload()); });  // This does the same as the previous task, but also // concatenates and minimizes the resulting JavaScript files. // 这个任务与上个任务的功能基本一致, // 但这个任务还会把编译产生的 JavaScript 文件合并、压缩起来。 gulp.task('transpile-prod', function () {     return gulp.src(paths.js).         pipe(pi.sourcemaps.init()).         pipe(pi.babel()).         pipe(pi.concat('all.js')).         pipe(pi.uglify()).         pipe(pi.sourcemaps.write('.')).         pipe(gulp.dest(paths.build)); });  // This is not meant to be used directly. // Use the "test" task instead. // 这个任务并不是用来直接运行的。 // 我们应该使用 "test" 这个任务来代替。 gulp.task('jasmine', function () {     return gulp.src(paths.test).         pipe(pi.plumber()).         pipe(pi.jasmine()); });  gulp.task('test', gulp.series('transpile-dev', 'jasmine'));  // This watches HTML, LESS, and JavaScript files for changes // and processes them when they do. // It also reloads the web browser. // 这个任务会监听 HTML、LESS 和 JavaScript 文件的变动, // 并在它们有变动的时候处理它们。 // 这个任务也会自动刷新浏览器。 gulp.task('watch', function () {     pi.livereload.listen();     gulp.watch(paths.html, gulp.series('html'));     gulp.watch(paths.less, gulp.series('less', 'csslint'));     gulp.watch(paths.jsPlusTests,         gulp.series('eslint', 'jshint', 'transpile-dev')); });  // This compiles LESS and ES6 JavaScript files in parallel. // 这个任务会以并行的方式编译 LESS 和 ES6 JavaScript 文件。 gulp.task('build-dev', gulp.parallel('less', 'transpile-dev'));  // This does the same as the previous tasks, but also // concatenates and minimizes the resulting JavaScript files. // 这个任务与上个任务的功能基本一致, // 但这个任务还会把编译产生的 JavaScript 文件合并、压缩起来。 gulp.task('build-prod', gulp.parallel('less', 'transpile-prod'));  // This is used when gulp is run without specifying a task. // It runs the "build-dev" task and then // starts the "connect" and "watch" tasks in parallel. // This is the most commonly used task during development. // 如果在执行 `gulp` 命令时没有指定任务名,那么这个默认任务就会被调用。 // 它会先运行 "build-dev" 任务, // 然后以并行的方式启动 "connect" 和 "watch" 任务。 // 这个任务在整个开发期间是最为常用的。 gulp.task('default',     gulp.series('build-dev', gulp.parallel('connect', 'watch')));

Typical Usage

典型应用

The most common usage of the gulpfile.js above includes the following steps:

上面这个 gulpfile.js 文件的使用方法是这样的:

  • Open a terminal, cd to the project directory, and run gulp in it. This starts the local HTTP server and begins watching for file changes.
  • Keep this terminal visible so new output can be observed.
  • Browse the app in a web browser that works with livereload.
  • Use any editor or IDE to make changes to the client-side files of the app.
  • Watch the terminal for errors reported by gulp tasks that are triggered by watches.
  • Watch the browser for updates that result from livereload.
  • Repeat all day long.
  • 打开终端,进入这个项目所在的目录,执行 gulp 命令。它将启动本地的 HTTP 服务,并监听文件的变动。
  • 记得保持终端窗口不被遮挡,这样你才能观察到最新的输出。
  • 在配置好 livereload 的浏览器中打开这个项目。
  • 使用编辑器或 IDE 来编辑代码(比如 HTML、CSS、JS 文件等)。
  • 在终端中观察监听任务所触发的其它任务是否产生了错误。
  • 在浏览器中观察 livereload 刷新的结果是否正确。
  • 不断重复下去。

Caveat

后续

One concern is how long it is taking for gulp 4 to replace gulp 3 as the stable version. On January 29, 2015, the main contributor tweeted "#gulpjs 4 was supposed to come out on the 31st but i got the flu and am down for a few days, sorry folks". On April 28, 2015, I replied, "Any update on when gulp 4 might be released? I know we can use it now, but I'm looking for an official release." The reply was a simple "nope". On May 19, 2015, the main contributor tweeted, "I'm pleased to announce our 10m in funding for@gulpjs as part of a Series B." Hopefully that is an indication that progress on a new release will soon resume.

我们都很关心,Gulp 4 何时才能代替 Gulp 3 成为最新的稳定版本。在 2015 年 1 月 29 日,gulp4 的主要开发者发推说 “gulp4 本来会在 31 号问世,但最近我得了流感,估计要匿一阵子了,所以抱歉了伙计们”。时间一晃到了 2015 年 4 月 28 日,在经历了三个月的等待之后,我又问了他一次 “gulp4 的有何进展?虽然它现在已经能用了,但我们还是希望能有一个正式版出来”。遗憾的是他只回了我一句 “没有”。后来在 2015 年 5 月 19 日,Gulp 的主要开发者发推公布他们在 B 轮融资中拿到了一千万。但愿这是 Gulp 4 即将到来的好预兆。

(译注:截至本文发稿时,已经是 2016 年的夏天,Gulp 4 仍然没有发布正式版。不过实际上,我们已经在生产环境提前享受 Gulp 4 快一年了。)

Summary

总结

gulp is a popular and powerful tool for automating web development tasks. It seems to be overtaking Grunt in popularity. If you are not currently using gulp, give it a shot!

Gulp 是一款为 Web 开发服务的自动化工具,它十分流行,而且功能强大。看起来它的风头已经明显盖过 Grunt 了。如果你还没有用过 Gulp,赶快试试吧!

(译注:本文最初由 Leooonard 翻译,随后由 CSS魔法 整理补充而成。)

References

参考链接

  • [1] Chrome web store apps - https://chrome.google.com/webstore/category/apps
  • [2] Connect module - https://github.com/senchalabs/connect
  • [3] gaze module - https://github.com/shama/gaze
  • [4] gulp 4 GitHub repo - https://github.com/gulpjs/gulp/tree/4.0
  • [5] gulp dest options - https://github.com/gulpjs/gulp/blob/master/docs/API.md#gulpdestpath-options
  • [6] gulp main website - http://gulpjs.com
  • [7] gulp on Twitter -@gulpjs
  • [8] gulp plugins - http://gulpjs.com/plugins
  • [9] gulp src options - https://github.com/gulpjs/gulp/blob/master/docs/API.md#gulpsrcglobs-options
  • [10] gulp-livereload module - https://github.com/vohof/gulp-livereload
  • [11] Jasmine - http://jasmine.github.io/
  • [12] JSCS - http://jscs.info/
  • [13] my ES6 slides - http://www.ociweb.com/download_file/219
  • [14] Node.js core Events API - https://nodejs.org/api/events.html
  • [15] node-glob module - https://github.com/isaacs/node-glob
  • [16] undertaker GitHub repo - https://github.com/phated/undertaker
  • [17] vinyl module - https://github.com/wearefractal/vinyl
  • [18] vinyl overview - https://medium.com/@contrahacks/gulp-3828e8126466
  • [19] vinyl-fs module - https://github.com/wearefractal/vinyl-fs

本文在 “CSS魔法” 微信公众号首发,扫码立即订阅:

[译] Gulp 4 入门指南

© Creative Commons BY-NC-ND 4.0   | 我要订阅 |   我要捐助

原文  https://github.com/cssmagic/blog/issues/62
正文到此结束
Loading...