1.自动化构建基本介绍
自动化构建是前端工程化中重要组成部分,
就是把开发阶段源代码自动转化成生产环境当中可以运行的代码或者程序
- 自动化构建工作流
2.自动化构建体验
NPM Scripts
在package.json中增加一个scripts对象,如:在这里插入代码片
{
"scripts": {
"build": "sass scss/main.scss css/style.css"
}
}
scripts可以自动发现node_modules里面的命令,所以不需要写完整的路径,直接写命令的名称就可以。然后可以通过npm或yarn运行scripts下面的命令名称,npm用run启动,yarn可以省略run,如:npm run build
或yarn build
NPM Scripts是实现自动化构建工作流的最简方式
安装browser-sync
{
"scripts": {
"build": "sass scss/main.scss css/style.css",
"preserve": "yarn build",
"serve": "browser-sync ."
}
}
preserve是一个钩子,保证在执行serve之前,会先执行build,使样式先处理,然后再执行serve
通过–watch可以监听sass文件的变化自动编译,但是此时sass命令在工作时,命令行会阻塞,去等待文件的变化,导致了后面的serve无法去工作,此时就需要同时去执行多个任务,要安装npm-run-all
这个模块
{
"scripts": {
"build": "sass scss/main.scss css/style.css --watch",
"serve": "browser-sync .",
"start": "run-p build serve"
}
}
运行npm run start命令,build和serve就会被同时执行
3.常用的自动化构建工具
- Grunt:磁盘读写
- Gulp:在内存中完成,可同时执行多个任务
- FIS:百度支持,微内核
4.Grunt的使用
官网
Grunt是最早的前端构建系统,它的插件生态非常完善,它的插件可以帮你完成任何你想做的事情。由于Grunt工作过程是基于临时文件去实现的,所以会比较慢
使用详情
- 初始化项目
yarn init --yes
- 安装grunt:
yarn add grunt
- 编写
gruntfile.js
文件,下面举例grunt任务的几种用法: - 执行命令:yarn grunt build
1.基本使用
// Grunt 的入口文件
// 用于定义一些需要 Grunt 自动执行的任务
// 需要导出一个函数
// 此函数接收一个 grunt 的对象类型的形参
// grunt 对象中提供一些创建任务时会用到的 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() 方法创建回调函数
// 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)
})
}
2.标记任务失败
- 在任务中return false
- 命令中添加 --force
- 异步任务中给done添加实参
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.Grunt的配置方法
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'))
})
}
4.多目标任务(相当于子任务)
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: {
options: {
msg: 'foo target options'
}
},
bar: '456'
}
})
grunt.registerMultiTask('build', function () {
console.log(this.options())
})
}
5.grunt插件使用
插件机制是grunt的核心,因为很多构建任务都是通用的,社区当中也就出现了很多通用的插件,这些插件中封装了很多通用的任务,一般情况下我们的构建过程都是由通用的构建任务组成的。先去npm中安装 需要的插件,再去gruntfile中使用grunt.loadNpmTasks方法载入这个插件,最后根据插件的文档完成相关的配置选项
使用clean插件,可清除文件
- 安装 yarn add grunt-contrib-clean
module.exports = grunt => {
// 多目标任务需要通过initConfig配置目标
grunt.initConfig({
clean: {
temp: 'temp/**' // ** 表示temp下的子目录以及子目录下的文件
}
})
grunt.loadNpmTasks('grunt-contrib-clean')
}
执行:yarn grunt clean ,就会删除temp文件夹
6.Grunt常用插件总结
- grunt-sass
- grunt-babel
- grunt-watch
1. grunt-sass
const sass = require('sass')
module.exports = grunt => {
grunt.initConfig({
sass: {
options: {
sourceMap:true,
implementation: sass
},
main: {
files: {
'dist/css/main.css': 'src/scss/main.scss'
}
}
}
})
grunt.loadNpmTasks('grunt-sass')
}
2. grunt-babel(将ES6语法转化为ES5)
yarn add grunt-babel @babel/core @babel/preset-env --dev
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']
},
main: {
files: {
'dist/js/app.js': 'src/js/app.js'
}
}
}
})
// grunt.loadNpmTasks('grunt-sass')
loadGruntTasks(grunt) // 自动加载所有的 grunt 插件中的任务
}
3.grunt-contrib-watch(监视文件改变)
const sass = require('sass')
const loadGruntTasks = require('load-grunt-tasks')
module.exports = grunt => {
grunt.initConfig({
sass: {
options: {
sourceMap: true,
implementation: sass, // implementation指定在grunt-sass中使用哪个模块对sass进行编译,我们使用npm中的sass
},
main: {
files: {
'dist/css/main.css': 'src/scss/main.scss'
}
}
},
babel: {
options: {
presets: ['@babel/preset-env'],
sourceMap: true
},
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'])
}
package.json安装对应的依赖
{
"name": "grunt-demo",
"version": "0.1.0",
"main": "index.js",
"author": "zce <w@zce.me> (https://zce.me)",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"grunt": "^1.0.4",
"grunt-babel": "^8.0.0",
"grunt-contrib-watch": "^1.1.0",
"grunt-sass": "^3.1.0",
"load-grunt-tasks": "^5.1.0",
"sass": "^1.22.10"
}
}
5.Gulp
英文官网
中文网址
Gulp是目前世界上最流行的前端构建系统,其核心特点就是高效、易用。它很好的解决了Grunt中读写磁盘慢的问题,Gulp是基于内存操作的。Gulp支持同时执行多个任务,效率自然大大提高,而且它的使用方式相对于Grunt更加易懂,而且Gulp的生态也非常完善
1.gulp的使用
- 初始化项目
yarn init --yes
- 安装:yarn add gulp
- 创建gulpfile.js
// gulp的入口文件
exports.foo = done => {
console.log('foo task working...')
done() // 使用done()标识任务完成
}
exports.default = done => {
console.log('default task working...')
done()
}
- 执行命令:yarn gulp foo执行foo任务, 或者yarn gulp执行默认任务default
结果:
gulp4.0之前的任务写法:
const gulp = require('gulp')
gulp.task('bar', done => {
console.log('bar working...')
done()
})
执行命令yarn gulp bar可以运行bar任务,gulp4.0之后也保留了这个API,但是不推荐使用了
2.组合任务(串行,并行)
const { series, parallel } = require('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 输出
yarn run v1.22.10
$ D:\CODE\study\02-01-study-materials\02-01-study-materials\code\02-01-03-08-gulp-compose-tasks\node_modules\.bin\gulp foo
[16:10:34] Using gulpfile D:\CODE\study\02-01-study-materials\02-01-study-materials\code\02-01-03-08-gulp-compose-tasks\gulpfile.js
[16:10:34] Starting 'foo'...
[16:10:34] Starting 'task1'...
task1 working~
[16:10:35] Finished 'task1' after 1 s
[16:10:35] Starting 'task2'...
task2 working~
[16:10:36] Finished 'task2' after 1 s
[16:10:36] Starting 'task3'...
task3 working~
[16:10:37] Finished 'task3' after 1 s
[16:10:37] Finished 'foo' after 3.01 s
Done in 3.94s.
yarn gulp gar 输出
yarn run v1.22.10
$ D:\CODE\study\02-01-study-materials\02-01-study-materials\code\02-01-03-08-gulp-compose-tasks\node_modules\.bin\gulp bar
[16:10:43] Using gulpfile D:\CODE\study\02-01-study-materials\02-01-study-materials\code\02-01-03-08-gulp-compose-tasks\gulpfile.js
[16:10:43] Starting 'bar'...
[16:10:43] Starting 'task1'...
[16:10:43] Starting 'task2'...
[16:10:43] Starting 'task3'...
task1 working~
[16:10:44] Finished 'task1' after 1.01 s
task2 working~
[16:10:44] Finished 'task2' after 1.01 s
task3 working~
[16:10:44] Finished 'task3' after 1.01 s
[16:10:44] Finished 'bar' after 1.01 s
Done in 1.93s.
3.Gulp的异步任务
回调方式解决
- promise的回调方案解决
- node 环境是8以上的版本可以使用async await
- stream是最常见的使用方式
const fs = require('fs')
exports.callback = done => {
console.log('callback task')
done()// 通过使用done()标志异步任务执行结束
}
exports.callback_error = done => {
console.log('callback task')
done(new Error('task failed')) // done函数也是错误优先回调函数。如果这个任务失败了,后序任务也不会工作了
}
exports.promise = () => {
console.log('promise task')
return Promise.resolve()// resolve执行的时候,表示异步任务执行结束了。resolve不需要参数,因为gulp会忽略它的参数
}
exports.promise_error = () => {
console.log('promise task')
return Promise.reject(new Error('task failed'))// reject标志这是一个失败的任务,后序的任务也会不再执行
}
const timeout = time => {
return new Promise(resolve => {
setTimeout(resolve, time)
})
}
exports.async = async () => {
await timeout(1000)// 在node8以上可以使用async和await,await的就是一个Promise对象
console.log('async task')
}
exports.stream = () => {
const read = fs.createReadStream('yarn.lock')
const write = fs.createWriteStream('a.txt')
read.pipe(write)
return read
}
//与stream 一致
exports.stream_copy = done => {// 最常用的就是基于stream的异步任务
const read = fs.createReadStream('yarn.lock')
const write = fs.createWriteStream('a.txt')
read.pipe(write)
read.on('end', () => {
done()
})
}
4.构建过程的核心原理
gulpfile.js
- 首先将文件读取出来写入文件流
const fs = require('fs')
exports.default = () => {
// 文件读取流
const read = fs.createReadStream('normalize.css')
// 文件写入流
const write = fs.createWriteStream('normalize.min.css')
//把读取出来的文件流导入写入文件流
read.pipe(write)
return read
}
- 将文件转换后再导入
const fs = require('fs')
const { Transform } = require('stream')
exports.default = () => {
// 文件读取流
const read = fs.createReadStream('normalize.css')
// 文件写入流
const write = fs.createWriteStream('normalize.min.css')
// 文件转换流
const transform = new Transform({
// 核心转换过程
transform: (chunk, encoding, callback) => {
// chunk=>读取流中读取到的内容buffer
const input = chunk.toString()
//替换掉空格,和注释
const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')
callback(null, output)
}
})
//把读取出来的文件流导入写入文件流
read
.pipe(transform)
.pipe(write)
return read
}
5.Gulp文件操作API
yarn add gulp-clean-css --dev
压缩css代码yarn add gulp-rename --dev
const { src, dest } = require('gulp')
const cleanCSS = require('gulp-clean-css')
const rename = require('gulp-rename')
// 模拟 gulp 的原理: 读取流 => 转换流 => 写入流
exports.default = () => {
return src('src/*.css')
.pipe(cleanCSS())
.pipe(rename({ extname: '.min.css' }))
.pipe(dest('dist'))
}
运行后的结果
6.Gulp 案例
模拟构建:
安装的依赖
yarn add gulp --dev
yarn add gulp-sass --dev
处理 sassyarn add gulp-babel @babel/core @babel/preset-env --dev
处理 es6+yarn add gulp-swig --dev
模板引擎yarn add gulp-imagemin --dev
图片处理yarn add gulp-load-plugins --dev
自动加载gulp插件 解决文件顶部插件引入很多,导致代码比较繁杂的问题yarn add del --dev
清除文件yarn add browser-sync --dev
开发服务器 支持HMRyarn add gulp-useref --dev
处理文件引用关系yarn add gulp-htmlmin gulp-uglify gulp-clean-css --dev
压缩文件yarn add gulp-if --dev
判断 流的类型yarn add bootstrap jquery popper.js
项目启动的其他依赖
1.样式的编译任务
const { src, dest } = require("gulp");
const sass = require("gulp-sass");
// scss 转 css
const style = () => {
// 指定从 src 下保留路径
return (
src("src/assets/styles/*.scss", { base: "src" })
// sass对_icons.css,默认不编译
.pipe(sass({ outputStyle: "expanded" }))
.pipe(dest("dist"))
);
};
module.exports = {
style
}
2.脚本的编译任务
const { src, dest } = require("gulp");
const sass = require("gulp-sass");
const babel = require('gulp-babel')
// scss 转 css
const style = () => {
// 指定从 src 下保留路径
return (
src("src/assets/styles/*.scss", { base: "src" })
// sass对_icons.css,默认不编译
.pipe(sass({ outputStyle: "expanded" }))
.pipe(dest("dist"))
);
};
const script = () => {
// 指定从 src 下保留路径
return (
src("src/assets/scripts/*.js", { base: "src" })
// ES6+ 处理 注意这里要提供 babel 预设, 不然就不转换
.pipe(babel({ presets: ['@babel/preset-env'] }))
.pipe(dest("dist"))
);
};
module.exports = {
style,
script
}
3.页面模板的编译任务
const { src, dest, parallel } = require("gulp");
const sass = require("gulp-sass");
const babel = require('gulp-babel')
const swig = require("gulp-swig");
const data = {
menus: [
{
name: "Home",
icon: "aperture",
link: "index.html",
},
{
name: "Features",
link: "features.html",
},
{
name: "About",
link: "about.html",
},
{
name: "Contact",
link: "#",
children: [
{
name: "Twitter",
link: "https://twitter.com/w_zce",
},
{
name: "About",
link: "https://weibo.com/zceme",
},
{
name: "divider",
},
{
name: "About",
link: "https://github.com/zce",
},
],
},
],
pkg: require("./package.json"),
date: new Date(),
};
// scss 转 css
const style = () => {
// 指定从 src 下保留路径
return (
src("src/assets/styles/*.scss", { base: "src" })
// sass对_icons.css,默认不编译
.pipe(sass({ outputStyle: "expanded" }))
.pipe(dest("dist"))
);
};
const script = () => {
// 指定从 src 下保留路径
return (
src("src/assets/scripts/*.js", { base: "src" })
// ES6+ 处理 注意这里要提供 babel 预设, 不然就不转换
.pipe(babel({ presets: ['@babel/preset-env'] }))
.pipe(dest("dist"))
);
};
const page = () => {
// src/**/*.html 匹配任意子目录
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.图片和字体文件的转换
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)
5.其他文件清除
const del = require("del")
// 清除文件
const clean = () => {
// del 返回的是个 promise
return del(["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 = {
compile,
build
}
6.自动加载插件
安装 gulp-load-plugins
const loadPlugins = require("gulp-load-plugins");
const plugins = loadPlugins();
//sass 修改为plugins.sass
7. 开发服务器
browser-sync安装
const browserSync = require('browser-sync')
const bs = browserSync.create()
const serve = () => {
bs.init({
notify: false,
port: 2080,
// open: false,
files: 'dist/**',
server: {
baseDir: 'dist',
routes: {
'/node_modules': 'node_modules'
}
}
})
}
8. 监视变化以及构建优化
watch
考虑如何在src原代码修改后自动编译
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/**',// 监听 dist 文件变化刷新
server: {
baseDir: ['dist', 'src', 'public'],
routes: {
'/node_modules': 'node_modules'
}
}
})
}
// 并行执行 样式-脚本-页面 编译
const compile = parallel(style, script, page)
//上线之前执行的任务
const build = series(clean,parallel(compile,image, font,extra))
const develop = series(compile, serve)
module.exports = {
clean,
compile,
build,
serve,
develop
}
9. useref文件引用处理
gulp-useref 根据构建注释构建css,js 路径
目前存在的一些问题:
- dist中的index.html文件为例。引用的node_modules的文件目录,部署上线后,会找不到对应的目录
- 未使用useref时文件内容 dist中的index.html部分内容
<!-- build:css assets/styles/vendor.css -->
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css">
<!-- endbuild -->
<!-- build:css assets/styles/main.css -->
<link rel="stylesheet" href="assets/styles/main.css">
<!-- endbuild -->
gulpfile.js文件
const useref = () => {
return src('dist/*.html', { base: 'dist' })
.pipe(plugins.useref({ searchPath: ['dist', '.'] }))
// html js css
.pipe(dest('dist'))
}
使用后
<link rel="stylesheet" href="assets/styles/vendor.css">
<link rel="stylesheet" href="assets/styles/main.css">
10. 文件压缩
- gulp-htmlmin 压缩 HTML 文件
- gulp-uglify 压缩 JS 文件
- gulp-clean-css 压缩 CSS 文件
- gulp-if 判断文件类型
const useref = () => {
return src('dist/*.html', { base: 'dist' })
.pipe(plugins.useref({ searchPath: ['dist', '.'] }))
// 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'))
}
11.重新规划合理的构建过程
- 添加临时文件 tmp 避免读写流冲突(不能读写都是dist 文件)
const { src, dest, parallel, series, watch } = require("gulp");
const del = require("del")
const browserSync = require("browser-sync");
const loadPlugins = require("gulp-load-plugins");
const plugins = loadPlugins();
const bs = browserSync.create()
// const sass = require("gulp-sass");
// const babel = require('gulp-babel')
// const swig = require("gulp-swig");
// const imagemin = require("gulp-imagemin")
const data = {
menus: [
{
name: "Home",
icon: "aperture",
link: "index.html",
},
{
name: "Features",
link: "features.html",
},
{
name: "About",
link: "about.html",
},
{
name: "Contact",
link: "#",
children: [
{
name: "Twitter",
link: "https://twitter.com/w_zce",
},
{
name: "About",
link: "https://weibo.com/zceme",
},
{
name: "divider",
},
{
name: "About",
link: "https://github.com/zce",
},
],
},
],
pkg: require("./package.json"),
date: new Date(),
};
// 清除文件
const clean = () => {
// del 返回的是个 promise
return del(["dist","temp"]);
};
// scss 转 css
const style = () => {
// 指定从 src 下保留路径
return (
src("src/assets/styles/*.scss", { base: "src" })
// sass对_icons.css,默认不编译
.pipe(plugins.sass({ outputStyle: "expanded" }))
.pipe(dest("temp"))
);
};
const script = () => {
// 指定从 src 下保留路径
return (
src("src/assets/scripts/*.js", { base: "src" })
// ES6+ 处理 注意这里要提供 babel 预设, 不然就不转换
.pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
.pipe(dest("temp"))
.pipe(bs.reload({ stream: true }))
);
};
const page = () => {
// src/**/*.html 匹配任意子目录
return src("src/*.html", { base: "src" })
.pipe(plugins.swig({data }))
.pipe(dest("temp"));
};
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 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 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'))
}
// 并行执行 样式-脚本-页面 编译
const compile = parallel(style, script, page)
//上线之前执行的任务
const build = series(clean,parallel(series(compile, useref),image, font,extra))
const develop = series(compile, serve)
module.exports = {
clean,
compile,
build,
serve,
develop,
useref
}
12.问题
导出可用任务,并放到scripts中
module.exports = {
clean,
build,
develop
}
package.json
{
"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",
"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
13. 封装自动化构建工作流
gulpfile.js复用
- 创建一个模块,将模块发布npm,新项目使用npm
- 将gulpfile 中的代码替换到入口文件
- 将 gulpfile 完成项目中的 package.json 依赖拷入新 package.json 项目依赖(dependencies)
- 将模块 yarn link 到全局
- 在项目中使用link的模块
- 提取公共配置文件
6 FIS
FIS是百度的前端团队推出的构建系统,FIS相对于前两种微内核的特点,它更像是一种捆绑套餐,它把我们的需求都尽可能的集成在内部了,例如资源加载、模块化开发、代码部署、甚至是性能优化
- 基本使用
yarn global add fis3
执行fis3 release
查看效果
- 创建 fis-conf.js
fis.match('*.{js,scss,png}', {
release: '/assets/$0'
})
fis.match('**/*.scss', {
rExt: '.css',
parser: fis.plugin('node-sass'),
optimizer: fis.plugin('clean-css')
})
fis.match('**/*.js', {
parser: fis.plugin('babel-6.x'),
optimizer: fis.plugin('uglify-js')
})