1. Introduction to automated builds
Introduction to the
- Automate the conversion of our source code into production code.
- This process of transformation is called the automated build flow
- Out-of-runtime compatibility issues
- Use efficient syntax, specifications, and standards in your development environment
- Such as:
- ESMAScript Next
- Sass
- Template engines (most of these uses are not directly supported by browsers)
- Use build tools to transform unsupported “features”
For example
- sass.scss –> css
# download sass
npm i sass
# to perform
./node_modules/.bin/sass sass/main.scss css/style.css
NPM Scripts can be used
"scripts": {
"build": "sass sass/main.scss css/style.css"
}
Copy the code
- Using NPM Scripts is the simplest way to automate the build workflow
// browser-sync is used to start a test server to run our project
scrips: {
"preserve": "npm run build"// This command is automatically executed before serving similar to Pre hook
"serve": "browser-sync ."
}
// --watch
// To execute multiple commands, use the 'npm-run-all' module
// With this module
scripts: {
"start": "run-p build"."serve" // Run build and serve at the same time
}
// This can be done with serve
scrips: {
"serve": "browser-sync . --files \"css/*.css\"" // This will automatically synchronize the changed CSS to the browser
}
Copy the code
Common automated build tools
- Grunt
- Gulp
- FIS
Note: Webpack is a module packaging tool
2. Use of Grunt
1. Basic use of Grunt
- npm init
- npm i grunt
- increase
gruntfile.js
(Grunt entry file)
// Grunt entry file
// Users define tasks that Grunt automatically performs
// A function needs to be exported
// This function takes a grunt parameter and provides some API that can be used to create tasks
module.exports = grunt= > {
grunt.registerTask('foo'.() = > {
console.log('hello grunt! ')
})
grunt.registerTask('bar'.'Task Description'.() = > {
console.log('other task! ')})// YARN grunt executes the default task by default
// grunt.registerTask('default', () => {
// console.log('default task')
// })
// So you can do this
grunt.registerTask('default'['foo'.'bar']);
// Asynchronous operation
grunt.registerTask('async-task'.function () {
const done = this.async()
setTimeout(() = > {
console.log('async task workding~');
done();
}, 1000); })}Copy the code
1.1 Failed to mark the Grunt task
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. Use YARN grunt default. If bad ends and fails, bar does not run
// 2. Use yarn grunt default --force
grunt.registerTask('default'['foo'.'bad'.'bar'])
/ / asynchronous
grunt.registerTask('bad-async'.function () {
const done = this.async()
setTimeout(() = > {
console.log('bad async')
done(false)},1000)})}Copy the code
2. Grunt configuration method
module.exports = grunt= > {
grunt.initConfig({
// foo: 'bar'
foo: {
bar: 123
}
})
grunt.registerTask('foo'.() = > {
// console.log(grunt.config('foo'))
console.log(grunt.config('foo.bar'))})}Copy the code
3. Grunt Multi-objective missions
module.exports = grunt= > {
grunt.initConfig({
build: {
// The configured key will be the following this.target value will be this.data note, except options
options: { // appears as a configuration option for the task
foo: 'bar'
},
// CSS: '1', // can also be objects
css: {
options: { // This will replace the configuration in build options
foo: 'bar-css'}},js: '2'}})// Multi-target mode allows tasks to form multiple sub-tasks according to configuration
grunt.registerMultiTask('build'.function() {
console.log(`build task -- target:The ${this.target}, data: The ${this.data}`)})}Copy the code
4. Use of the Grunt plugin
- For example,
grun-contrib-clean
Automatic cleanup of temporary files that we automatically generated during project development - use
loadNpmTasks
Load the plug-in - perform
yarn grunt clean
module.exports = grunt= > {
grunt.initConfig({
clean: {
// temp: 'temp/app.js', // app.js in the temp directory
// Wildcard characters can also be used
temp: 'temp/*.txt'
}
})
grunt.loadNpmTasks('grunt-contrib-clean')}// Use YARN grunt clean to delete temp/app.js
Copy the code
4.1 Common Grunt plug-ins
grunt-sass
sass
grunt-babel
@babel/core
@babel/preset-env
grunt-contrib-watch
Monitoring file changes
const sass = require('sass')
const loadGruntTasks = require('load-grunt-tasks')
module.exports = grunt= > {
grunt.initConfig({
sass: {
// Need to add otions
options: {
sourceMap: true.// This can be added according to the error message
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'] // Tasks that need to be performed when changes are detected
},
css: {
files: ['src/scss/*.scss'].tasks: ['sass']}}})// grunt.loadNpmTasks('grunt-sass')
// Too many tasks are loaded, which can be handled by the community load-grunt- Tasks module
loadGruntTasks(grunt)
// Yarn grunt watch Does not execute tasks under watch immediately
// So make a mapping
grunt.registerTask('default'['sass'.'babel'.'watch'])}Copy the code
3. Gulp
1. Basic use of Gulp
- The streaming build system can be used to build The streaming system
Core features: high efficiency, easy to use
// Gulp entry lets you speak
//$ yarn gulp foo
exports.foo = done= > {
console.log('this is foo task working~');
done() // Indicate that the task is complete
}
//$ yarn gulp
exports.default = done= > {
console.log('default task working~');
done()
}
Before 4.0, registering gulp tasks required methods in the gulp module.
// It is not recommended to use it
const gulp = require('gulp')
gulp.task('bar'.done= > {
console.log('bar working ~');
done();
})
Copy the code
2. Combined tasks of Gulp
series
Creating a serial taskparallel
Creating parallel Tasks
const { series, parallel } = require('gulp')
// Unexported tasks are treated as private tasks
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); // Create a serial task
exports.bar = parallel(task1, task2, task3); // Create parallel tasks
Copy the code
3. Gulp asynchronous tasks (three ways)
- The callback function
- Promise
- async await
// 1. Callback function
exports.callback = done= > {
console.log('callback task~')
done()
}
// Node's callback function is a standard, which is called error first callback function
exports.callback_error = done= > {
console.log('callback_error task~')
done(new Error('task failed:')) // Can block subsequent work execution
}
// 2. Gulp supports promises
exports.promise = () = > {
console.log('promise task~')
return Promise.resolve() // resolve does not need an argument because Gulp ignores this value
}
exports.promise_error = () = > {
console.log('promise_error task~')
return Promise.reject(new Error('task failed:')) // resolve does not need an argument because Gulp ignores this value
}
// 3. Node environment above 8, mainly supports async await
const timeout = time= > {
return new Promise(resolve= > {
setTimeout(resolve, time)
})
}
exports.async = async() = > {await timeout(1000)
console.log('async task~');
}
// In addition to the above three types, there are some similar ones in gulp
const fs = require('fs')
/ / file stream
exports.stream = done= > {
const readStream = fs.createReadStream('package.json')
const writeStream = fs.createWriteStream('temp.txt')
readStream.pipe(writeStream)
// return readStream // as follows
readStream.on('end'.() = > {
done()
})
}
Copy the code
4. Core working principle of Gulp construction process
- Input – Reads the stream
- Processing – conversion flow
- Output – write to the stream
5. Gulp file operation 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()) // Add gulp-rename as an example
.pipe(rename({extname: '.min.css'}))
.pipe(dest('dist'))}// gulp-clean-css // Compress the CSS conversion stream
Copy the code
4. Gulp
1. Style, script, page template compilation
1.1 Style Compilation
Reference code github.com/zce/zce-gul…
const { src, dest } = require('gulp')
const sass = require('gulp-sass')
// 1. Style compilation
const style = () = > {
//, options.base is the base path
return src('src/assets/styles/*.scss', { base: 'src' })
//sass can pass parameters
//.pipe(sass()) // sass is a plug-in for converting streams
.pipe(sass({ outputStyle: 'expanded' }))
.pipe(dest('dist'))}module.exports = {
style
}
Copy the code
1.2. Script compilation
const { src, dest } = require('gulp')
const babel = require('gulp-babel')
// 2. Script compile 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
}
Copy the code
1.3. Page template compilation
const { src, dest } = require('gulp')
const swig = require('gulp-swig')
// 3. Page templates are compiled using the swig template engine
const data = {} // Fill in the template structure, only the name is replaced here
const page = () = > {
return src('src/*.html', { base: 'src' })
.pipe(swig({ data: data }))
.pipe(dest('dist'))}module.exports = {
page
}
Copy the code
1.4 Combine the three
Create parallel tasks using PARALLEL
const { src, dest, parallel } = require('gulp')
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const swig = require('gulp-swig')
// 1. Style compilation
const style = () = > {
//, options.base is the base path
return src('src/assets/styles/*.scss', { base: 'src' })
//sass can pass parameters
//.pipe(sass()) // sass is a plug-in for converting streams
.pipe(sass({ outputStyle: 'expanded' }))
.pipe(dest('dist'))}// 2. Script compile 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. Page templates are compiled using the swig template engine
const data = {} // Fill in the template structure, only the name is replaced here
const page = () = > {
return src('src/*.html', { base: 'src' })
.pipe(swig({ data: data }))
.pipe(dest('dist'))}// Combine the three tasks
const compile = parallel(style, script, page)
module.exports = {
compile
}
Copy the code
2. Picture and font file conversion
// 4. Use gulp-imagemin to convert images
const image = () = > {
return src('src/assets/images/**', { base: 'src' })
.pipe(imagemin())
.pipe(dest('dist'))}// 5. Fonts for SVG are also images
const font = () = > {
return src('src/assets/fonts/**', { base: 'src' })
.pipe(imagemin())
.pipe(dest('dist'))}Copy the code
3. Other files and file removal
- Clear installation del
yarn add del -D
const { src, dest, parallel, Series} = require('gulp') const del = require('del') const clean = () => {return del(['dist']) Const compile = parallel(style, script, page, image, font) const build = series(clean, parallel(compile, extra))Copy the code
4. Automatically load plug-ins
gulp-load-plugins
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins() // use gulp-sass. If gulp-sass-dev is gulp-sass-dev, it becomes plugins.sassdev
// When used in tasks, the following is an example
// 1. Style compilation
const style = () = > {
//, options.base is the base path
return src('src/assets/styles/*.scss', { base: 'src' })
//sass can pass parameters
//.pipe(sass()) // sass is a plug-in for converting streams
// This is replaced by plugins.sass
// Note that when the plugin is named gulp-sass-xxx, it is plugins.sassxxx
.pipe(plugins.sass({ outputStyle: 'expanded' }))
.pipe(dest('dist'))}Copy the code
5. Development server
yarn add browser-sync -D
const browserSync = require('browser-sync')
const bs = browserSync.create()
// 7. Create a serve task
const serve = () = > {
bs.init({
notify: false.// This is a successful connection message in the upper right corner of the browser
port: 2080./ / port
// open: false, // Whether to open the browser by default
files: 'dist/**'.// Listen on the file below dist, automatically synchronize to the browser after modification
server: {
baseDir: 'dist'.routes: {
'/node_modules': 'node_modules' Have a direct reference node_modules / / dist inside HTML inside the bootstrap/dist/CSS/bootstrap CSS so here to add a map}}})}Copy the code
Monitor changes and build optimizations
- use
gulp
In thewatch
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) // For these three types of files, there is no need to compile them during development, just reload them
[dist", "SRC ", "public"] [dist", "dist", "dist"]
// if baseDir is an array, dist will be searched first, SRC will be searched if it is not found, and so on
Copy the code
- Note in bs.init({files: ‘dist/**’})
This file can be removed without listening, and then used in the task via.pipe(bs.reload({stream: true})). Stream: true: in stream mode
// 1. Style compilation
const style = () = > {
//, options.base is the base path
return src('src/assets/styles/*.scss', { base: 'src' })
//sass can pass parameters
//.pipe(sass()) // sass is a plug-in for converting streams
.pipe(plugins.sass({ outputStyle: 'expanded' }))
.pipe(dest('dist'))
.pipe(bs.reload({ stream: true}}))Copy the code
7. Useref file reference processing
There are reference comments in HTML
-
Since the mapping of node_modules was added before and the CSS file in node_modules was used, the HTML file of the packaged dist has the path referring to node_modules
-
Using useref
<! -- This is in packing up dist, because it needs to be handled -->
<! -- 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 -->
Copy the code
// Create useref task
const useref = () = > {
return src('dist/*.html', { base: 'dist' })
.pipe(plugins.useref( { searchPath: ['dist'.'. '] } ))
.pipe(dest('dist'))}Copy the code
8. File compression
gulp-htmlmin
gulp-uglif
gulp-clean-css
gulp-if
const useref = () = > {
return src('dist/*.html', { base: 'dist' })
.pipe(plugins.useref( { searchPath: ['dist'.'. ']}))// There are three types of files here. To compress HTML, JS and CSS, you need to download three compression plug-ins
.pipe(plugins.if(/\.js$/, plugins.uglify()))
.pipe(plugins.if(/\.css$/, plugins.cleanCss())) //
.pipe(plugins.if(/\.html$/, plugins.htmlmin(
{
collapseWhitespace: true.// Whitespace characters
minifyCSS: true./ / compress CSS
minifyJS: true / / scripts
}
)))
.pipe(dest('temp')) // There is dist package and temp package
}
Copy the code
9. Redesign the build process
- Generate packages for
dist
Temporary package calledtemp
Need to make some adjustments in the code
/ / for
// 1. Style compilation
const style = () = > {
//, options.base is the base path
return src('src/assets/styles/*.scss', { base: 'src' })
//sass can pass parameters
//.pipe(sass()) // sass is a plug-in for converting streams
.pipe(plugins.sass({ outputStyle: 'expanded' }))
.pipe(dest('temp')) // Change it here
.pipe(bs.reload({stream: true}}))// 2. Script compile 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')) // Change it here
.pipe(bs.reload({stream: true}}))// And so on
Copy the code
10. Build tasks into modules
- Let’s take the task to be
package.json
In thescripts
中
{
"scripts": {
"clean": "gulp clean"."build": "gulp build"."develop": "gulp develop"}}Copy the code
// Extract tasks to expose only common ones
module.exports = {
clean,
build,
develop
}
Copy the code
11. Encapsulate workflows
Gulpfile
+Gulp
=Build workflow
Gulpfile
+Gulp CLI
=Workflow module (EG: ZCE-Pages)
- Convention specific configuration files are similar to vue. Config. js. Here we can have a pages.config.js
- Use closed workflows for local debugging
npm link
Put it in the global context