我是靠谱客的博主 曾经皮卡丘,最近开发中收集的这篇文章主要介绍前端自动化构建-Grunt、Gulp、FIS1. 自动化构建简介2. Grunt 的使用3. Gulp4. Gulp 案例,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
1. 自动化构建简介
简介
- 就是将我们的源代码自动化的去转换成生产代码。
- 这个转换的过程我们称之为自动化构建流
- 脱离运行环境兼容带来的问题
- 在开发环境使用提高效率的语法、规范和标准
- 比如:
- ESMAScript Next
- Sass
- 模板引擎 (这些用法大都不被浏览器直接支持)
- 使用构建工具转换那些不被支持的『特性』
举例说明
- sass.scss --> css
# 下载sass
npm i sass
# 执行
./node_modules/.bin/sass sass/main.scss css/style.css
# 可以使用 NPM Scripts
"scripts": {
"build": "sass sass/main.scss css/style.css"
}
- 使用 NPM Scripts是实现自动化构建工作流的最简方式
// browser-sync 用于启动一个测试服务器来运行我们的项目
scrips: {
"preserve": "npm run build"// 这个命令是在 serve 之前是会自动执行 类似pre hook
"serve": "browser-sync ."
}
// --watch
// 想执行多个命令可以使用 `npm-run-all` 模块
// 有了这个模块之后
scripts: {
"start": "run-p build", "serve" // 同时执行 build 和 serve
}
// 在serve的命令下可以这样
scrips: {
"serve": "browser-sync . --files "css/*.css"" // 加了这个之后会自动把改变后的css同步到浏览器
}
常用的自动化构建工具
- Grunt
- Gulp
- FIS
注意: Webpack 属于模块打包工具
2. Grunt 的使用
1. Grunt的基本使用
- npm init
- npm i grunt
- 增加
gruntfile.js
(grunt的入口文件)
// Grunt 的入口文件
// 用户定义一些需要 Grunt 自动执行的任务
// 需要导出一个函数
// 此函数接收一个 grunt 的形参,内部提供一些创建任务时可以用到的API
module.exports = grunt => {
grunt.registerTask('foo', () => {
console.log('hello grunt!')
})
grunt.registerTask('bar', '任务描述', () => {
console.log('other task!')
})
// yarn grunt 会默认执行 default 任务
// grunt.registerTask('default', () => {
// console.log('default task')
// })
// 因此 可以这样
grunt.registerTask('default', ['foo', 'bar']);
// 异步操作
grunt.registerTask('async-task',function () {
const done = this.async()
setTimeout(() => {
console.log('async task workding~');
done();
}, 1000);
})
}
1.1 Grunt标记任务失败
module.exports = grunt => {
grunt.registerTask('bad', () => {
console.log('bad workding')
return false
})
grunt.registerTask('foo', () => {
console.log('foo task')
})
grunt.registerTask('bar', () => {
console.log('bar task')
})
// 1. 使用 yarn grunt default 当bad结束后 失败,则 bar不会执行
// 2. 使用 yarn grunt default --force
grunt.registerTask('default', ['foo', 'bad', 'bar'])
// 异步的
grunt.registerTask('bad-async', function () {
const done = this.async()
setTimeout(() => {
console.log('bad async')
done(false)
}, 1000)
})
}
2. Grunt 的配置方法
module.exports = grunt => {
grunt.initConfig({
// foo: 'bar'
foo: {
bar: 123
}
})
grunt.registerTask('foo', () => {
// console.log(grunt.config('foo'))
console.log(grunt.config('foo.bar'))
})
}
3. Grunt 多目标任务
module.exports = grunt => {
grunt.initConfig({
build: {
// 配置的key都会成为 下面 this.target 值成为this.data 注意,除了 options
options: { // 作为任务的配置选项出现
foo: 'bar'
},
// css: '1', // 也可以是对象
css: {
options: { // 这里会将替换build的options里面的配置
foo: 'bar-css'
}
},
js: '2'
}
})
// 多目标模式, 可以让任务根据配置形成多个子任务
grunt.registerMultiTask('build', function() {
console.log(`build task -- target:${this.target}, data: ${this.data}`)
})
}
4. Grunt 插件的使用
- 举例
grun-contrib-clean
自动清除我们在项目开发过程中自动生成的临时文件 - 使用
loadNpmTasks
加载插件 - 执行
yarn grunt clean
module.exports = grunt => {
grunt.initConfig({
clean: {
// temp: 'temp/app.js', // temp目录下的app.js
// 也可以使用通配符
temp: 'temp/*.txt'
}
})
grunt.loadNpmTasks('grunt-contrib-clean')
}
// 使用 yarn grunt clean 将会把temp/app.js删除掉
4.1 Grunt 常用插件
grunt-sass
sass
grunt-babel
@babel/core
@babel/preset-env
grunt-contrib-watch
监控文件更改
const sass = require('sass')
const loadGruntTasks = require('load-grunt-tasks')
module.exports = grunt => {
grunt.initConfig({
sass: {
// 需要添加otions
options: {
sourceMap: true,
// 没有这个可以根据报错信息的提示添加
implementation: sass
},
main: {
files: {
'dist/css/main.css': 'src/scss/main.scss'
}
}
},
babel: {
options: {
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']
}
}
})
// grunt.loadNpmTasks('grunt-sass')
// 加载的任务过多,可以通过社区的 load-grunt-tasks 模块来处理
loadGruntTasks(grunt)
// yarn grunt watch 执行后并不会立马执行 watch下的任务
// 因此做个映射
grunt.registerTask('default', ['sass', 'babel', 'watch'])
}
3. Gulp
1. Gulp的基本使用
- The streaming build system 基于流的构建系统
核心特点: 高效、易用
// gulp 的入口让你说的
//$ yarn gulp foo
exports.foo = done => {
console.log('this is foo task working~');
done() // 标识任务完成
}
//$ yarn gulp
exports.default = done => {
console.log('default task working~');
done()
}
// 在4.0以前,在注册gulp任务时是需要gulp模块里面的方法去实现的。
// 具体来看 如下,但是不推荐使用了
const gulp = require('gulp')
gulp.task('bar', done => {
console.log('bar working ~');
done();
})
2. 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()
}, 1000)
}
exports.foo = series(task1, task2, task3); // 创建串行任务
exports.bar = parallel(task1, task2, task3); // 创建并行任务
3. Gulp 的异步任务(三种方式)
- 回调函数
- Promise
- async await
// 1. 回调函数
exports.callback = done => {
console.log('callback task~')
done()
}
// 以node的回调函数是一种标准,都是叫做错误优先的回调函数
exports.callback_error = done => {
console.log('callback_error task~')
done(new Error('task failed:')) // 可以阻绝后续工作执行
}
// 2. Gulp 支持 Promise
exports.promise = () => {
console.log('promise task~')
return Promise.resolve() // resolve不需要带参数,因为Gulp会忽略掉这个值
}
exports.promise_error = () => {
console.log('promise_error task~')
return Promise.reject(new Error('task failed:')) // resolve不需要带参数,因为Gulp会忽略掉这个值
}
// 3. node环境8以上,主要是支持 async await
const timeout = time => {
return new Promise(resolve => {
setTimeout(resolve, time)
})
}
exports.async = async () => {
await timeout(1000)
console.log('async task~');
}
// 除了以上3种,gulp里面有一些类似的
const fs = require('fs')
// 文件流
exports.stream = done => {
const readStream = fs.createReadStream('package.json')
const writeStream = fs.createWriteStream('temp.txt')
readStream.pipe(writeStream)
// return readStream //如同以下
readStream.on('end', () => {
done()
})
}
4. Gulp 构建过程核心工作原理
- 输入–读取流
- 加工–转换流
- 输出–写入流
5. Gulp 文件操作 API
const { src, dest } = require('gulp')
const cleanCss = require('gulp-clean-css')
const rename = require('gulp-rename')
exports.default = () => {
// return src('src/normalize.css').pipe(dest('dist'))
return src('src/*.css')
.pipe(cleanCss()) // 可以继续加 比如 gulp-rename
.pipe(rename({extname: '.min.css'}))
.pipe(dest('dist'))
}
// gulp-clean-css // 压缩css的转换流
4. Gulp 案例
1. 样式、脚本、页面模板编译
1.1 样式编译
参考代码 https://github.com/zce/zce-gulp-demo
const { src, dest } = require('gulp')
const sass = require('gulp-sass')
// 1. 样式编译
const style = () => {
// , options.base 是基准路径
return src('src/assets/styles/*.scss', { base: 'src' })
//sass 可以传参数
// .pipe(sass()) // sass 是转换流的插件
.pipe(sass({ outputStyle: 'expanded' }))
.pipe(dest('dist'))
}
module.exports = {
style
}
1.2. 脚本编译
const { src, dest } = require('gulp')
const babel = require('gulp-babel')
// 2. 脚本编译 gulp-babel @babel/core @babel/preset-env
const script = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(babel({ presets: ['@babel/preset-env'] }))
.pipe(dest('dist'))
}
module.exports = {
script
}
1.3. 页面模板编译
const { src, dest } = require('gulp')
const swig = require('gulp-swig')
// 3. 页面模板编译 使用了 swig 模板引擎
const data = {} // 按照模板内的结构填写好,这里只用名称代替了
const page = () => {
return src('src/*.html', { base: 'src' })
.pipe(swig({ data: data }))
.pipe(dest('dist'))
}
module.exports = {
page
}
1.4 将这三者组合起来
使用
parallel
创建并行任务
const { src, dest, parallel } = require('gulp')
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const swig = require('gulp-swig')
// 1. 样式编译
const style = () => {
// , options.base 是基准路径
return src('src/assets/styles/*.scss', { base: 'src' })
//sass 可以传参数
// .pipe(sass()) // sass 是转换流的插件
.pipe(sass({ outputStyle: 'expanded' }))
.pipe(dest('dist'))
}
// 2. 脚本编译 gulp-babel @babel/core @babel/preset-env
const script = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(babel({ presets: ['@babel/preset-env'] }))
.pipe(dest('dist'))
}
// 3. 页面模板编译 使用了 swig 模板引擎
const data = {} // 按照模板内的结构填写好,这里只用名称代替了
const page = () => {
return src('src/*.html', { base: 'src' })
.pipe(swig({ data: data }))
.pipe(dest('dist'))
}
// 将这3个任务组合起来
const compile = parallel(style, script, page)
module.exports = {
compile
}
2. 图片和字体文件转换
// 4. 图片转换 使用 gulp-imagemin
const image = () => {
return src('src/assets/images/**', { base: 'src' })
.pipe(imagemin())
.pipe(dest('dist'))
}
// 5. 字体处理 svg的也是图片
const font = () => {
return src('src/assets/fonts/**', { base: 'src' })
.pipe(imagemin())
.pipe(dest('dist'))
}
3. 其它文件及文件清除
- 清除安装 del
yarn add del -D
const { src, dest, parallel, series } = require('gulp')
const del = require('del')
const clean = () => {
return del(['dist'])
}
// 修改一个build任务
// 将这3个任务组合起来
const compile = parallel(style, script, page, image, font)
const build = series(clean, parallel(compile, extra))
4. 自动加载插件
gulp-load-plugins
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins() // 使用这个 gulp-sass 如果是 gulp-sass-dev 会成为 plugins.sassDev
// 任务当中使用时为举例如下
// 1. 样式编译
const style = () => {
// , options.base 是基准路径
return src('src/assets/styles/*.scss', { base: 'src' })
//sass 可以传参数
// .pipe(sass()) // sass 是转换流的插件
// 这是换成 plugins.sass
// 注意 当插件命名为 gulp-sass-xxx 则为 plugins.sassXxx
.pipe(plugins.sass({ outputStyle: 'expanded' }))
.pipe(dest('dist'))
}
5. 开发服务器
yarn add browser-sync -D
const browserSync = require('browser-sync')
const bs = browserSync.create()
// 7. 创建serve 任务
const serve = () => {
bs.init({
notify: false, // 这个是浏览器打开后右上角有个 连接成功 的提示消息 ,这里设置为取消
port: 2080, // 端口
// open: false, // 是否默认打开浏览器
files: 'dist/**', // 监听dist下面的文件,发生修改后自动同步到浏览器上
server: {
baseDir: 'dist',
routes: {
'/node_modules': 'node_modules' // dist里面的html有直接引用node_modules里面的bootstrap/dist/css/bootstrap.css 所以这里加个映射
}
}
})
}
6. 监视变化以及构建优化
- 使用
gulp
中的watch
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) // 对于这三种文件, 在开发阶段不需要编译,只需要重新加载一下
// 需要注意的地方,当上面那三种文件没有编译到dist时,需要把bs.init中的server.baseDir更换成数组 ["dist", "src", "public"]
// baseDir 是一个数组,则会先在dist下找,找不到再往src下找,依次类推
- 注意在bs.init({files: ‘dist/**’})
这个files可以去掉,不监听,然后在任务里面通过
.pipe(bs.reload({ stream: true }))
来使用。stream: true
表示以流的方式
// 1. 样式编译
const style = () => {
// , options.base 是基准路径
return src('src/assets/styles/*.scss', { base: 'src' })
//sass 可以传参数
// .pipe(sass()) // sass 是转换流的插件
.pipe(plugins.sass({ outputStyle: 'expanded' }))
.pipe(dest('dist'))
.pipe(bs.reload({ stream: true }))
}
7. useref 文件引用处理
在html当中有引用注释
-
因为之前增加了node_modules的映射 使用了node_modules里面的css文件,所以打包出来的dist的html文件当中有引用node_modules的路径
-
使用
useref
<!-- 这是在打包好dist当中的,因为需要处理 -->
<!-- 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 -->
// 创建 useref 任务
const useref = () => {
return src('dist/*.html', { base: 'dist' })
.pipe(plugins.useref( { searchPath: ['dist', '.'] } ))
.pipe(dest('dist'))
}
8. 文件压缩
gulp-htmlmin
gulp-uglif
gulp-clean-css
gulp-if
const useref = () => {
return src('dist/*.html', { base: 'dist' })
.pipe(plugins.useref( { searchPath: ['dist', '.'] } ))
// 在这里会有三种文件类型 html js css 要压缩 需要下载3个压缩插件
.pipe(plugins.if(/.js$/, plugins.uglify()))
.pipe(plugins.if(/.css$/, plugins.cleanCss())) //
.pipe(plugins.if(/.html$/, plugins.htmlmin(
{
collapseWhitespace: true, // 空白字符
minifyCSS: true, // 压缩 css
minifyJS: true // 压缩 scripts
}
)))
.pipe(dest('temp')) // 这里出现了 dist包 和 temp 包 后续会统一调整
}
9. 重新规划构建过程
- 生成包为
dist
临时包叫temp
,需要将代码中的调整一下
// 举例
// 1. 样式编译
const style = () => {
// , options.base 是基准路径
return src('src/assets/styles/*.scss', { base: 'src' })
//sass 可以传参数
// .pipe(sass()) // sass 是转换流的插件
.pipe(plugins.sass({ outputStyle: 'expanded' }))
.pipe(dest('temp')) // 这里修改
.pipe(bs.reload({stream: true}))
}
// 2. 脚本编译 gulp-babel @babel/core @babel/preset-env
const script = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
.pipe(dest('temp')) // 这里修改
.pipe(bs.reload({stream: true}))
}
// 依次类推
10. 将构建任务提为模块
- 将任务提为
package.json
中的scripts
中
{
"scripts": {
"clean": "gulp clean",
"build": "gulp build",
"develop": "gulp develop"
}
}
// 将任务提取出来只暴露常用的
module.exports = {
clean,
build,
develop
}
11. 封装工作流
Gulpfile
+Gulp
=构建工作流
Gulpfile
+Gulp CLI
=工作流模块 (eg: zce-pages)
- 约定专一配置文件 类似 vue.config.js 这里我们可以来一个 pages.config.js
- 将封闭出来的工作流在本地调试时使用
npm link
放到全局上去
最后
以上就是曾经皮卡丘为你收集整理的前端自动化构建-Grunt、Gulp、FIS1. 自动化构建简介2. Grunt 的使用3. Gulp4. Gulp 案例的全部内容,希望文章能够帮你解决前端自动化构建-Grunt、Gulp、FIS1. 自动化构建简介2. Grunt 的使用3. Gulp4. Gulp 案例所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复