- 将源代码编译成在线上环境运行的过程
- 优势:
- 编码阶段可以使用最新语法,提高开发效率
- 例如使用sass编写css,使用NPM scripts定义命令
- 常用的自动化构建工具
- Grunt:项目大的时候构建速度慢,基于磁盘读写
- Gulp:基于内存实现,默认同时执行多个任务
- FIS
Grunt
- yarn add grunt
- 创建gruntfile.js
// gruntfile.js 是grunt的入口
// 用于定义一些需要grunt 自动执行的任务
module.exports = grunt => {
// 默认任务
//grunt.registerTask('default', () => {
//
//})
grunt.registerTask('default',[ 'foo', 'bar'])
grunt.registerTask('foo', () => {
})
grunt.registerTask('bar', () => {
})
// 异步操作
grunt.registerTask('async-task', function() {
const done = this.async()
setTimeout(()=>{
done()
},1000)
})
}
Grunt标记任务失败
module.exports = grunt => {
grunt.registerTask('bar', () => {
return false
})
grunt.registerTask('async-task', function() {
const done = this.async()
setTimeout(()=>{
done(false)
},1000)
})
}
//-- force 强制后面任务执行
Grunt配置选项方法
module.exports = grunt => {
grunt.initConfig({
foo: {
bar: 123
}
})
grunt.registerTask("foo",() => {
console.log(grunt.config('foo.bar'))
})
}
Grunt多目标任务
module.exports = grunt => {
grunt.initConfig({
build: {
options:{
foo: 'bar'
},
css: {
options: {
foo: 'baz' // 会覆盖上面的值
}
},
js: ''
}
})
// 多目标模式,可以让任务根据配置形成多个子任务
grunt.registerMultiTask('build', function () {
console.log(this.options())
console.log(`target: ${this.target}, data: ${this.data}`)
})
}
Grunt插件的使用
// 封装了通用的构建任务
// grunt-contrib-clean 清除文件
module.exports = grunt => {
grunt.initConfig({
clean:{
temp: 'temp/**' // "temp/*.txt"
}
})
grunt.loadNpmTasks('grunt-contrib-clean')
}
Grunt常用插件
grunt-sass
// yarn add grunt-sass 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')
}
grunt-babel
load-grunt-tasks
// yarn add grunt-babel @babel/core @babel/preset-env --dev
// yarn add load-grunt-tasks --dev
const loadGruntTasks = require('load-grunt-tasks')
module.exports = grunt => {
grunt.initConfig({
babel:{
options: {
presets: ['@babel/preset-env'],
sourceMap: true
}
main:{
files: {
"dist/js/app.js": 'src/js/app.js'
}
}
}
})
loadGruntTasks(grunt) // 自动加载所有的grunt插件中的任务
}
grunt-contrib-watch
module.exports = grunt => {
grunt.initConfig({
watch:{
options: {
presets: ['@babel/preset-env'],
sourceMap: true
}
js: {
files: ['src/js/*.js'],
tasks: ['babel']
},
css: {
files: ['src/scss/*.scss'],
tasks: ['sass']
}
}
})
loadGruntTasks(grunt) // 自动加载所有的grunt插件中的任务
grunt.registerTask('default',['sass','babel','watch'])
}
Gulp
- yarn init 初始化package.json
- yarn add gulp —dev
- 创建gulpfile.js 入口文件
exports.foo = done => {
conosle.log('foo task working')
done() // 标识任务完成
}
// gulp foo
export.default = done => {
console.log('default task')
done()
}
// 直接运行 gulp
// gulp4.0之前需要先引入gulp
const gulp = require('gulp')
gulp.task('bar', done => {
console.log("bar task")
done()
})
Gulp组合任务
const { series, parallel } = require('gulp')
const task1 = done => {
setTimeout(() => {
console.log('task1')
done()
}, 1000)
}
const task2 = done => {
setTimeout(() => {
console.log('task1')
done()
}, 1000)
}
const task3 = done => {
setTimeout(() => {
console.log('task1')
done()
}, 1000)
}
exports.foo = series(task1, task2, task3)// 按顺序进行
exports.bar = parallel(task1, task2, task3) // 同时进行
Gulp中的异步任务
// done
exports.callback_error = done => {
done(new Error('task failed'))
}
exports.promise = () => {
return Promise.resolve()
}
exports.promise_error = () => {
return Promise.reject()
}
const timeout = time => {
return new Promise( resolve => {
setTimeout(resolve, time)
})
}
exports.async = async () => {
await timeout(1000)
}
// 这种方式看node版本支不支持async await
exports.stream = () => {
const readStream = fs.createReadStream('package.json')
const writeStream = fs.createWriteStream('temp.txt')
readStream.pipe(writeStream)
return readStream
}
// stream 中end事件触发结束任务
exports.stream = done => {
const readStream = fs.createReadStream('package.json')
const writeStream = fs.createWriteStream('temp.txt')
readStream.pipe(writeStream)
readStream.on('end', () => {
done()
})
}
Gulp构建过程核心工作原理
const fs = require('fs')
const { Transform } = require('stream')
exporta.default = () => {
const read = fs.createReadStream('normalize.css')
const write = fs.createWriteStream('normalize.min.css')
// 文件转换流
const transform = new Transform({
// 核心转换过程实现
// chunk 读取流中读取到的内容(Buffer)
const input = chunk.toString()
const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')
callback(null, output)
})
read.pipe(transform).pipe(write)
}
// gulp是基于文件流的构建方式
Gulp文件操作API + 插件的使用
const { src, dest } = require('gulp')
const cleanCss = require('gulp-clean-css')
const rename = require('gulp-rename')
export.default = () => {
return src('src/*.css')
.pipe(cleanCss())
.pipe(rename({ extname: '.min.css' }))
.pipe(dest('dist'))
}
Gulp案例
// yarn add gulp --dev
// 项目根目录新建gulpfile.js文件
const { src, dest, parallel, series } = require('gulp')
// 自动加载插件
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
//const sass = require('gulp-sass')
//const babel = require('gulp-babel') // 需要安装@babel/core @babel/preset-env
//const swig = require('gulp-swig')
//const imagemin = require('gulp-imagemin')
//const del = require('del')
const style = () => {
return src('src/assets/styles/*.scss', { base: 'src' })// 保留原本目录结构
.pipe(plugins.sass({ outputStyle: 'expanded' }))
.pipe(dest('temp'))
.pipe(fs.reload({ stream: true })) // 与bs配置中的files属性用途类似
}
const script = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
.pipe(dest('temp'))
}
const page = () => {
return src('src/**/*.html', { base: 'src' })
.pipe(plugins.swig( { data, cache: false } )) // 将模板需要的数据导入
.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 clean = () => {
return del(['dist','temp'])
}
const compile = parallel(style, script, page, image, font)
const build = series(clean, parallel(compile, extra))
module.exports = {
build
}
Gulp配置开发热更新服务器
// browsersync
const { watch } = require('gulp')
const browsersync = require("browser-sync")
const bs = browsersync.create()
const server = () => {
// 监听src源代码的变化
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({
server: {
notify: false,
port: 8080,
open: true,
//files: 'temp/**', // 用来被监听的文件
baseDir: ['temp','src','public'],
routes: {
'/node_modules': 'node_modules'
}
}
})
}
module.exports = {
server
}
Gulp文件引用处理 useref
// 将html中的build:css等构建注释的地方转换
// yarn add gulp-useref --dev
const useref = () => {
return src('temp/*.html', { base: 'dist' })
.pipe(plugins.useref({ searchPath: ['dist', '.'] }))
// html js css 压缩 gulp-htmlmin gulp-uglify gulp-clean-css gulp-if
.pipe(plugins.if(/\.js$/, plugins.uglify()))
.pipe(plugins.if(/\.html$/, plugins.htmlmin({ collapseWhitespace: true, minifyCss: true, minifyJs: true }))) // style script 标签中代码压缩
.pipe(plugins.if(/\.css$/, plugins.cleanCss()))
.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,
build,
develop
}
- 可以将构建命令放到package.json的scripts中