之前做过一个项目,是一种无线设备,由于设备本身的内存容量比较小,为了节约内存使用,选择了gulp这种工具,可以将前端的代码进行打包发布,并能在项目中正常运行,较之之前的代码量有了量的突破,还是不错的。后来接触的项目几乎无一例外的都是用到打包这种工具。我们知道在html中引入js才能让我们的事件起到效果,那么使用gulp这种工具的好处就在于,编译或者压缩之后的js文件完全可以替代之前传统意义上的js文件,不管你目录怎样?他都能编译后被浏览器识别,被程序识别。
当然这么做的唯一坏处就是不太容易debug,在开发环境中是很容易debug的,因为在开发环境中随时可以替换自己的代码去debug问题,当然各有利弊。在测试环境中我们还是可以保留源码,通过双引入(引入压缩js文件和非压缩文件),来测试复现定位BUG。
工欲善其事必先利其器,想要使用gulp组件打包,需要安装gulp。安装gulp,就不得不讲到另外一个----Node.js.它可以提供世界上最全的开源库生态。
https://nodejs.org/zh-cn/
命令执行没有问题,就算安装好了。接着我们需要通过node通过的npm命令来执行一系列的依赖js包安装。
切到工作目录下执行npm install -g
将会执行一段时间,他其实是在为你下载依赖库文件,生成一个叫node_modules的文件夹,这个文件夹下的便
时所有的依赖包了。
往下拉,我们能够看到打包工具所对应的gulp一系列的包文件
到目前为止,我们就是使用nodejs安装好我们所需要的打包工具gulp,下面我们就来看看怎么使用gulp来实现
打包功能。
我们先来看看我的工作目录,是怎么划分的
所有的项目使用的js和html源码,我都是放到src下,这个路径在后面我们使用gulp.src时能够用到。
接下来最关键的就是如何使用其API来实现我们的打包功能。
首先我们需要在项目的根目录下,也就是我这里对应的HAM-Front下创建一个gulpfile.js文件,我们会在这个文件种引入依赖的js文件和定义一些执行任务。
// Include gulp
var gulp = require('gulp');
require:引入gulp资源文件,类似于java中import作用
var connect = require('gulp-connect');
var gulpDocs = require('gulp-ngdocs');
这两条命令的意识是引入docs文件,使用gulp可以生成自定义的dos类型的API文档,这个比较高级了。我们的自定义组件都有自己对应的API文档,方便我们自己使用。如果你也有自己API文档不放参考gulp的官方文档,这里不做说明(都是机密
)
如上执行自定义的connect-docs执行,他就会为你启动一个端口为8080的服务,那么你只要在浏览器中输入localhost:8080,就可以访问你们的docs文档。
// Include Our Plugins
var plugins = require('gulp-load-plugins')({pattern: ['*']});
var wmaApp = 'src/main/webapp/app';
var wmaTemplatePath = '';
var wmaModule = 'am';
自定义项目路径和module模块。
gulp.task:执行自定义的一系列任务,gulp会最大量的执行定义的所有任务,这些任务不分先后。
gulp.task("one", function () {
});
gulp.task("two", function () {
});
那么这两个任务回一起执行,当然gulp也会支持先后执行,这个需要你做特殊的声明。我们来看看官网是怎么给出支持的。
1.异步支持
gulp支持异步方式,依次执行你所需要的任务,使用一个 callback,或者返回一个 promise 或 stream。
接收一个callback函数:
// 在 shell 中执行一个命令
var exec = require('child_process').exec;
gulp.task('jekyll', function(cb) {
// 编译 Jekyll
exec('jekyll build', function(err) {
if (err) return cb(err); // 返回 error
cb(); // 完成 task
});
});
返回一个stream或者promise:
gulp.task('somename', function() {
var stream = gulp.src('client/**/*.js')
.pipe(minify())
.pipe(gulp.dest('build'));
return stream;
});
var Q = require('q');
gulp.task('somename', function() {
var deferred = Q.defer();
// 执行异步的操作
setTimeout(function() {
deferred.resolve();
}, 1);
return deferred.promise;
});
当需要批量执行一个序列化的任务时,我们需要让下一个任务知道他需要在谁之后执行:(以下内容来自官网)
给出一个提示,来告知 task 什么时候执行完毕,
并且再给出一个提示,来告知一个 task 依赖另一个 task 的完成。
对于这个例子,让我们先假定你有两个 task,"one" 和 "two",并且你希望它们按照这个顺序执行:
- 在 "one" 中,你加入一个提示,来告知什么时候它会完成:可以再完成时候返回一个 callback,或者返回一个 promise 或 stream,这样系统会去等待它完成。
- 在 "two" 中,你需要添加一个提示来告诉系统它需要依赖第一个 task 完成。
因此,这个例子的实际代码将会是这样:
var gulp = require('gulp');
// 返回一个 callback,因此系统可以知道它什么时候完成
gulp.task('one', function(cb) {
// 做一些事 -- 异步的或者其他的
cb(err); // 如果 err 不是 null 或 undefined,则会停止执行,且注意,这样代表执行失败了
});
// 定义一个所依赖的 task 必须在这个 task 执行之前完成
gulp.task('two', ['one'], function() {
// 'one' 完成后
});
gulp.task('default', ['one', 'two']);
知道任务时怎么执行的之后,我们来创建我们的任务,然后定义需要执行的步骤。
2.3 js,css打包
gulp打包会将js和html代码打包到一个js中,把css打包到另外一个css中,这需要我们定义不同的任务来实现
- 定制js打包任务
// Concatenate & Minify JS
gulp.task('script-build', function () {
var javascriptStream = gulp.src(wmaApp + '/**/*.js');
var htmlStream = gulp.src(wmaApp + '/**/*.html')
.pipe(plugins.htmlmin({collapseWhitespace: true}))
.pipe(plugins.angularTemplatecache('templateCache.js', {module: wmaModule, root: wmaTemplatePath}));
return plugins.eventStream.merge(javascriptStream, htmlStream)
.pipe(plugins.angularFilesort())
.pipe(plugins.concat('ham.min.js'))
.pipe(plugins.uglify())
.pipe(gulp.dest('build/scripts'));
});
- 定制css打包任务
// Concatenate & Minify CSS
gulp.task('css-build', function () {
return gulp.src(wmaApp + '/**/*.css')
.pipe(plugins.concat('ham.min.css'))
.pipe(plugins.minifyCss())
.pipe(gulp.dest('build/styles/css'));
});
通过上面定义的两个任务就可以将css和js文件打包。
其中:
gulp.src(""):输出与指定匹配字符串或数组的文件,将返回一个 Vinyl files 的 stream 它可以被 piped 到别的
插件中。简单的说就是vinyl file的一种流文件,这种流文件可以具备可读写性,更重的是可以被pie到插件中。pie是
nodejs提供的一种方法,该方法可以增加可写性流的可读性,使其可能自动的切换到流动模式,并且使流的所有
数据成为可写。为了防止可写流不被更快的可读流覆盖淹没,这些数据流将会被自动管理。
gulp.dest():之前被pie进去的所有文件数据将会重新输出到文件中,这个文件可以是指定的存在的文件,也
可以是不存在的,如果不存在的话,它将会为你创建该文件。
2.4 gulp-clean
gulp-clean:创建clean任务,该任务主要作用是为了清除之前pie输出的流文件,为了避免在生成文件的时候
数据被覆盖,通常我们希望每次build的文件都是我们需要的最新的,我们需要将之前的文件流清除掉,来生成最新
的。
简单的来说就是直接删除已经build生成的文件:
// Clean existed build
gulp.task('clean', function () {
return gulp.src(
[
'build/*'
])
.pipe(plugins.clean({force: true}));
});
为了方便操作,我们定制了一系列的任务,让他执行,这个定制任务分为两个部分。一部分:清除已build编译
的文件;二部分:重新build文件生成新的我们需要的文件。
2.5 gulp-build
创建这个任务主要是为了方便我们操作:其实就是把clean,和重新编译任务组成一个有序的任务队列,让gulp
依次执行,还好nodejs提供了方法:
// Build all
gulp.task('build', function () {
plugins.runSequence('clean', 'script-build', 'css-build');
});
就是依次执行这三个任务,关于runSequence这个方法在下面这个文件中有定义,感兴趣的可以看看源码。
这样我们定制的所有任务在webstorm中都有提示:
我们切换到build目录下看看我们生成的编译压缩的文件:只要将这两个文件引入到index.html文件中就可以正常的使用,正常的访问项目了,有没有觉得很酷呢