1.自动化构建初体验
- 项目结构:
我们使用sass使编写css提高效率,但需要对sass进行编译。
yarn init --yes # 初始化项目目录
yarn add sass --dev # 在开发环境安装sass
yarn add browser-sync --dev # 在开发环境安装browser-sync
yarn add npm-run-all --dev # 在开发环境安装npm-run-all用来运行所有script
编辑package.json文件:
{
"name": "my-web-app",
"version": "0.1.0",
"main": "index.js",
"author": "zce <w@zce.me> (https://zce.me)",
"license": "MIT",
"scripts": {
"build": "sass scss/main.scss css/style.css --watch",
"serve": "browser-sync . --files \"css/*.css\"",
"start": "run-p build serve"
},
"devDependencies": {
"browser-sync": "^2.26.7",
"npm-run-all": "^4.1.5",
"sass": "^1.29.0"
}
}
命令行运行:
yarn start
自动执行:
yarn build
yarn browser-sync
2.常用的自动化构建工具
为什么要使用自动化构建工具:
一句话:自动化。对于需要反复重复的任务,例如压缩(minification)、编译、单元测试、linting等,自动化工具可以减轻你的劳动,简化你的工作。
2.1Grunt
Grunt 生态系统非常庞大,并且一直在增长。由于拥有数量庞大的插件可供选择,因此,你可以利用 Grunt 自动完成任何事,并且花费最少的代价。如果找不到你所需要的插件,那就自己动手创造一个 Grunt 插件,然后将其发布到 npm 上吧。
由于其工作过程是基于临时文件的,所以构建的速度相对较慢,频繁的磁盘读写导致速度慢
2.2Gulp
gulp 将开发流程中让人痛苦或耗时的任务自动化,从而减少你所浪费的时间、创造更大价值。
工作过程是基于内存实现的,解决了Grunt的速度问题。默认支持同时去处理多个任务,效率大大提高,使用方式相对于Grunt相对通俗易懂,插件生态也同样完善。个人安利。
2.3FIS
解决前端开发中自动化工具、性能优化、模块化框架、开发规范、代码部署、开发流程等问题
百度团队的工具,捆绑套餐,将很多功能都提供给我们。
3.Grunt使用
3.1 Grunt基本使用
创建空项目grunt-sample
yarn init --yes
安装grunt模块
yarn add grunt --dev
项目根目录添加gruntfile.js文件,并编写以下内容
// grunt入口文件 // 用于定义一些需要Grunt自动执行的任务 // 需要导出一个函数 // 此函数接收一个grtun对象,内部体用一些创建任务时可以用的API module.exports = grunt => { // 第二个字符串为任务描述 grunt.registerTask('foo','a sample task', () => { console.log('hello grunt'); }) grunt.registerTask('bar', () => { console.log('other task'); }) // // default 是默认任务名称 // // 通过grunt执行时可以省略任务名 // // grunt.registerTask('default', () => { // // console.log('default task'); // // }) // // 第二个参数可以指定此任务的映射任务 // // 这样执行default就相当于执行对应的任务 // // 这里的映射的任务会按照顺序一次执行,不会同步执行 // grunt.registerTask('default', ['foo', 'bar']) // // 也可以在任务函数中执行其他任务 // grunt.registerTask('run-other', () => { // // foo和bar会在当前任务执行完成过后自动依次执行 // grunt.task.run('foo', 'bar') // console.log('current task runing'); // }) // // 默认grunt采用同步模式编码 // // 如果需要异步可以使用this.async()方法创建回调函数 // // 下面代码不会再settimeout后打印语句 // // grunt.registerTask('async-task', () => { // // setTimeout(() => { // // console.log('async task working'); // // }, 1000); // // }) // // 由于函数体重需要使用this,所以这里不能使用箭头函数 grunt.registerTask('async-task', function () { const done = this.async() setTimeout(() => { console.log('async task working'); done() }, 1000); }) }
命令行运行
yarn grunt # 后面添加任务名或不添加任务名默认执行default
3.2 Grunt标记任务失败
标记任务失败需要在函数体中返回false。默认情况下(yarn grunt default),如果为任务列表,则当前面的任务执行失败后,后续的任务不再执行。如果在yarn grunt default后面添加–force时,则前面任务失败后,强制执行后面的任务yarn grunt default –force。
异步函数中标记当前任务执行失败的方式是为回调函数指定一个 false 的实参
module.exports = grunt => {
// 任务函数执行过程中如果返回 false
// 则意味着此任务执行失败
grunt.registerTask('bad', () => {
console.log('bad working~')
return false
})
grunt.registerTask('foo', () => {
console.log('foo working~')
})
grunt.registerTask('bar', () => {
console.log('bar working~')
})
// 如果一个任务列表中的某个任务执行失败
// 则后续任务默认不会运行
// 除非 grunt 运行时指定 --force 参数强制执行
grunt.registerTask('default', ['foo', 'bad', 'bar'])
// 异步函数中标记当前任务执行失败的方式是为回调函数指定一个 false 的实参
grunt.registerTask('bad-async', function () {
const done = this.async()
setTimeout(() => {
console.log('async task working~')
done(false)
}, 1000)
})
}
3.3 Grunt的配置方法
除了grunt.registerTask外,grunt还提供了一个去添加配置选项的API:initConfig
module.exports = grunt => {
// grunt.initConfig() 用于为任务添加一些配置选项
grunt.initConfig({
// 键一般对应任务的名称
// 值可以是任意类型的数据
foo: {
bar: 'baz'
}
})
grunt.registerTask('foo', () => {
// 任务中可以使用 grunt.config() 获取配置
console.log(grunt.config('foo'))
// 如果属性值是对象的话,config 中可以使用点的方式定位对象中属性的值
console.log(grunt.config('foo.bar'))
})
}
3.4 Grunt多目标任务
命令行运行yarn grunt build时,可以同时运行目标任务。如果需要运行指定目标任务,可以使用yarn grunt build:foo命令
module.exports = grunt => {
// 多目标模式,可以让任务根据配置形成多个子任务
// grunt.initConfig({
// build: {
// foo: 100,
// bar: '456'
// }
// })
// grunt.registerMultiTask('build', function () {
// console.log(`task: build, target: ${this.target}, data: ${this.data}`)
// })
grunt.initConfig({
build: {
// 任务配置选项,并不会执行
options: {
msg: 'task options'
},
foo: {
// 会覆盖build中的option
options: {
msg: 'foo target options'
}
},
bar: '456'
}
})
grunt.registerMultiTask('build', function () {
console.log(this.options())
})
}
3.5 Grunt插件的使用
- 安装插件
- gruntfile中载入插件
- 根据文档完成相关的配置选项
grunt sass
项目初始
安装插件grunt-sass以及npm模块sass
yarn add grunt-sass sass --dev
编写gruntfile.js
const sass = require('sass') module.exports = grunt => { grunt.initConfig({ sass: { options: { implementation:sass, }, main: { files: { 'dist/css/main.css': 'src/scss/main.scss' // 键为目标文件路径,值为需要编译的文件 } } } }) grunt.loadNpmTasks('grunt-sass') }
命令运行后的目录
grunt-babel
初始目录
安装grunt-babel
yarn add grunt-babel @babel/core @babel/preset-env --dev yarn add load-grunt-tasks --dev
编辑上面sass中js
const sass = require('sass') const loadGruntTasks = require('load-grunt-tasks') module.exports = grunt => { grunt.initConfig({ sass: { options: { sourceMap: true, implementation:sass, }, main: { files: { 'dist/css/main.css': 'src/scss/main.scss' // 键为目标文件路径,值为需要编译的文件 } } }, babel: { options: { sourceMap: true, presets: ['@babel/preset-env'] // 最新的ECMAScript中的特性加载进来 }, main:{ files: { 'dist/js/app.js': 'src/js/app.js' } } } }) // grunt.loadNpmTasks('grunt-sass') loadGruntTasks(grunt) // 自动加载所有的grunt插件中的所有任务 }
命令后的目录
grunt-contrib-watch
源文件变化时,实时编译文件
安装grunt-contrib-watch
yarn add grunt-contrib-watch --dev
编辑js文件
const sass = require('sass') const loadGruntTasks = require('load-grunt-tasks') module.exports = grunt => { grunt.initConfig({ sass: { options: { sourceMap: true, implementation:sass, }, main: { files: { 'dist/css/main.css': 'src/scss/main.scss' // 键为目标文件路径,值为需要编译的文件 } } }, babel: { options: { sourceMap: true, presets: ['@babel/preset-env'] // 最新的ECMAScript中的特性加载进来 }, main:{ files: { 'dist/js/app.js': 'src/js/app.js' } } }, watch: { js: { files:['src/js/*.js'], tasks: ['babel'] }, css: { files:['src/scss/*.scss'], tasks: ['sass'] } } }) // grunt.loadNpmTasks('grunt-sass') loadGruntTasks(grunt) // 自动加载所有的grunt插件中的所有任务 grunt.registerTask('default', ['sass', 'babel']) // 确保启动watch瞬间先执行sass任务和babel }
监听文件时terminal的状态:
4.Gulp使用
当下最流行的前端构建系统,其核心特性就是高效、易用。现在项目中安装gulp开发依赖。添加gulpfile.js,用于编写需要gulp自动执行的任务。随后可以再命令行使用gulp提供cli工具运行构建任务。
4.1 Gulp的基本使用
初始化项目目录
mkdir gulp-test # 创建项目目录 cd gulp-test # 切换目录 yarn init --yes # 初始化目录 yarn add gulp --dev # 安装gulp到开发环境
根目录创建gulpfile.js文件
// gulp入口文件 // 导出函数成员 exports.foo = () => { console.log('foo task working~'); }
通过命令行运行任务
yarn gulp foo # [22:23:50] Using gulpfile D:\DeskTop\02-01-study-materials\gulp-test\gulpfile.js # [22:23:50] Starting 'foo'... # foo task working~ # [22:23:50] The following tasks did not complete: foo # [22:23:50] Did you forget to signal async completion? # error Command failed with exit code 1. # info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
The following tasks did not complete: foo,foo任务未完成,因为最新的gulp中取消了同步代码运行模式,默认约定为异步任务,任务执行完成后,需要调用回调函数或其他方式去标记这个任务表示完成。这里我们手动的调用回调函数。
// gulp入口文件 // 导出函数成员 exports.foo = done => { console.log('foo task working~'); done() // 表示任务完成 } exports.default = done => { console.log('default task working~'); done() // 标记任务完成 }
此时foo任务会正常启动,正常结束。此时我们直接运行yarn gulp,他会自动运行default任务,同grunt一样。除此之外,gulp4.0前,注册gulp任务需要通过gulp模块中的方法来实现,具体来看:
const gulp = require('gulp') gulp.task('bar',done => { console.log('bar task working~') })
4.2 Gulp的组合使用
glup中需要使用到并行任务和串行任务,在我们项目过程中,编译scss文件和js文件是不冲突的,所以我们需要使用并行任务。而我们在编译文件和部署服务时,我们需要先进行编译scss和css文件,然后进行服务部署,这时候需要使用串行任务。在glup中提供了两个API serires以及parallel,分别提供串行和并行任务。
const {series, parallel} = reqire(‘gulp’)
const task1 = done => {
SetTimeout(() => {
console.log(‘task1 working~’)
done()
}, 1000)
}
const task2 = done => {
SetTimeout(() => {
console.log(‘task2 working~’)
done()
}, 1000)
}
const task3 = done => {
SetTimeout(() => {
console.log(‘task3 working~’)
done()
}, 1000)
}
exports.foo = series(task1, task2, task3) // 执行串行任务
exports.bar = parallel(task1, task2, task3) // 执行并行任务
yarn gulp foo # 此时三个任务会依次等待1秒后执行console.log()方法
yarn gulp bar # 此时三个任务会同时开始,在1秒后同时执行conssole.log()方法。
4.3 Gulp的异步任务
gulp中的任务都是异步任务,也就是我们经常提到的一部函数。我们调用一个异步函数时是没有办法去直接明确这个调用是否完成的。都是在函数内部通过回调或者事件去通知外部这个函数是否调用完成。在异步任务中,同样面临如何去通知gulp任务的完成情况。上面我们使用同步任务done()来模仿异步任务。
// 通过同步任务进行模拟
exports.call ask = done => {
console.log(‘callback task’)
done()
}
// 同步任务失败情况
export.callback_error = done => {
console.log(‘callback_error task’)
done(new Error(‘callback_error task failed!’))
}
// 使用promise去完成异步任务
exports.promise = () => {
console.log(‘promise task~’)
return Promise.resolve() // 标记promise任务完成
}
// promise任务失败情况
exports.promise_error = () => {
console.log(‘promise_error task’)
return Promise.reject(new Error(‘promise_error failed!’))
}
// 使用ES7中提供的async和await语法糖
const timeout = time => {
return new Promise(resolve => {
setTimeout(resolve, time)
})
}
exports.async = async () => {
await timeout(1000)
console.log(‘async task~’)
}
// 使用stream
const { doesNotMatch } = require('assert')
const fs = require('fs')
exports.stream = () => {
const read = fs.createReadStream('yarn.lock')
const write = fs.createWriteStream('a.txt')
read.pipe(write)
return read
}
// 模仿stream
exports.stream_copy = done => {
const read = fs.createReadStream('yarn.lock')
const write = fs.createWriteStream('b.txt')
read.pipe(write)
read.on('end', () => {
done()
})
}
4.4 Gulp构建过程核心工作原理
构建过程大多数都是将文件读取然后进行一些转换,最后写入另外一个位置。
这里我们模拟压缩css到吗为min.css的过程,主要分为以下几个步骤:
- 创建文件读取流-目标css
- 创建文件写入流-目标min.css
- 文件转换流,将读取的文件流使用replace进行替换空白字符与注释
- 使用pipe将文件流先转换,然后再讲转换流写入
具体代码如下:
const fs = require('fs')
const {Transform} = require('stream')
exports.default = () => {
// 文件流读取
const readStream = fs.createReadStream('normalize.css')
// 写入文件流
const writeStream = fs.createWriteStream('normalize.min.css')
// readStream.pipe(writeStream)
//
// return readStream
// 文件流转换
const transformStream = new Transform({
// 核心转换过程
transform: (chunk, encoding, callback) => {
const input = chunk.toString()
const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')
callback(null, output) // 第一个参数为错误对象,output为转换完的结果
}
})
return readStream
.pipe(transformStream) // 先转换
.pipe(writeStream) // 再写入
}
4.5 Gulp文件操作API
Gulp中为我们提供读取流和写入流 的API,相比于底层Node的API,Gulp的API更强大、更易用,至于负责文件的转换流,绝大多数情况我们都是通过独立的插件来提供。我们在实际去通过Gulp创建构建任务时的流程就是:先通过src方法去创建一个读取流,然后再借助插件提供的转换流来实现文件加工,最后我们再通过Gulp提供的dest方法去创建一个写入流,从而写入到目标文件。具体工作过程如下:
const {src, dest} = require('gulp')
const cleanCSS = require('gulp-clean-css')
const rename = require('gulp-rename')
exports.default = () => {
return src('src/*.css')
.pipe(cleanCSS())
.pipe(rename({extname: '.min.css'}))
.pipe(dest('dist'))
}
4.6 Gulp案例-样式编译
const {src, dest} = require('gulp')
// gulp.src:gulp底层是使用的nodejs的stream,首先获取到stream流,然后使用pipe()方法把流数据导入到你想让它去的地方。
// gulp.dest:src函数是读取文件,那dest函数就是写文件,gulp.dest(path[,options]),path是要写入的文件的路径,这里注意只能是路径,不能是具体的文件
const sass = require('gulp-sass') // 真是执行css编译的,其调用node-sass,而node-sass是c++的二进制模块,所以安装时需要设置淘宝镜像进行安装
const style = () => {
return src('src/assets/styles/*.scss', {base: 'src'}) // base作用是以src为基准,原样输出目录结构
.pipe(sass({outputStyle: 'expanded'})) // outputStyle作用是将sass生成的css文件最后的花括号放在块末尾
.pipe(dest('dist'))
}
module.exports = {
style
}
命令行运行:
yarn gulp style
4.7 Gulp案例-脚本编译
安装依赖:
yarn add gulp-babel --dev
yarn add @babel/core @babel/preset-env # preset-env会将ECMAScript中所有的新特性进行转换
const babel = require('gulp-babel')
const script = () => {
return src('src/assets/scripts/*.js', {base: 'src'})
.pipe(babel({presets: ['@babel/preset-env']}))
.pipe(dest('dist'))
}
module.exports = {
style,
script
}
命令行运行:
yarn gulp script
4.8 Gulp案例-页面编译
安装依赖:
yarn add gulp-swig --dev
const {src, dest, parallel, series} = require('gulp')
// gulp.src:gulp底层是使用的nodejs的stream,首先获取到stream流,然后使用pipe()方法把流数据导入到你想让它去的地方。
// gulp.dest:要说src函数是读取文件,那么dest函数就是写文件,gulp.dest(path[,options]),path是要写入的文件的路径,这里注意只能是路径,不能是具体的文件
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const swig = require('gulp-swig')
const data = {...}
const style = () => {
return src('src/assets/styles/*.scss', {base: 'src'}) // base作用是以src为基准,原样输出目录结构
.pipe(sass({outputStyle: 'expanded'})) // outputStyle作用是将sass生成的css文件最后的花括号放在块末尾
.pipe(dest('dist'))
}
const script = () => {
return src('src/assets/scripts/*.js', {base: 'src'})
.pipe(babel({presets: ['@babel/preset-env']}))
.pipe(dest('dist'))
}
const page = () => {
return src('src/*.html', {base: 'src'})
.pipe(swig({data})) // 填充模板页面的数据
.pipe(dest('dist'))
}
const compile = parallel(style, script, page) // 任务并行
module.exports = {
compile
}
命令行输入:
yarn gulp compile
4.9 Gulp案例-图片和字体文件转换
安装依赖:
yarn add gulp-imagemin --dev # 与node-sass相同,需要引入二进制文件,科学上网
const {src, dest, parallel, series} = require('gulp')
// gulp.src:gulp底层是使用的nodejs的stream,首先获取到stream流,然后使用pipe()方法把流数据导入到你想让它去的地方。
// gulp.dest:要说src函数是读取文件,那么dest函数就是写文件,gulp.dest(path[,options]),path是要写入的文件的路径,这里注意只能是路径,不能是具体的文件
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const swig = require('gulp-swig')
const imagemin = require('gulp-imagemin')
const data = {...}
const style = () => {
return src('src/assets/styles/*.scss', {base: 'src'}) // base作用是以src为基准,原样输出目录结构
.pipe(sass({outputStyle: 'expanded'})) // outputStyle作用是将sass生成的css文件最后的花括号放在块末尾
.pipe(dest('dist'))
}
const script = () => {
return src('src/assets/scripts/*.js', {base: 'src'})
.pipe(babel({presets: ['@babel/preset-env']}))
.pipe(dest('dist'))
}
const page = () => {
return src('src/*.html', {base: 'src'})
.pipe(swig({data})) // 填充模板页面的数据
.pipe(dest('dist'))
}
const image = () => {
return src('src/assets/images/**', { base: 'src' })
.pipe(imagemin())
.pipe(dest('dist'))
}
const font = () => {
return src('src/assets/fonts/**', { base: 'src' })
.pipe(imagemin())
.pipe(dest('dist'))
}
const compile = parallel(style, script, page, image, font) // 任务并行
module.exports = {
compile,
}
运行命令:
yarn gulp image
yarn gulp font
4.10 Gulp案例-其他文件及文件清除
const {src, dest, parallel, series} = require('gulp')
// gulp.src:gulp底层是使用的nodejs的stream,首先获取到stream流,然后使用pipe()方法把流数据导入到你想让它去的地方。
// gulp.dest:要说src函数是读取文件,那么dest函数就是写文件,gulp.dest(path[,options]),path是要写入的文件的路径,这里注意只能是路径,不能是具体的文件
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const swig = require('gulp-swig')
const imagemin = require('gulp-imagemin')
const data = {...}
const style = () => {
return src('src/assets/styles/*.scss', {base: 'src'}) // base作用是以src为基准,原样输出目录结构
.pipe(sass({outputStyle: 'expanded'})) // outputStyle作用是将sass生成的css文件最后的花括号放在块末尾
.pipe(dest('dist'))
}
const script = () => {
return src('src/assets/scripts/*.js', {base: 'src'})
.pipe(babel({presets: ['@babel/preset-env']}))
.pipe(dest('dist'))
}
const page = () => {
return src('src/*.html', {base: 'src'})
.pipe(swig({data})) // 填充模板页面的数据
.pipe(dest('dist'))
}
const image = () => {
return src('src/assets/images/**', { base: 'src' })
.pipe(imagemin())
.pipe(dest('dist'))
}
const font = () => {
return src('src/assets/fonts/**', { base: 'src' })
.pipe(imagemin())
.pipe(dest('dist'))
}
const extra = () => {
return src('public/**', {base: 'public'}) // 额外拷贝的任务
.pipe(dest('dist'))
}
const compile = parallel(style, script, page, image, font) // 任务并行
const build = parallel(compile, extra) // 任务并行
module.exports = {
build
}
需要在build任务之前先自动清除dist文件,因此使用series创建串行任务。
安装依赖
yarn add del --dev
const {src, dest, parallel, series} = require('gulp')
// gulp.src:gulp底层是使用的nodejs的stream,首先获取到stream流,然后使用pipe()方法把流数据导入到你想让它去的地方。
// gulp.dest:要说src函数是读取文件,那么dest函数就是写文件,gulp.dest(path[,options]),path是要写入的文件的路径,这里注意只能是路径,不能是具体的文件
const del = require('del')
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const swig = require('gulp-swig')
const imagemin = require('gulp-imagemin')
const data = {...}
const clean = () => {
return del(['dist']) // 返回promise
}
const style = () => {
return src('src/assets/styles/*.scss', {base: 'src'}) // base作用是以src为基准,原样输出目录结构
.pipe(sass({outputStyle: 'expanded'})) // outputStyle作用是将sass生成的css文件最后的花括号放在块末尾
.pipe(dest('dist'))
}
const script = () => {
return src('src/assets/scripts/*.js', {base: 'src'})
.pipe(babel({presets: ['@babel/preset-env']}))
.pipe(dest('dist'))
}
const page = () => {
return src('src/*.html', {base: 'src'})
.pipe(swig({data})) // 填充模板页面的数据
.pipe(dest('dist'))
}
const image = () => {
return src('src/assets/images/**', { base: 'src' })
.pipe(imagemin())
.pipe(dest('dist'))
}
const font = () => {
return src('src/assets/fonts/**', { base: 'src' })
.pipe(imagemin())
.pipe(dest('dist'))
}
const extra = () => {
return src('public/**', {base: 'public'}) // 额外拷贝的任务
.pipe(dest('dist'))
}
const compile = parallel(style, script, page, image, font) // 任务并行
const build = series(clean, parallel(compile, extra)) // 任务并行
module.exports = {
build
}
4.11 Gulp案例-自动加载插件
代码合理化,自动加载所有gulp的插件,使用gulp-load-plugins
const {src, dest, parallel, series} = require('gulp')
// gulp.src:gulp底层是使用的nodejs的stream,首先获取到stream流,然后使用pipe()方法把流数据导入到你想让它去的地方。
// gulp.dest:要说src函数是读取文件,那么dest函数就是写文件,gulp.dest(path[,options]),path是要写入的文件的路径,这里注意只能是路径,不能是具体的文件
const del = require('del')
const loadPlugins = require('gulp-load-plugins') // 加载load-plugins
const plugins = loadPlugins() //以下所有插件使用plugins.[插件名],如果插件名为gulp-xx-xx,那么改为plugins.xxYy,驼峰命名
const data = {...}
const clean = () => {
return del(['dist', 'temp'])
}
const style = () => {
return src('src/assets/styles/*.scss', {base: 'src'}) // base作用是以src为基准,原样输出目录结构
.pipe(plugins.sass({outputStyle: 'expanded'})) // outputStyle作用是将sass生成的css文件最后的花括号放在块末尾
.pipe(dest('dist'))
}
const script = () => {
return src('src/assets/scripts/*.js', {base: 'src'})
.pipe(plugins.babel({presets: ['@babel/preset-env']}))
.pipe(dest('dist'))
}
const page = () => {
return src('src/*.html', {base: 'src'})
.pipe(plugins.swig({data})) // 填充模板页面的数据
.pipe(dest('dist'))
}
const image = () => {
return src('src/assets/images/**', {base: 'src'})
.pipe(plugins.imagemin())
.pipe(dest('dist'))
}
const font = () => {
return src('src/assets/fonts/**', {base: 'src'})
.pipe(plugins.imagemin())
.pipe(dest('dist'))
}
const extra = () => {
return src('public/**', {base: 'public'}) // 额外拷贝的任务
.pipe(dest('dist'))
}
const compile = parallel(style, script, page, image, font) // 任务并行
const build = series(clean, parallel(compile, extra)) // 任务并行
module.exports = {
build
}
4.12 Gulp案例-开发服务器、监视变化以及构建优化
const serve = () => {
watch('src/assets/styles/*.scss', style)
watch('src/assets/scripts/*.js', script)
watch('src/*.html', page)
// watch('src/assets/images/**', image)
// watch('src/assets/fonts/**', font)
// watch('public/**', extra)
watch([
'src/assets/images/**',
'src/assets/fonts/**',
'public/**'
], bs.reload)
bs.init({
notify: false,
port: 2080,
// open: false,
// files: 'dist/**',
server: {
baseDir: ['temp', 'src', 'public'],
routes: {
'/node_modules': 'node_modules'
}
}
})
}
const develop = series(compile, serve)
module.exports = {
clean,
build,
develop
}
4.13Gulp案例-userer文件引用处理
const useref = () => {
return src('temp/*.html', { base: 'temp' })
.pipe(plugins.useref({ searchPath: ['temp', '.'] }))
// html js css
.pipe(plugins.if(/\.js$/, plugins.uglify()))
.pipe(plugins.if(/\.css$/, plugins.cleanCss()))
.pipe(plugins.if(/\.html$/, plugins.htmlmin({
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true
})))
.pipe(dest('dist'))
}
4.14Gulp案例-重新规划构建过程
暴露出任务
{
"name": "zce-gulp-demo",
"version": "0.1.0",
"main": "index.js",
"repository": "https://github.com/zce/zce-gulp-demo.git",
"author": "zce <w@zce.me> (https://zce.me)",
"license": "MIT",
"scripts": {
"clean": "gulp clean", // 此时可以直接执行yarn clean
"build": "gulp build",
"develop": "gulp develop"
},
"dependencies": {
"bootstrap": "^4.3.1",
"jquery": "^3.4.1",
"popper.js": "^1.15.0"
},
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"browser-sync": "^2.26.7",
"del": "^5.1.0",
"gulp": "^4.0.2",
"gulp-babel": "^8.0.0",
"gulp-clean-css": "^4.2.0",
"gulp-htmlmin": "^5.0.1",
"gulp-if": "^3.0.0",
"gulp-imagemin": "^6.1.0",
"gulp-load-plugins": "^2.0.1",
"gulp-sass": "^4.0.2",
"gulp-swig": "^0.9.1",
"gulp-uglify": "^3.0.2",
"gulp-useref": "^3.1.6"
}
}
gitignore忽略生成的目录
dist
temp