自动化构建
在开发网页应用的时候,经常会有一些需要在开发阶段去重复执行的命令
NPM Script是实现自动化构建工具流的最简单方式
- “build”: “sass scss/main.scss css/style.css --watch”,
npm script的preserve钩子机制,在执行yarn serve之前执行yarn build;
- “preserve”: "yarn build,
使用npm-run-all模块可以同时执行多个script任务;// npm install npm-run-all --save-dev
- “start”: “run-p build serve”
使用browser-sync模块可以启动一个本地服务器
- “serve”: “browser-sync”,
// package.json文件中
{
"name": "my-web-app",
"version": "0.1.0",
"main": "index.js",
"author": "xiapeng",
"license": "MIT",
"scripts": {
"build": "sass scss/main.scss css/style.css --watch",
// "preserve": "yarn build,
"serve": "browser-sync",
"start": "run-p build serve"
},
"devDependencies": {
"browser-sync": "^2.26.7",
"npm-run-all": "^4.1.5",
"sass": "^1.22.10"
}
}
常用的构建化自动工具: Grunt、Gulp、FIS
Grunt算是最早的前端构建系统,由于工作过程是基于临时文件的,构建速度会比较慢,每一步都会有磁盘读写操作,在大型项目中,处理的文件较多,会导致构建速度慢;Gulp是基于内存实现的,对于文件的处理都是在内存中处理的,支持同时处理多个文件,生态也比较完善;
Grunt
// 初始化package.json文件
yarn init --yes
// 下载grunt
yarn add grunt
// 运行grunt任务
yarn grunt 任务名
创建Task
创建单个任务:grunt.registerTask
-
grunt.registerTask(‘default’, [‘foo’, ‘bar’]) // 创建默认任务
-
grunt.task.run(‘foo’, ‘bar’) // foo 和 bar 会在当前任务执行完成过后自动依次执行
-
const done = this.async() // done()标记异步任务,异步函数任务中不能使用箭头函数
-
// 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) }) }
创建多目标任务:grunt.registerMultiTask
-
配置多目标任务时需要配置targets
-
grunt.initConfig({ ** })
-
子任务的options会覆盖父任务的options,可以在任务中通过this.options()来获取;
-
通过this.target来获取当前子任务名,通过this.data来获取当前子任务值;
-
module.exports = grunt => { // 多目标模式,可以让任务根据配置形成多个子任务 grunt.initConfig({ build: { options: { msg: 'task options' }, foo: { options: { msg: 'foo target options' } }, bar: '456' } }) grunt.registerMultiTask('build', function () { console.log(this.options()) console.log(this.target, this.data) }) }
Grunt插件
- 找到插件并安装;
- 通过grunt.loadNpmTasks方法将插件加载进来;
- 在grunt.initConfig中为任务添加配置选项;
module.exports = grunt => {
grunt.initConfig({
clean: {
temp: 'temp/**'
}
})
grunt.loadNpmTasks('grunt-contrib-clean')
}
常用插件
grunt-sass
yarn add grunt-sass sass --dev
yarn 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')
}
grunt-babel
yarn add grunt-babel @babel/core @babel/preset-env --dev
yarn grunt babel
- 随着任务插件越来越多,可以使用load-grunt-tasks插件来自动加载所有插件,这样就不用重复导入了;
- yarn add load-grunt-tasks --dev
- presets实际为你需要使用babel转换哪些特性,这里选择的是@babel/preset-env即根据最新的ES特性转换;
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'
}
}
},
watch: {
js: {
files: ['src/js/*.js'],
tasks: ['babel']
},
css: {
files: ['src/scss/*.scss'],
tasks: ['sass']
}
}
})
loadGruntTasks(grunt) // 自动加载所有的 grunt 插件中的任务
grunt.registerTask('default', ['sass', 'babel', 'watch'])
}
grunt-contrib-watch
yarn add grunt-contrib-watch --dev
yarn grunt watch
- 将所有的任务做一个映射到default任务上;
- grunt.registerTask(‘default’, [‘sass’, ‘babel’, ‘watch’])
watch: {
js: {
files: ['src/js/*.js'], // 监视的文件
tasks: ['babel'] // 监视文件更改后执行
},
css: {
files: ['src/scss/*.scss'],
tasks: ['sass']
}
}
grunt.registerTask('default', ['sass', 'babel', 'watch'])
Gulp
yarn add gulp --dev
新建gulpfile.js文件配置gulp
yarn gulp foo
- 最新版本的gulp默认所有的任务都是异步任务
- 接收一个done参数作为回调函数来标记任务结束
// // 导出的函数都会作为 gulp 任务
// exports.foo = () => {
// console.log('foo task working~')
// }
// gulp 的任务函数都是异步的
// 可以通过调用回调函数标识任务完成
exports.foo = done => {
console.log('foo task working~')
done() // 标识任务执行完成
}
// default 是默认任务
// 在运行是可以省略任务名参数
exports.default = done => {
console.log('default task working~')
done()
}
// v4.0 之前需要通过 gulp.task() 方法注册任务
const gulp = require('gulp')
gulp.task('bar', done => {
console.log('bar task working~')
done()
})
Gulp组合任务
series是串行任务,按照顺序执行;
parallel是并行任务,并发执行;
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()
<