gulp进阶构建项目由浅入深
gulp进阶构建项目由浅入深
阅读目录
- gulp基本安装和使用
- gulp API介绍
- gulp一些常用插件
- gulp构建小型项目的基本过程
gulp基本安装和使用
Gulp的构建过程:gulp是使用nodejs中的stream(流),首先通过gulp.src()方法获取到我们需要的文件流(stream),然后把文件流通过pipe()方法把流导入到gulp的插件中,最后通过插件处理后的流再通过pipe()方法导入到gulp.dest()中,gulp.dest()方法把流中的内容写入到文件中。
1. Gulp安装:
首先我们需要安装nodejs,然后进行全局安装;安装如下:
sudo npm install gulp –g
全局安装后,还需要切换到项目的根目录下,单独为单个项目进行安装下;安装如下:
sudo npm install gulp
如果想在安装的时候把gulp写进package.json文件的依赖中,则可以加上 –save-dev
sudo npm install –save-dev gulp
2. 如何使用gulp?
在项目的根目录下新建一个 gulpfile.js文件,之后就可以定义一个任务了;
比如如下简单的任务:代码如下:
var gulp = require('gulp'); gulp.task('default',function(){ console.log('hello world'); });
现在我项目的目录结构假如是如下样子:
最后我们进行命令行切换到项目的根目录下,运行gulp命令后,就可以在控制台看到consoe.log的打印的消息了;
gulp API介绍
Gulp.src(globs[,options])
最常见的我们使用四个API,gulp.task() gulp.src() gulp.dest() gulp.watch();
该方法是获取我们需要的文件流,这个流里面的内容不是原始的文件流,而是一个虚拟文件对象流(Vinyl files);该方法有2个参数
globs类型是 String 或 Array , 该文件流可以是一个单独的字符串形式,也可以是一个数组形式;
options是一个对象类型;该对象类型有一个我们常用的base字段配置 options.base是经常会使用的到;
比如如下代码:
var gulp = require('gulp');
var uglify = require('gulp-uglify');
gulp.task("uglify-js",function(){
return gulp.src("src/js/*.js")
.pipe(uglify())
.pipe(gulp.dest('build'));
});
gulp.task('default',['uglify-js']);
// 写入到 build/a.js 和 build/index.js
如下目录结构:
我们使用base字段来继续编写如下代码:
var gulp = require('gulp');
var uglify = require('gulp-uglify'); gulp.task("uglify-js",function(){
return gulp.src("src/js/*.js",{ base: 'src' })
.pipe(uglify())
.pipe(gulp.dest('build'));
});
gulp.task('default',['uglify-js']);
我们再在项目的根目录下面运行gulp命令可以看到项目的目录结构变为如下:
因此我们可以理解base字段为相对于路径来进行打包,最后生成 build/js/*.js文件;
看看Gulp用到的glob的匹配规则:
Gulp内部使用了node-glob模块来实现文件匹配功能。该文件匹配类似于JS中的正则表达式;如下匹配:
* 匹配文件路径中的0个或者多个字符,但是不会匹配路径分隔符。比如: 可以匹配 abc.js,x.js,aaa,abc/(路径分隔符出现在末尾也可以匹配);但是不能匹配类似于这样的路径分隔符 abc/aa.js
*.* 可以匹配a.xxx; xxxx.yyyy;等
*/*/*.js 可以匹配a/b/c.js,但不是不能匹配 a/b.js 或者 a/b/c/d.js
** 可以匹配路径中的0个或者多个目录及其子目录。比如:能匹配abc,a/b.js,
a/b/c.js,x/y/z等等;
**/*.js 能够匹配a.js , a/a.js,a/aaa/aaaa/a.js等等;也就是说只要以.js结尾的,不管前面有多少个文件或者分隔符都可以匹配;
a/**/z 能匹配a/z,a/b/z, a/b/c/z等等。
a/**b/z 能匹配a/b/z,a/sb/z, 不是不能匹配a/x/y/xxb/z;
?.js 能匹配a.js,b.js,c.js,相当于js正则里面的一样匹配0个或者1个,优先匹配;
[xyz].js 能匹配x.js,y.js,z.js,类似于js正则一样,中括号中的任意一个字符;
[^xyz].js 除了中括号中的x,y,z中的其他的任意一个字符;
当有多种匹配模式的时候可以使用数组,如下:
gulp.src([‘js/*.js’,’css/*.css’]);
我们也可以排除一些文件,可以使用!, 比如如下代码:
gulp.src([‘js/*.js’,’css/*.css’,’!reset.css’]) ; 匹配所有的js/目录下的js文件及匹配css/目录下的css文件,但是不包括reset.css文件;但是不能把排除写在第一个元素位置;
比如如下代码: gulp.src([‘!reset.css’,’css/*.css’]); 这样的是排除不掉的,这种方式我们在css中可以理解为后面的代码覆盖前面的,因此需要写在后面才能排除当前的;
gulp.dest(path[,options])
该方法可以理解为把目标的源文件通过pipe方法导入到gulp插件中,最后把文件流写到目标文件中;如果该文件不存在的话,则会自动创建它;比如上面的gulp.src(),目录结构一刚开始build目录是没有的,通过打包后自动创建build文件夹;
字段path: 文件被写入的路径(输出的目录),也可以传入一个函数,在函数中返回相应的路径。
字段options也是一个对象类型;
Gulp.dest(path) 生成的文件路径是相对于gulp.src()中有通配符开始出现的那部分路径。
比如如下代码:
var gulp = require('gulp');
var uglify = require('gulp-uglify');
gulp.task("uglify-js",function(){
return gulp.src("src/js/*.js")
.pipe(uglify())
.pipe(gulp.dest('build'));
});
gulp.task('default',['uglify-js']);
gulp.src()上面有通配符的是 *.js, 因此最后生成的文件路径是 build/*.js;
但是如果没有出现通配符的情况下,比如如下代码:
gulp.src("src/js/a.js")
.pipe(gulp.dest('build'));
那么最后生成的路径就是 build/a.js 了;
当然我们可以在gulp.src()方法中配置base属性,如果没有配置base属性的话,那么默认生成的路径就是相对于通配符出现的那部分路径;如果设置了base属性的话,那么就相对于base的那个设置的路径;假如现在的源目录结构为src/js/下游很多js文件
比如如下代码:
var gulp = require('gulp');
var uglify = require('gulp-uglify');
gulp.task("uglify-js",function(){
return gulp.src("src/js/*.js",{ base: 'src' })
.pipe(uglify())
.pipe(gulp.dest('build'));
});
gulp.task('default',['uglify-js']);
是相对于src文件下的,因此最后生成的路径为 build/js/*.js
gulp.task(name[,deps],fn);
该方法是定义一个任务;
name: 是任务的名字;
deps: {Array} 类型是数组类型;一个包含任务列表的数组,这些任务会在你当前任务运行之前完成;比如如下代码:
gulp.task('mytask', ['one', 'two', 'task', 'names'], function() {
// 做一些事
});
比如上面的代码,我们想要完成'mytask'这个任务的话,首先会执行依赖数组中的那些任务,但是如果依赖任务里面又使用了异步的方法,比如使用setTimeout这样的时候,那么这个时候,我再执行mytask这个任务的时候,就不会等待该依赖任务完成后再执行了;比如如下代码:
var gulp = require('gulp');
gulp.task('one',function(){
//one是一个异步执行的任务
setTimeout(function(){
console.log('one is done')
},5000);
});
//two任务虽然依赖于one任务,但并不会等到one任务中的异步操作完成后再执行
gulp.task('two',['one'], function(){
console.log('two is done');
});
gulp.task('default',['two']);
上面的例子中我们执行two任务时,会先执行one任务,但不会去等待one任务中的异步操作完成后再执行two任务,而是紧接着执行two任务。所以two任务会在one任务中的异步操作完成之前就执行了。
但是如果我们想等待one任务中的setTimeout执行完成后,再执行two这个任务该怎么办呢?
我们可以使用如下方法,代码如下:
var gulp = require('gulp');
gulp.task('one',function(fn){
// fn 为任务函数提供的回调 用来通知该任务已经完成
//one是一个异步执行的任务
setTimeout(function(){
console.log('one is done');
fn();
},1000);
});
//two任务虽然依赖于one任务,但并不会等到one任务中的异步操作完成后再执行
gulp.task('two',['one'], function(){
console.log('two is done');
});
gulp.task('default',['two']);
gulp.watch(glob[,opts],tasks)
用来监听文件的变化,当文件发生改变的时候,我们可以用它来执行相应的任务;
参数如下:
glob: 为要监听的文件匹配模式,规则和gulp.src中的glob相同;
opts: 为一个可选的配置对象,一般不怎么用;
tasks: 为文件变化后要执行的任务,为一个数组;
比如代码如下:
gulp.task('two', function(){
console.log('two is done');
});
gulp.watch('js/**/*.js',['two'])
gulp一些常用插件
1.gulp-rename(重命名)
用来重命名文件流中的文件。
安装:npm install --save-dev gulp-rename
比如如下代码:
var gulp = require('gulp'),
rename = require('gulp-rename'),
uglify = require("gulp-uglify"); gulp.task('rename', function () {
gulp.src('src/**/*.js')
.pipe(uglify()) //压缩
.pipe(rename('index.min.js'))
.pipe(gulp.dest('build/js'));
});
gulp.task('default',['rename']);
//关于gulp-rename的更多强大的用法请参考https://www.npmjs.com/package/gulp-rename
2.gulp-uglify(JS压缩)
安装:npm install --save-dev gulp-uglify
还是上面的gulpfile.js代码如下:
var gulp = require('gulp'),
rename = require('gulp-rename'),
uglify = require("gulp-uglify"); gulp.task('rename', function () {
gulp.src('src/**/*.js')
.pipe(uglify()) //压缩
.pipe(rename('index.min.js'))
.pipe(gulp.dest('build/js'));
});
gulp.task('default',['rename']);
3.gulp-minify-css(css文件压缩)
安装:npm install --save-dev gulp-minify-css
代码如下:
var gulp = require('gulp'),
minifyCss = require("gulp-minify-css");
gulp.task('minify-css', function () {
gulp.src('src/**/*.css') // 要压缩的css文件
.pipe(minifyCss()) //压缩css
.pipe(gulp.dest('build'));
});
gulp.task('default',['minify-css']);
4.gulp-minify-html(html压缩)
安装:npm install --save-dev gulp-minify-html
代码如下:
var gulp = require('gulp'),
minifyHtml = require("gulp-minify-html"); gulp.task('minify-html', function () {
gulp.src('src/**/*.html') // 要压缩的html文件
.pipe(minifyHtml()) //压缩
.pipe(gulp.dest('build'));
}); gulp.task('default',['minify-html']);
5.gulp-concat(JS文件合并)
安装:npm install --save-dev gulp-concat
代码如下:
var gulp = require('gulp'),
concat = require("gulp-concat"); gulp.task('concat', function () {
gulp.src('src/**/*.js') //要合并的文件
.pipe(concat('index.js')) // 合并匹配到的js文件并命名为 "index.js"
.pipe(gulp.dest('build/js'));
}); gulp.task('default',['concat']);
6.gulp-less (less编译)
安装:npm install –save-dev gulp-less
Gulpfile.js代码如下:
var gulp = require('gulp'),
less = require("gulp-less"); gulp.task('compile-less', function () {
gulp.src('src/less/*.less')
.pipe(less())
.pipe(gulp.dest('build/css'));
}); gulp.task('default',['compile-less']);
7.gulp-sass(sass编译)
安装:npm install –save-dev gulp-sass
代码如下:
var gulp = require('gulp'),
sass = require("gulp-sass"); gulp.task('compile-sass', function () {
gulp.src('src/sass/*.sass')
.pipe(sass())
.pipe(gulp.dest('build/css'));
}); gulp.task('default',['compile-sass']);
8.gulp-imagemin(图片压缩)
安装:npm install –save-dev gulp-imagemin
代码如下:
var gulp = require('gulp');
var imagemin = require('gulp-imagemin'); gulp.task('uglify-imagemin', function () {
return gulp.src('src/images/*')
.pipe(imagemin())
.pipe(gulp.dest('build/images'));
});
gulp.task('default',['uglify-imagemin']);
9.理解 Browserify
browserify是一个使用node支持的CommonJS模块标准 来为浏览器编译模块的,可以解决模块及依赖管理;
先来看看使用gulp常见的问题:
1. 使用 gulp 过程中,偶尔会遇到 Streaming not supported 这样的错误。这通常是因为常规流与 vinyl 文件对象流有差异、
gulp 插件默认使用了只支持 buffer (不支持 stream)的库。比如,不能把 Node 常规流直接传递给 gulp 及其插件。
比如如下代码:会抛出异常的;
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var fs = require('fs'); gulp.task('bundle', function() {
return fs.createReadStream('./test.txt')
.pipe(uglify())
.pipe(rename('bundle.min.js'))
.pipe(gulp.dest('dist/'));
});
gulp.task('default',['bundle']);
gulp 选择默认使用内容转换成 buffer 的 vinyl 对象流,以方便处理。当然,设置 buffer: false 选项,可以让 gulp 禁用 buffer:
比如如下gulpfile.js代码如下:
var gulp = require('gulp');
var fs = require('fs');
gulp.task('bundle', function() {
return gulp.src('./src/js/app.js', {buffer: false}).on('data', function(file) {
var stream = file.contents;
stream.on('data', function(chunk) {
console.log('Read %d bytes of data', chunk.length);
});
});
})
gulp.task('default',['bundle']);
运行如下:
2. Stream 和 Buffer 之间转换
基于依赖的模块返回的是 stream, 以及 gulp 插件对 stream 的支持情况,有时需要把 stream 转换为 buffer。比如很多插件只支持 buffer,如 gulp-uglify、使用时可以通过 gulp-buffer 转换:Stream转换Buffer
如下gulpfile.js代码:
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var buffer = require('gulp-buffer');
var uglify = require('gulp-uglify');
var fs = require('fs');
gulp.task('bundle', function() {
return fs.createReadStream('./src/js/app.js')
.pipe(source('app.min.js')) // 常规流转换成 vinyl 对象
.pipe(buffer())
.pipe(uglify())
.pipe(gulp.dest('dist/'));
})
gulp.task('default',['bundle']);
如下所示:
3. 从 Buffer 到 Stream之间转换
也可以通过使用 gulp-streamify(https://www.npmjs.com/package/gulp-streamify) 或者 gulp-stream (https://www.npmjs.com/package/gulp-stream)插件,让只支持 buffer 的插件直接处理 stream。
如下gulpfile.js代码:
var gulp = require('gulp');
var wrap = require('gulp-wrap');
var streamify = require('gulp-streamify');
var uglify = require('gulp-uglify');
var gzip = require('gulp-gzip'); gulp.task('bundle', function() {
return gulp.src('./src/js/app.js', {buffer: false})
.pipe(wrap('(function(){<%= contents %>}());'))
.pipe(streamify(uglify()))
.pipe(gulp.dest('dist'))
.pipe(gzip())
.pipe(gulp.dest('dist'));
});
gulp.task('default',['bundle']);
如下所示:
4. 使用browserify进行Stream 向 Buffer 转换
vinyl-source-stream + vinyl-buffer
vinyl-source-stream(https://www.npmjs.com/package/vinyl-source-stream) : 将常规流转换为包含 Stream 的 vinyl 对象;
vinyl-buffer(https://www.npmjs.com/package/vinyl-buffer) 将 vinyl 对象内容中的 Stream 转换为 Buffer。
gulpfile.js代码如下:
var browserify = require('browserify');
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer'); gulp.task('browserify', function() {
return browserify('./src/js/app.js')
.bundle()
.pipe(source('bundle.js')) // gives streaming vinyl file object
.pipe(buffer()) // convert from streaming to buffered vinyl file object
.pipe(uglify())
.pipe(gulp.dest('./dist/js'));
});
gulp.task('default',['browserify']);
vinyl-source-stream 使用指定的文件名bundle.js创建了一个 vinyl 文件对象实例,因此可以不再使用 gulp-rename(gulp.dest 将用此文件名写入结果)。
如下所示:
5. 使用browserify多文件操作
5-1. 使用Gulp和Browserify单个文件操作也可以如下:
var gulp = require('gulp');
var browserify = require('browserify');
var source = require('vinyl-source-stream'); gulp.task('browserify', function(){
return browserify(
{entrieis:['./src/js/app.js']})
.bundle()
.pipe(source("bundle.js"))
.pipe(gulp.dest('dist'));
});
gulp.task('default',['browserify']);
5-2 多文件操作如下:
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var browserify = require('browserify');
var glob = require('glob');
var es = require('event-stream'); gulp.task('browserify', function(done) {
glob('./src/**/*.js', function(err, files) {
if(err) {
done(err)
};
var tasks = files.map(function(entry) {
return browserify({ entries: [entry] })
.bundle()
.pipe(source(entry))
.pipe(gulp.dest('./dest'));
});
es.merge(tasks).on('end', done);
})
});
gulp.task('default',['browserify']);
5-3 也可以使用gulp.src和browserify一起使用;代码如下:
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var browserify = require('browserify');
var glob = require('glob');
var es = require('event-stream');
var buffer = require('vinyl-buffer'); gulp.task('browserify', function(done) {
gulp.src('./src/**/*.js',function(err,files) {
if(err) {
done(err)
}
files.forEach(function(file){
return browserify({ entries: [file] })
.bundle()
.pipe(source(file))
.pipe(buffer())
.pipe(gulp.dest('./dest'));
});
});
});
gulp.task('default',['browserify']);
browserify深入学习;
1.前言:
之前我们做项目的时候,比如需要jquery框架的话,我们可能需要下载jquery源码,然后引入到我们的项目中,之后在html文件中像如下引入即可:
<script src="path/to/jquery.js"></script>
2.bower学习
之后我们学习了 Bower,因此我们安装了Bower,然后进入我们的项目文件根目录中 在命令行中使用bower安装jquery;如下命令:
bower install jquery
之后会在我们的根目录中生成一个 bower_components文件,里面包含了jquery文件,因此我们需要在我们的html文件中这样引入jquery了;
<script src="bower_components/jquery/dist/jquery.js"></script>
如下所示:
3. npm&Browserify学习
我们现在又可以使用 命令行用npm安装jQuery。进入项目的根目录后,运行如下命令:
npm install --save-dev jquery
接着我们在命令行中全局安装 browserify;命令如下:
sudo npm install -g browserify
现在我们就可以在命令行中使用 browserify命令了;
比如现在我在我的项目目录下的源文件 src/js/a.js 下想要使用jquery的话,我们可以在a.js代码如下引用:
var $ = require('jquery');
$(function(){
// 获取页面中的DOM元素
console.log($("#jquery2"));
});
function a() {
console.log("a.js");
}
a();
再进入命令行相对应的js文件中,进行如下命令:
browserify a.js -o dest.js
执行命令后会在同目录下生成dest.js,该文件包含jquery.js和a.js;然后我们把dest文件引入到我们需要的html文件中即可访问;
4. gulp和Browserify 一起使用
结合gulp一起使用时,我们只需要把Browserify安装到我们的项目内即可;因此进入项目的根目录中,进行如下命令安装:
npm install --save-dev browserify
然后在项目的根目录中在gulpfile.js文件中加入如下代码:
var gulp = require("gulp");
var browserify = require("browserify");
var sourcemaps = require("gulp-sourcemaps");
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer'); gulp.task("browserify", function () {
var b = browserify({
entries: "./src/js/a.js",
debug: true
});
return b.bundle()
.pipe(source("bundle.js"))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write("."))
.pipe(gulp.dest("./dist"));
}); gulp.task('default',['browserify']);
a.js代码还是如下:
var $ = require('jquery');
$(function(){
// 获取页面中的DOM元素
console.log($("#jquery2"));
});
function a() {
console.log("a.js");
}
a();
进入项目的根目录中运行命令 gulp即可,在目录中会生成dist目录(包含bundle.js和bundle.js.map)两个文件;之后在html文件页面上引入
dist目录文件下的bundle.js即可;
在上面的代码中,debug: true是告知Browserify在运行同时生成内联sourcemap用于调试。
如果我们把debug设置成false的话;在浏览器中访问页面,可以看到如下:
如果我们把debug设置成true的话,在浏览器中访问页面,可以看到如下:
引入gulp-sourcemaps并设置loadMaps: true是为了读取上一步得到的内联sourcemap,并将其转写为一个单独的sourcemap文件。
如果我们把loadMaps设置成false的话,我们在浏览器访问页面如下图所示:
如果我们把loadMaps设置成true的话,我们在浏览器访问页面如下图所示:
vinyl-source-stream用于将Browserify的bundle()的输出转换为Gulp可用的[vinyl][](一种虚拟文件格式)流。
vinyl-buffer用于将vinyl流转化为buffered vinyl文件(gulp-sourcemaps及大部分Gulp插件都需要这种格式)。
如果代码比较多,可能一次编译需要很长时间。这个时候,我们可以使用[watchify][]。它可以在你修改文件后,
只重新编译需要的部分(而不是Browserify原本的全部编译),这样,只有第一次编译会花些时间,此后的即时变更刷新则十分迅速。
如下代码:
var watchify = require('watchify');
var browserify = require('browserify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var gutil = require('gulp-util');
var sourcemaps = require('gulp-sourcemaps');
var assign = require('lodash.assign'); // 在这里添加自定义 browserify 选项
var customOpts = {
entries: ['./src/js/a.js'],
debug: true
};
var opts = assign({}, watchify.args, customOpts);
var b = watchify(browserify(opts)); // 在这里加入变换操作
// 比如: b.transform(coffeeify); gulp.task('js', bundle); // 这样你就可以运行 `gulp js` 来编译文件了
b.on('update', bundle); // 当任何依赖发生改变的时候,运行打包工具
b.on('log', gutil.log); // 输出编译日志到终端 function bundle() {
return b.bundle()
// 如果有错误发生,记录这些错误
.on('error', gutil.log.bind(gutil, 'Browserify Error'))
.pipe(source('bundle.js'))
// 可选项,如果你不需要缓存文件内容,就删除
.pipe(buffer())
// 可选项,如果你不需要 sourcemaps,就删除
.pipe(sourcemaps.init({loadMaps: true})) // 从 browserify 文件载入 map
// 在这里将变换操作加入管道
.pipe(sourcemaps.write('./')) // 写入 .map 文件
.pipe(gulp.dest('./dist'));
}
gulp.task('default',['js']);
5. 使用Browserify来组织JavaScript文件
还是上面那个项目,假如src/js文件内有2个js文件,分别为a.js和b.js;假如现在a.js想引用b.js的模块,就像seajs那样通过require来引用如何做?
现在我们可以在b.js这样编写代码;把我们的代码模块通过module.exports 或 exports模块对外提供接口,和其他的比如seajs一样编写代码
即可:比如现在b.js代码如下:
function b() {
console.log("b.js");
}
module.exports = b;
那么a.js代码如下:
var b = require('./b');
function a() {
b();
console.log("a.js");
}
a();
然后再在gulpfile.js文件代码还是如下:
var gulp = require("gulp");
var browserify = require("browserify");
var sourcemaps = require("gulp-sourcemaps");
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer'); gulp.task("browserify", function () {
var b = browserify({
entries: "./src/js/a.js",
debug: true
});
return b.bundle()
.pipe(source("bundle.js"))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write("."))
.pipe(gulp.dest("./dist"));
}); gulp.task('default',['browserify']);
在命令行中运行gulp,即可生成bundle.js文件;引用该文件即可解决模块依赖的问题;我们打开bundle.js文件查看代码如下:
(function e(t,n,r){
/*
function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;
if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");
throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];
return s(n?n:e)},l,l.exports,e,t,n,r)}
return n[o].exports}var i=typeof require=="function"&&require;
for(var o=0;o<r.length;o++)s(r[o]);return s */ })({1:[function(require,module,exports){ var b = require('./b'); function a() {
b();
console.log("a.js");
}
a();
},{"./b":2}],2:[function(require,module,exports){
function b() {
console.log("b.js");
}
module.exports = b;
},{}]},{},[1])
该函数有3个参数,
第一个参数是一个对象;第二个参数是一个空对象{};第三个参数是一个[1];
第一个参数是一个object;它的每一个key都是一个数字,作为模块的id,每一个数字key对应的值是长度为2的数组。可以看下,第一个key数字1
模块中的数组中的第一个元素是a.js代码;数组中第二个元素是a模块的依赖项,第二个key数字2模块中数组第一个元素是b.js代码;数组中的第二个
元素是空对象{};因为b模块没有依赖项;因此为{};
我们的文件代码通过一个匿名函数被包装起来,这样做的好处是:我们的浏览器中并没有require这样的解决依赖的东西,但是我们又想像seajs,
requireJS等一样使用require来引入文件解决模块依赖的文件的时候,因此 Browserify实现了require、module、exports这3个关键字。
第2个参数几乎总是空的{}。它如果有的话,也是一个模块map;
第3个参数是一个数组,指定的是作为入口的模块id。a.js是入口模块,它的id是1,所以这里的数组就是[1]。
那么 Browserify是如何实现了require、module、exports这3个关键字的呢?
我们前面被注释的代码将解析require、module、exports这三个3个参数,然后让一切运行起来。
这段代码是一个函数,来自于browser-pack项目的[prelude.js][]。
上面我们看到在Browserify打包文件的时候,它会自动使用匿名函数进行包装;因此我们在编写代码的时候一般可以不需要考虑全局变量的问题了;
不需要在函数中添加像类型匿名函数的结构 (function(){})();
10.理解gulp.watch()的使用
gulp.watch()方法可以监听文件的动态修改,它接受一个glob或者glob数组(和gulp.src()一样)以及一个任务数组来执行回调。下面我们来看下
gulp.watch()方法的使用;比如现在gulpfile.js任务代码如下:
var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify'); var paths = {
scripts: ['src/js/**/*.js'],
css: ['src/css/**/*.css'],
// 把源文件html放在src下,会自动打包到指定目录下
html: ['src/html/**/*.html']
}; gulp.task('scripts', function() { return gulp.src(paths.scripts)
.pipe(concat('all.js'))
.pipe(uglify())
.pipe(gulp.dest('build/js'));
}); gulp.task('css', function() { return gulp.src(paths.css)
.pipe(concat('all.css'))
.pipe(gulp.dest('build/css'));
}); // 监听html文件的改变
gulp.task('html',function(){
return gulp.src(paths.html)
.pipe(gulp.dest('html/'));
}); // Rerun the task when a file changes
gulp.task('watch', function() {
gulp.watch(paths.scripts, ['scripts']);
gulp.watch(paths.css, ['css']);
gulp.watch(paths.html, ['html']);
}); // The default task (called when you run `gulp` from cli)
gulp.task('default', ['scripts', 'css', 'html','watch']);
监听src文件下的js和css及html的文件的变化,我们在相关的项目根目录命令行中运行gulp后,当我们改变css或者js文件或html的时候,
可以监听文件的动态修改,因此保存刷新浏览器即可生效,这是gulp-watch的基本功能;如下所示:
会把src下的文件css和js自动打包到build下,src下的html文件会打包到项目根目录下的html文件下;
上面的gulp.watch 回调函数有一个包含触发回调函数信息的event对象:比如我们把gulp watch任务改成如下:
当每次更改文件的时候 都会触发change事件;代码改为如下:
gulp.task('watch', function() {
var watch1 = gulp.watch(paths.scripts, ['scripts']);
var watch2 = gulp.watch(paths.css, ['css']);
var watch3 = gulp.watch(paths.html, ['html']); watch1.on('change', function (event) {
console.log('Event type: ' + event.type); // Event type: changed
console.log('Event path: ' + event.path); // Event path: /Users/tugenhua/gulp/src/css/a.css
});
watch2.on('change', function (event) {
console.log('Event type: ' + event.type); // Event type: changed
console.log('Event path: ' + event.path); // Event path: /Users/tugenhua/gulp/src/css/a.css
});
watch3.on('change', function (event) {
console.log('Event type: ' + event.type); // Event type: changed
console.log('Event path: ' + event.path); // Event path: /Users/tugenhua/gulp/src/css/a.css
});
});
除了change事件,还可以监听很多其他的事件:
end 在watcher结束时触发
error 在出现error时触发
ready 在文件被找到并正被监听时触发
nomatch 在glob没有匹配到任何文件时触发
Watcher对象也包含了一些可以调用的方法:
watcher.end() 停止watcher(以便停止执行后面的任务或者回调函数)
watcher.files() 返回watcher监听的文件列表
watcher.add(glob) 将与指定glob相匹配的文件添加到watcher
watcher.remove(filepath) 从watcher中移除个别文件
上面是通过gulp-watch来动态监听html,css和js文件的改变,但是需要重新刷新页面才能生效;
11.理解LiveReload插件的使用
该插件的作用是当文件被修改的时候,它能实时刷新网页,这样的话就不需要我们实时刷新了;但是该插件需要在我们服务器下生效;因此
我们需要使用 gulp-connect 创建一个服务器;下面是gulpfile.js代码如下;使用liveReload实现实时刷新;
var gulp = require('gulp');
var connect = require('gulp-connect');
var uglify = require("gulp-uglify");
var concat = require("gulp-concat");
var mincss = require("gulp-minify-css");
//自动刷新
var livereload = require("gulp-livereload"); /* 设置路径 */
var paths = {
src : "src/",
css : "src/css/",
scripts : "src/js/",
scss : "src/scss/",
img : "src/images/",
html : "src/html/",
build : "build"
}
// 创建一个webserver 服务器
gulp.task('webserver', function() {
connect.server({
port: 8000,
livereload: true
});
}); gulp.task('scripts', function() { return gulp.src(paths.scripts+ "**/*.js")
.pipe(concat('all.js'))
.pipe(uglify())
.pipe(gulp.dest(paths.build + '/js'));
}); gulp.task('css', function() { return gulp.src(paths.css+ "**/*.css")
.pipe(concat('all.css'))
.pipe(mincss())
.pipe(gulp.dest(paths.build + '/css'));
}); // 监听html文件的改变
gulp.task('html',function(){
return gulp.src(paths.html + "**/*.html")
.pipe(gulp.dest('html/'));
}); //reload server
gulp.task('reload-dev',['scripts','css','html'],function() {
return gulp.src(paths.src + '**/*.*')
.pipe(connect.reload());
}); // Watch
gulp.task('watch', function() {
//监听生产环境目录变化
gulp.watch(paths.src + '**/*.*',['reload-dev']);
}) gulp.task('default', ['webserver','reload-dev','watch']);
12.理解browser-sync的使用
BroserSync在浏览器中展示变化的功能与LiveReload非常相似,但是它有更多的功能。实现静态服务器,也是能实时刷新页面的;BrowserSync也可以在不同浏览器之间同步点击翻页、表单操作、滚动位置等功能。
安装如下命令:
npm install --save-dev browser-sync
如下gulpfile文件是动态监听js,css和html文件的变化实时更新;如下代码:
var gulp = require('gulp');
var connect = require('gulp-connect');
var uglify = require("gulp-uglify");
var concat = require("gulp-concat");
var mincss = require("gulp-minify-css");
//自动刷新
var browserSync = require('browser-sync').create();
var reload = browserSync.reload; /* 设置路径 */
var paths = {
src : "src/",
css : "src/css/",
scripts : "src/js/",
scss : "src/scss/",
img : "src/images/",
html : "src/html/",
build : "build"
} gulp.task('scripts', function() { return gulp.src(paths.scripts+ "**/*.js")
.pipe(concat('all.js'))
.pipe(uglify())
.pipe(gulp.dest(paths.build + '/js'))
.pipe(reload({stream:true})); // inject into browsers
}); gulp.task('css', function() { return gulp.src(paths.css+ "**/*.css")
.pipe(concat('all.css'))
.pipe(mincss())
.pipe(gulp.dest(paths.build + '/css'))
.pipe(reload({stream:true})); // inject into browsers
}); // 监听html文件的改变
gulp.task('html',function(){
return gulp.src(paths.html + "**/*.html")
.pipe(gulp.dest('html/'))
.pipe(reload({stream:true})); // inject into browsers
}); // 创建本地服务器,并且实时更新页面文件
gulp.task('browser-sync', ['scripts','css','html'],function() {
var files = [
'**/*.html',
'**/*.css',
'**/*.js'
]; browserSync.init(files,{
server: {
//baseDir: "./html"
}
}); }); //gulp.task('default', ['webserver','reload-dev','watch']);
gulp.task('default', ['browser-sync'], function () {
gulp.watch("**/*.css", ['css']);
gulp.watch("**/*.html", ['html']);
gulp.watch("**/*.js", ['scripts']);
});
对 browser-sync 更多的学习 请看文档(http://www.browsersync.cn/docs/api/)
gulp构建小型项目的基本过程
比如我现在一个小项目的基本架构如下所示:
src文件夹:是源文件的目录结构;build文件夹是通过构建后生成的文件;
src存放文件如下:
common(该目录是存放公用的插件css文件和js文件)
html目录是存放目前的html文件
images目录存放所有在项目中用到的图片
js目录是在项目中用到的所有的js文件;
less文件是存放需要预编译成css文件;
这上面几个目录都会通过gulpfile.js打包到build目录下;通过上面的学习browserify(可以解决js的模块化依赖问题)及学习 browserSync(实现自动刷新效果),因此目前该项目打包有2个优点:
1. 可以使用require,exports,和moudle这三个参数实现js模块化组织及加载的问题,它不需要依赖于seajs或者requireJS;
2. 可以实时监听html,css,js文件的修改,从而不需要刷新页面,可以提高工作效率;
现在我把package.json用到的依赖包放到下面来:
{
"name": "testProject",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"browser-sync": "^2.12.10",
"browserify": "^13.0.1",
"event-stream": "^3.3.2",
"glob": "^7.0.3",
"gulp": "^3.9.1",
"gulp-buffer": "0.0.2",
"gulp-clean": "^0.3.2",
"gulp-concat": "^2.6.0",
"gulp-connect": "^4.0.0",
"gulp-gzip": "^1.3.0",
"gulp-imagemin": "^3.0.1",
"gulp-less": "^3.1.0",
"gulp-livereload": "^3.8.1",
"gulp-marked": "^1.0.0",
"gulp-minify-css": "^1.2.4",
"gulp-rename": "^1.2.2",
"gulp-sourcemaps": "^1.6.0",
"gulp-str-replace": "0.0.4",
"gulp-streamify": "^1.0.2",
"gulp-uglify": "^1.5.3",
"gulp-util": "^3.0.7",
"gulp-watch": "^4.3.6",
"gulp-wrap": "^0.13.0",
"lodash.assign": "^4.0.9",
"node-glob": "^1.2.0",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0",
"watchify": "^3.7.0"
}
}
项目用到的话,直接npm install 就可以把所有的包加载进来;
gulpfile.js代码如下:
var gulp = require('gulp');
var less = require('gulp-less');
var mincss = require('gulp-minify-css');
var concat = require("gulp-concat");
var uglify = require("gulp-uglify");
var clean = require('gulp-clean'); var browserify = require("browserify");
var sourcemaps = require("gulp-sourcemaps");
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer'); var replace = require('gulp-str-replace');
var imagemin = require('gulp-imagemin'); //自动刷新
var browserSync = require('browser-sync').create();
var reload = browserSync.reload; var fs = require('fs');
var fileContent = fs.readFileSync('./package.json');
var jsonObj = JSON.parse(fileContent); var argv = process.argv.pop();
var DEBUGGER = (argv === "-D" || argv === "-d") ? true : false; /* 基础路径 */
var paths = {
css : 'src/common/css/',
less : 'src/less/',
scripts : "src/js/",
img : "src/images/",
html : "src/html/",
build : "build",
src : 'src'
}
var resProxy = "项目的真实路径";
var prefix = "项目的真实路径"+jsonObj.name; if(DEBUGGER) {
resProxy = "http://localhost:3000/build";
prefix = "http://localhost:3000/build";
} // 先清理文件
gulp.task('clean-css',function(){
return gulp.src(paths.build + "**/*.css")
.pipe(clean());
});
gulp.task('testLess', ['clean-css'],function () {
return gulp.src([paths.less + '**/*.less',paths.css+'**/*.css'])
.pipe(less())
.pipe(concat('index.css'))
.pipe(mincss())
.pipe(replace({
original : {
resProxy : /\@{3}RESPREFIX\@{3}/g,
prefix : /\@{3}PREFIX\@{3}/g
},
target : {
resProxy : resProxy,
prefix : prefix
}
}))
.pipe(gulp.dest(paths.build + "/css"))
.pipe(reload({stream:true}));
}); // 监听html文件的改变
gulp.task('html',function(){
return gulp.src(paths.html + "**/*.html")
.pipe(replace({
original : {
resProxy : /\@{3}RESPREFIX\@{3}/g,
prefix : /\@{3}PREFIX\@{3}/g
},
target : {
resProxy : resProxy,
prefix : prefix
}
}))
.pipe(gulp.dest(paths.build+'/html'))
.pipe(reload({stream:true}));
});
// 对图片进行压缩
gulp.task('images',function(){
return gulp.src(paths.img + "**/*")
.pipe(imagemin())
.pipe(gulp.dest(paths.build + "/images"));
});
// 创建本地服务器,并且实时更新页面文件
gulp.task('browser-sync', ['testLess','html','browserify'],function() {
var files = [
'**/*.html',
'**/*.css',
'**/*.less',
'**/*.js'
];
browserSync.init(files,{ server: {
//baseDir: "./html"
} });
}); // 解决js模块化及依赖的问题
gulp.task("browserify",function () {
var b = browserify({
entries: ["./src/js/index.js"],
debug: true
});
return b.bundle()
.pipe(source("index.js"))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(gulp.dest("./build/js"))
.pipe(uglify())
.pipe(sourcemaps.write("."))
.pipe(replace({
original : {
resProxy : /\@{3}RESPREFIX\@{3}/g,
prefix : /\@{3}PREFIX\@{3}/g
},
target : {
resProxy : resProxy,
prefix : prefix
}
}))
.pipe(gulp.dest("./build/js"))
.pipe(reload({stream:true}));
}); gulp.task('default',['testLess','html','images','browserify'],function () {
gulp.watch(["**/*.less","**/*.css"], ['testLess']);
gulp.watch("**/*.html", ['html']);
gulp.watch("**/*.js", ['browserify']);
}); gulp.task('server', ['browser-sync','images'],function () {
gulp.watch(["**/*.less","**/*.css"], ['testLess']);
gulp.watch("**/*.html", ['html']);
gulp.watch("**/*.js", ['browserify']);
});
如果我们在命令行中 运行gulp server -d 那就是开发环境,会自动打开一个服务器;如果运行gulp的话,就是线上的正式环境了;代码会通过replace插件替换成线上的环境;
使用replace插件的好处可以这样引入文件
<script src="@@@PREFIX@@@/js/index.js"></script>
<link rel="stylesheet" href="@@@PREFIX@@@/css/index.css"/>
所有的图片都可以使用这样的@@@PREFIX@@@来引入的,这样的话就可以指向本地的环境和线上的环境了;方便开发;
gulp进阶构建项目由浅入深的更多相关文章
- webpack进阶构建项目(一)
webpack进阶构建项目(一) 阅读目录 1.理解webpack加载器 2.html-webpack-plugin学习 3.压缩js与css 4.理解less-loader加载器的使用 5.理解ba ...
- gulp插件构建项目 压缩js、css、image、zip、web服务、跨域等插件
推荐一个很好文: https://github.com/lin-xin/blog/issues/2 匹配符 *.**.!.{} gulp.src('./js/*.js') // * 匹配js文件夹下所 ...
- [转]webpack进阶构建项目(一)
阅读目录 1.理解webpack加载器 2.html-webpack-plugin学习 3.压缩js与css 4.理解less-loader加载器的使用 5.理解babel-loader加载器 6.理 ...
- webpack进阶构建项目(一):1.理解webpack加载器
1.理解webpack加载器 webpack的设计理念,所有资源都是“模块”,webpack内部实现了一套资源加载机制,这与Requirejs.Sea.js.Browserify等实现有所不同. We ...
- 使用gulp自动构建项目
网址:https://segmentfault.com/a/1190000011514257
- gulp 自动化构建html项目--自动刷新
使用gulp自动化构建项目是前端学习的重要部分,gulp依赖于node.js.首选电脑要配置node和npm. 查看node版本号 node --version 查看npm 版本 npm --vers ...
- 基于Gulp + Browserify构建es6环境下的自动化前端项目
随着React.Angular2.Redux等前沿的前端框架越来越流行,使用webpack.gulp等工具构建前端自动化项目也随之变得越来越重要.鉴于目前业界普遍更流行使用webpack来构建es6( ...
- 【gulp】gulp + browsersync 构建前端项目自动化工作流
什么是 gulp? gulp.js 是一个自动化构建工具,开发者可以使用它在项目开发过程中自动执行常见任务.gulp.js 是基于 node.js 构建的,利用 node.js 流的威力,你可以快速构 ...
- gulp自动化构建工具
gulp 自动化构建工具,实时监控.代码合并.压缩... http://www.gulpjs.com.cn/ 中文网 http://gulpjs.com/plugins/ 英文网 ...
随机推荐
- Python简介及环境部署
Python的由来: Python的创始人:Guido van Rossum Guido 在1989年12月时,寻找一门“课余”编程项目来打发圣诞节前后的时间.Guido决定为当时正构 ...
- eclipse+SVN文件只显示版本号,不显示时间和作者解决办法
SVN默认是显示提交次数的 改成这样 就可以了...
- 使用PreApplicationStartMethodAttribute
第一次见到这个东西是在公司的框架里,刚开始还挺郁闷怎么框架的Application_Start里没东西,初始化的那些代码都哪去了,后来通过一些线索找到了PreApplicationStartMetho ...
- 分布式ID生成器
最近会写一篇分布式的ID生成器的文章,先占位.借鉴Mongodb的ObjectId的生成: 4byte时间戳 + 3byte机器标识 + 2byte PID + 3byte自增id 简单代码: imp ...
- CSS,font-family,好看常用的中文字体
例1(小米米官网):font-family: "Arial","Microsoft YaHei","黑体","宋体",s ...
- Handler,Thread,Looper之间关系小结
http://blog.csdn.net/sunxingzhesunjinbiao/article/details/6794840 (1) Looper类别用来为一个线程开启一个消息循环.默认情况下A ...
- HTML5系列四(特征检测、Modernizr.js的相关介绍)
Modernizr:一个HTML5特征检测库 Modernizr帮助我们检测浏览器是否实现了某个特征,如果实现了那么开发人员就可以充分利用这个特征做一些工作 Modernizr是自动运行的,无须调用诸 ...
- python小打小闹之简陋版BBS
闲的蛋疼,索性写个东西玩,于是,写个类似于BBS的念头就开始了. 我们考虑到需要实现的功能: 1 只有登陆的用户才可以点赞,如果没有登陆,那么不可以点赞,点赞次数只可以为1. 2 只有登陆的用户可以评 ...
- 日志模块logging使用心得
在应用程序使用中,日志输出对应用维护人员.开发人员判断程序的问题起重要作用. 那么在python中如何定义程序的日志输出? 推荐使用日志模块logging 需求:实现日志内容输出在文件中和控制器中 i ...
- EmgnCv进行轮廓寻找和计算物体凸包
http://blog.csdn.net/qq_22033759/article/details/48029493 一.轮廓寻找 用的是FindContours函数,在CvInvoke中 不过需要用到 ...