构建工具 Gulp.js 最近正在变得越来越流行。我们可以用它做很多事,比如合并 Javascript 文件或者压缩图片。如果你还不了解 Gulp.js, 可以看一下《前端构建工具 Gulp.js 上手实例》。
本文将向你介绍如何使用 Gulp.js 来作为本地 Web 服务器,而且是内置 livereload 支持的哦。
假设我们需要开发一个单页的 web 应用。应用入口很简单,就是 index.html 文件。我们的目的是通过浏览器,以及 localhost 域名访问这个文件(某些情况下,通过 file:// 协议访问不能满足需求)。在此之前,或许你会在本机安装一个 Apache 或者 Nginx 服务器。如果只是为了通过 HTTP 协议访问一些静态文件,现在以上这些都没必要了。
现在,由 Javascript 来实现的解决方案几乎无处不在,甚至是作为 web 服务器(都要感谢 Node.js啊)。最流行的是一个叫做 Connect 的开源组件。我们将通过 Gulp.js 的一个插件 gulp-connect 来调用它(与 grunt-contrib-connect 一样,不过 Gulp.js 更容易)。
在接下来的章节中,我们要为我们的单页应用配置一个本地 web 服务器,我假设你已经有了其它基础配置,比如 gulpfile.js 文件。
首先,用下面的命令来安装 Connect 插件:
npm
install
--save-dev gulp-connect
|
提示:npm install --save-dev
可以简化为 npm i -D
.
接下来,为 web 服务器定义一个任务。gulpfile.js 文件中的代码类似下面这样:
1
2
3
4
5
6
7
8
|
var
gulp = require(
'gulp'
),
connect = require(
'gulp-connect'
);
gulp.task(
'webserver'
,
function
() {
connect.server();
});
gulp.task(
'default'
, [
'webserver'
]);
|
这样就定义好了,只要在终端/命令行中执行 gulp
, 就可以启动 web 服务器。然后可以在浏览器中打开localhost:8080, 就能看到 index.html 的内容。这个简单的 web 服务器以当前 gulpfile.js 文件所在的文件夹作为网站根目录。服务器将一直运行,监听 localhost:8080, 要停止服务器,可以回到终端/命令行下按 Ctrl + C。(用过 Node.js, Grunt 或者 PHP 内置服务器的话,你一定对此非常熟悉。)
这个示例,以及接下来的所有示例的源代码可以在Github下载。每个例子的代码在一个单独的文件夹下,你需要在对应的文件夹下执行 npm install
命令来安装依赖项。
设置基本的 web 服务器非常简单,接下来我们要继续完善它,首先要实现实时刷新。需要做两件事:
第一步很简单,只要给 connect.server()
方法传入一个参数即可:
1
2
3
4
5
|
gulp.task(
'webserver'
,
function
() {
connect.server({
livereload:
true
});
});
|
第二步取决于你的项目的情况。在这个示例中(从 Github 下载示例代码,本例使用 02-livereload ),我们需要 Gulp.js 自动把 LESS 文件编译成 CSS 样式,并将其注入到浏览器。
先来分解一下这个例子:我们需要一个“监控器( watcher )”,它负责检查 LESS 文件是否发生变化。如果发生变化,它会通知 LESS 编译器把 LESS 文件编译为 CSS 文件,然后新的 CSS 文件通过实时刷新注入到页面。
为了编译 LESS 文件,需要用到 gulp-less 插件。你可以通过运行 npm i -D gulp-less
来安装 gulp-less 并在 gulpfile.js 文件中添加这个依赖项。watcher 不用额外插件, Gulp.js 已经自带了。
我们的文件结构如以下所示:
.
├── node_modules
│ └── ...
├── styles
│ └── main.less
├── gulpfile.js
├── index.html
└── package.json
|
在 watch 任务中,Gulp.js 监听 styles 目录下所有的 *.less 文件,一旦它们发生变化,就触发 less 任务。本例中, main.less 是 LESS 的入口文件。每次编译完成后,结果会自动注入到浏览器。gulpfile.js 的内容类似下面的实例,你可以复制粘贴到你的项目中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
// 定义依赖项
var
gulp = require(
'gulp'
),
connect = require(
'gulp-connect'
),
less = require(
'gulp-less'
);
// 定义 webserver 任务
gulp.task(
'webserver'
,
function
() {
connect.server({
livereload:
true
});
});
// 定义 less 任务
gulp.task(
'less'
,
function
() {
gulp.src(
'styles/main.less'
)
.pipe(less())
.pipe(gulp.dest(
'styles'
))
.pipe(connect.reload());
});
// 定义 watch 任务
gulp.task(
'watch'
,
function
() {
gulp.watch(
'styles/*.less'
, [
'less'
]);
})
// 定义默认任务
gulp.task(
'default'
, [
'less'
,
'webserver'
,
'watch'
]);
|
保存之后,回到终端/命令行,Ctrl+C 停止服务器(如果它还处于运行状态),然后再次执行 gulp
启动服务器。打开浏览器,打开 localhost:8080. 现在我们可以去 style 目录下的 LESS 文件做一点修改,并保存。你会看到 LESS 的修改被实时编译并自动同步生效到浏览器中的页面上。特别要说明的是,你不需要任何浏览器插件或者扩展。
请记住:前面的 gulpfile.js 只是一个为了演示如何使用 gulp.js 作为带有实时刷新支持的 web 服务器的精简示例。在实际项目中,建议配合其它的一些插件一起使用。你可以尝试着重新排列任务的顺序,或者尝试一下非内置的 gulp-watch 插件,这个插件可以让你只处理发生变化的文件。如果你的项目有大量的代码/文件,这个功能非常有用。在接下来的例子中,我会再演示另外的一种任务结构。
gulp-connect 插件支持很多配置选项,前面我们只用到了 livereload 这一个。如果你需要修改 web 服务器监听的端口或者主机名,比如想通过 http://gulp.dev 来访问,你可以这样做:
1
2
3
4
|
connect.server({
port: 80,
host:
'gulp.dev'
});
|
为了能够通过 gulp.dev 域名以及默认的 80 端口来启动和访问,你需要:
你还可以继续深入探索 connect 插件的其它用法,比如同时启动多个 web 服务器。有时候这很必要,比如你需要运行一个开发服务器,同时执行集成测试等。
gulp-connect 也提供了一些额外的特性,比如用多个文件夹作为单个服务器的根目录。例如,你使用 CoffeeScript, 希望把编译的 Javascript 文件暂存在某个临时目录中,你可以把原本的项目根目录与该临时文件夹同时作为网站根目录。具体的实例可以在这里找到。
在前面的示例中,我们配置了一个“小巧玲珑”的 gulpfile.js 来完成把 LESS 文件编译成 CSS 并且自动注入浏览器的任务。它能用,但是还可以优化。由于我们把编译和实时刷新两个任务混合成了一个,有可能会导致问题。所以,接下来我们要把它们拆成单独的任务,然后只监控生成后的文件。为了达到这个目的,就需要用到刚才提到的 gulp-watch 插件。
既然要重构,那就再多做一点,我们顺便把 CoffeeScript 编译也添加进去。这样,新的目录结构会更加整洁。首先通过 npm 来安装需要的新插件:
npm
install
--save-dev gulp-
watch
gulp-coffee
|
然后在 gruntfile.js 中加载。接下来的步骤,我假设你已经在 scripts 目录下创建了一些 .coffee 文件。这个示例的源文件在前面已经提到过的这个 github repo 中的 03-livereload-refactored 文件夹中。重构之后的 gruntfile.js 参见下面的代码,我们随后要一步一步地讲解这些代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
var
gulp = require(
'gulp'
),
connect = require(
'gulp-connect'
),
watch = require(
'gulp-watch'
),
less = require(
'gulp-less'
),
coffee = require(
'gulp-coffee'
);
gulp.task(
'webserver'
,
function
() {
connect.server({
livereload:
true
,
root: [
'.'
,
'.tmp'
]
});
});
gulp.task(
'livereload'
,
function
() {
gulp.src([
'.tmp/styles/*.css'
,
'.tmp/scripts/*.js'
])
.pipe(watch())
.pipe(connect.reload());
});
gulp.task(
'less'
,
function
() {
gulp.src(
'styles/main.less'
)
.pipe(less())
.pipe(gulp.dest(
'.tmp/styles'
));
});
gulp.task(
'coffee'
,
function
() {
gulp.src(
'scripts/*.coffee'
)
.pipe(coffee())
.pipe(gulp.dest(
'.tmp/scripts'
));
});
gulp.task(
'watch'
,
function
() {
gulp.watch(
'styles/*.less'
, [
'less'
]);
gulp.watch(
'scripts/*.coffee'
, [
'coffee'
]);
})
gulp.task(
'default'
, [
'less'
,
'coffee'
,
'webserver'
,
'livereload'
,
'watch'
]);
|
最大的变化是加入了单独的 livereload 任务。这个任务只负责监控(通过 gulp-watch 插件)编译后的文件的变化,并在浏览器中刷新它们。gulp-watch 自定义的 watch()
函数让我们可以只刷新变化的文件,而内置的 gulp.watch()
通常会刷新所有文件。
由于加入了一个额外的独立监控任务,编译步骤后面就不再需要 .pipe(connect.reload())
命令。这样我们就把任务根据它们的不同职能进行了划分,这是软件开发中经过实践验证的设计模式。
此外还应该注意到,编译后的文件不再保存在它们各自原先的源文件夹中,而是存储在 .tmp 临时文件夹中,这个文件夹的内容只有编译生成的文件,这样原来的样式和脚本文件夹就不再被生成的文件污染。这个文件夹还应该被排除在版本管理系统之外,比如 svn-ignore 属性和 .gitignore 文件。但是为了在开发过程中能够进行测试,需要把 .tmp 也作为网站根目录,在 webserver 任务中,完成这个工作的任务是下面这行代码:
root: [
'.'
,
'.tmp'
]
|
经过重构之后,完成的工作虽然没有什么不同,但是相比之前,就变得更加清晰明了,而且便于扩展。
通过本文,你了解了如何 使用 Gulp.js 来作为 web 服务器。
你可以把这个与其它技术一起使用,比如测试,或者创建单页应用程序。需要提醒的是,这个 web 服务器只适合作为本机开发用途。生产环境你还是需要使用性能更好,更可靠的解决方案,比如 Nginx 或者 CDN.
此外,以上所有的功能,在 Grunt 或者其它类似的项目中也可以实现。相比较而言,Gulp.js 提供的只是一种更加简单、优雅的实现方式。