使用Gulp作为Web开发服务器

构建工具Gulp.js最近正在变得越来越流行。我们可以用它做很多事,比如合并Javascript文件或者压缩图片。本文将向你介绍如何使用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文件中的代码类似下面这样:

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命令来安装依赖项。

(四)添加实时刷新(livereload)支持

设置基本的web服务器非常简单,接下来我们要继续完善它,首先要实现实时刷新。需要做两件事:

  • 让web服务器带实时刷新支持启动

  • 告诉组件什么时候应该自动刷新

第一步很简单,只要给connect.server()方法传入一个参数即可:

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的内容类似下面的实例,你可以复制粘贴到你的项目中:

// 定义依赖项
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来访问,你可以这样做:

connect.server({
  port: 80,
  host: 'gulp.dev'
});

为了能够通过gulp.dev域名以及默认的80端口来启动和访问,你需要:

在hosts文件中配置gulp.dev指向本机IP地址

没有其它程序占用80端口(比如Apache,Nginx,QQ旋风,腾讯视频,迅雷等……)

root或者Administrator权限(由于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文件。这个示例的源文件在前面已经提到过的这个githubrepo中的03-livereload-refactored文件夹中。重构之后的gruntfile.js参见下面的代码,我们随后要一步一步地讲解这些代码:

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提供的只是一种更加简单、优雅的实现方式。

参考资料:

本文标题:使用Gulp作为Web开发服务器

本文链接:http://yedward.net/?id=404

本文版权归作者所有,欢迎转载,转载请以文字链接的形式注明文章出处。

相关文章