常用的自動化構(gòu)建工具 Grunt Gulp FIS

image.png
-
Grunt
yarn init --yes 添加package.json
yarn add grunt 添加grunt模塊
code gruntfile.js 添加gruntfile文件 (Grunt 的入口文件,用于定義一些需要Grunt自動執(zhí)行的任務)使用
// Grunt 的入口文件
// 用于定義一些需要Grunt自動執(zhí)行的任務
/**
* 需要導出一個函數(shù)
* 次函數(shù)接收一個grunt的形參,內(nèi)部提供一些創(chuàng)建任務時候可以用到的API
*
*/
module.exports = grunt => {
// 使用registerTask 注冊一個任務
grunt.registerTask('foo', () => {
console.log('hello grunt 測試');
})
grunt.registerTask('bar', '任務描述', () => {
console.log('第二個參數(shù)是當前任務的描述');
})
// grunt.registerTask('default',() => {
// console.log('默認任務,調(diào)用不需要指定人物名');
// })
// grunt.registerTask('default', ['foo', 'bar']); //默認同時執(zhí)行兩個任務
grunt.registerTask('asyncTask', () => {
setTimeout(() => {
console.log('grunt 默認支持同步任務當前寫法不打印');
}, 1000);
})
grunt.registerTask('asyncTask1', function () {
const done = this.async();
setTimeout(() => {
console.log('grunt 異步 需要使用this,所以不使用箭頭函數(shù),當done()被執(zhí)行,grunt才會結(jié)束任務');
done();
}, 1000);
})
}
yarn grunt <任務名> 執(zhí)行
- Grunt標記任務失敗
grunt.registerTask('foo', () => {
console.log('hello grunt 測試');
return false;
})
grunt.registerTask('bad', () => {
console.log('hello grunt 測試');
})
grunt.registerTask('far', () => {
console.log('hello grunt 測試');
})
grunt.registerTask('default', ['bad', 'foo','far']);
grunt.registerTask('fooAsync', () => {
const done = this.async();
setTimeout(() => {
console.log('grunt 異步 需要使用this,所以不使用箭頭函數(shù),當done()被執(zhí)行,grunt才會結(jié)束任務');
done(false);
}, 1000);
})
當任務里有return false,后面的語句將都不會執(zhí)行;
當運行yarn grunt default --force ,即使運行失敗了,后面也會執(zhí)行
異步任務標記失敗,需要在done()中傳遞實參false,既done(false)
- Grunt 配置方法
grunt.initConfig({
foo:{
bar:123
},
red:132
})
grunt.registerTask('init-config', () => {
console.log(grunt.config('foo.bar'));
console.log(grunt.config('red'));
})
- Grunt 多任務
module.exports = grunt => {
grunt.initConfig({
build: {
options: { //配置選項
foo: "bar"
},
css: '1',
js: '2',
vue: {
options: { //配置選項
foo: "baz";//會覆蓋原有的配置項
},
}
}
})
// 多目標模式,可以讓任務根據(jù)配置形成多個子任務
grunt.registerMultiTask('build', function () {
console.log(this.options()); //可以獲取配置選項
console.log(`target:${this.target},data:${this.data}`); //target:css,data:1; target:js,data:2
})
}
- Grunt 插件的使用
安裝插件
yarn add grunt-contrib-clean
gruntfile.js
module.exports = grunt =>{
grunt.initConfit({
clean:{
temp:'temp/***'
}
})
grunt.loadNpmTasks('grunt-contrib-clean')
}
- Grunt 常用插件及總結(jié)
sass的基本使用
yarn add grunt-sass sass --dev
gruntfile.js
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");
};
//執(zhí)行
yarn grunt sass
es6語法編譯器
yarn add grunt-babel @babel/core @babel/preset-env --dev
減少loadNpmTasks的使用
yarn add load-grunt-tasts --dev
const loadGruntTasks = require("load-grunt-tasks");
module.exports = (grunt) => {
grunt.initConfig({
babel: {
options: {
presets: ["@babel/preset-env"],
},
main: {
files: {
"dist/js/app.js": "src/js/app.js",
},
},
},
});
loadGruntTasks(grunt); //自動加載所有的grunt插件中的任務
};
//執(zhí)行任務
yarn grunt babel
自動編譯插件
yarn add grunt-contrib-watch --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: {
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");
loadGruntTasks(grunt); //自動加載所有的grunt插件中的任務
grunt.registerTask("default", ["sass", "babel", "watch"]);
// 運行 yarn grunt
};
-
Gulp 的基本使用
yarn init --yes 添加package.json
yarn add gulp --dev 添加gulp 模塊
code gulpfile.js 添加gulpfile文件 (gulp 的入口文件,用于定義一些需要gulp 自動執(zhí)行的任務)使用
gulpfile.js
// glup 入口文件
exports.foo = (done)=>{
console.log('foo task working')
done();//標識任務完成
}
exports.default = (done)=>{ //默認執(zhí)行任務不需要帶名字
console.log('default task working')
done();//標識任務完成
}
// 不推薦這種方式
const gulp = require('gulp')
gulp.task('bar',done=>{
console.log('bar working');
done();
})
- Gulp 的組合任務
// glup 入口文件
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);// series自動按照順序自動執(zhí)行任務
exports.bar = parallel(task1,task2,task3) // parallel 并行執(zhí)行任務
執(zhí)行 yarn gulp foo
執(zhí)行 yarn gulp bar

image.png
- Gulp 的異步任務
// glup 入口文件
const fs = require('fs');
exports.callback = done =>{
console.log('callback task~');
done();
}
exports.callback_error = done =>{
console.log('callback task~');
done(new Error('task failed!')); //錯誤信息
}
exports.promise =()=>{
console.log('promise task!');
return Promise.resolve();
}
exports.promise_error =()=>{
console.log('promise task!');
return Promise.reject(new Error('task failed!'));
}
const timeout = time=>{
return new Promise(resolve=>{
setTimeout(resolve,time)
})
}
exports.async = async()=>{
await timeout(1000)
console.log('async task~');
}
exports.stream = ()=>{
const readStream = fs.createReadStream('package.json')
const writeStream = fs.createWriteStream('temp.txt')
readStream.pipe(writeStream)
return readStream
}
exports.stream_end = (done)=>{
const readStream = fs.createReadStream('package.json')
const writeStream = fs.createWriteStream('temp2.txt')
readStream.pipe(writeStream)
readStream.on('end',()=>{
console.log('OK!');
done();
})
}
- Gulp 構(gòu)建過程核心工作原理
const fs = require('fs')
const {Transform} = require('stream')
exports.default = ()=>{
// 讀取文件流
const read = fs.createReadStream('normalize.css')
// 文件寫入流
const write = fs.createWriteStream('normalize.min.css')
// 文件轉(zhuǎn)換流
const transform = new Transform({
transform:(chunk,encoding,callback)=>{
// 核心轉(zhuǎn)換過程
// chunk ==>讀取流中的內(nèi)容(Buffer)
const input = chunk.toString();
const output = input.replace(/\s+/g,'').replace(/\/\*.+?\*\//g,'')
callback(null,output)
}
})
// 把讀取數(shù)來的文件流倒入寫入文件流
read.pipe(transform).pipe(write)
return read;
}
- Gulp 文件操作API
壓縮轉(zhuǎn)換css流
yarn add gulp-clean-css --dev
后綴重命名
yarn add gulp-rename --dev
const { src, dest } = require("gulp");
const cleanCss = require("gulp-clean-css"); //壓縮css插件
const rename = require("gulp-rename"); //重命名的擴展名
exports.default = () => {
// return src("src/index.css").pipe(dest("dist"));
return src("src/*.css")
.pipe(cleanCss())
.pipe(rename({ extname: ".min.css" }))
.pipe(dest("dist"));
};
- Gulp 案例-樣式編譯
yarn add gulp --dev // 安裝gulp
code gulpfile.js //新建gulpfile.js 入口文件
yarn add gulp-sass sass --dev //安裝sass 依賴
- Gulp 案例- 腳本編譯
yarn add gulp-babel @babel/core @babel/preset-env --dev //安裝babel 依賴
- Gulp 案例- 頁面模板編譯
yarn add gulp-swig --dev //安裝swig依賴
- Gulp 案例 - 其他文件及文件清除
yarn add gulp-imagemin@7 --dev 安裝壓縮圖片依賴
因為依賴包里面有二進制文件,這些二進制文件不好下載,所以當下在包出現(xiàn)問題的時候可以參考
yarn add del --dev //安裝清除模塊
- Gulp 案例 - 自動加載插件
yarn add gulp-load-plugins --dev
- Gulp 案例- 開發(fā)服務器
yarn add browser-sync --dev //會提供給我們一個開發(fā)服務器
- Gulp 案例- 監(jiān)視變化以及構(gòu)建優(yōu)化
watch("src/assets/styles/*.scss", style);
watch("src/assets/scripts/*.js", script);
watch("src/*.html", page);
watch(
["src/assets/styles/*.scss", "src/assets/scripts/*.js", "src/*.html"],
bs.reload
); //優(yōu)化上面寫法
- Gulp 案例- useref文件引用處理
yarn add gulp-useref --dev //下載插件
- Gulp 案例 - 文件壓縮
yarn add gulp-htmlmin gulp-uglify gulp-clean-css --dev //下載壓縮html js css 插件
yarn add gulp-if --dev //判斷文件類型的插件
// 實現(xiàn)這個項目的構(gòu)建任務
const { src, dest, parallel, series, watch } = require("gulp");
const del = require("del"); //引入del
const browserSync = require("browser-sync"); //引入服務器browserSync
const loadPlugins = require("gulp-load-plugins"); //引入自動加載模塊
const plugins = loadPlugins();
const bs = browserSync.create(); //創(chuàng)建一個服務器
const sass = require("gulp-sass")(require("sass")); //引入gulp-sass
// const babel = require("gulp-babel"); //引入gulp-babel
// const swig = require("gulp-swig"); //引入swig
// const imagemin = require("gulp-imagemin"); //引入gulp-imagemin 壓縮圖片和svg
const style = () => {
// base:基本路徑,保存src下面的文件結(jié)構(gòu)
// outputStyle:'expanded' css中{ } 完全展開
return src("src/assets/styles/*.scss", { base: "src" })
.pipe(sass({ outputStyle: "expanded" }))
.pipe(dest("temp"))
.pipe(bs.reload({ stream: true })); //自動以流的方式推送到瀏覽器bs.reload({ stream: true })
};
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 })); //自動以流的方式推送到瀏覽器bs.reload({ stream: true })
};
const data = {
menus: [
{
name: "Home",
icon: "aperture",
link: "index.html",
},
{
name: "About",
link: "about.html",
},
{
name: "Contact",
link: "#",
children: [
{
name: "Twitter",
link: "https://twitter.com/w_zce",
},
],
},
],
// pkg: require("./package.json"),
date: new Date(),
};
const page = () => {
// src/**/*.html **下面所有的*.html文件
return src("src/*.html", { base: "src" })
.pipe(
plugins.swig({
data,
defaults: {
// 可能會因為swig模板引擎緩存機制導致頁面不變化 所以修改為false 不緩存
cache: false,
},
})
)
.pipe(dest("temp"))
.pipe(bs.reload({ stream: true })); //自動以流的方式推送到瀏覽器bs.reload({ stream: true })
};
// 圖片轉(zhuǎn)換
const image = () => {
return src("src/assets/images/**", { base: "src" })
.pipe(plugins.imagemin())
.pipe(dest("dist"));
};
// 文字轉(zhuǎn)換
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 = () => {
// del方法返回的是pormise 會標記任務結(jié)束
return del(["dist", "temp"]);
};
// 創(chuàng)建服務器的相關(guān)配置
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/styles/*.scss", "src/assets/scripts/*.js", "src/*.html"],
bs.reload
); //優(yōu)化上面寫法
bs.init({
notify: false, //瀏覽器右上角提示
port: 2021, //端口
// open:false,//是否自動打開瀏覽器
//當什么文件發(fā)生變化時候刷新頁面 為路徑
// 當.pipe(bs.reload({stream:true})); 存在可以省略files
// files: "dist/**",
server: {
baseDir: ["temp", "src", "public"],
routes: {
"/node_modules": "node_modules", //映射里面引用的node_module里面js等css的引用
},
},
});
};
// 文件引用處理
const useref = () => {
return (
src("temp/*.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"))
);
};
// 組合任務
const compile = parallel(style, script, page);
const develop = series(compile, serve); //先進性編譯樣式腳本頁面,然后在啟動服務器
// 上線之前執(zhí)行的任務
const build = series(
clean,
parallel(series(compile, useref), image, font, extra)
);
module.exports = {
clean,
build,
develop,
};
總結(jié)--流程
安裝并且引入gulp yarn add gulp
安裝并且引入gulp-sass yarn add gulp-sass sass --dev 用于轉(zhuǎn)換sass
安裝并且引入babel yarn add gulp-babel @babel/core @babel/preset-env --dev 用于編譯js
安裝并且引入swig yarn add gulp-swig --dev 用于頁面模板編譯
安裝并且引入imagemin yarn add gulp-imagemin@7 --dev 用于壓縮圖片svg
安裝并引入del yarn add del --dev 用于清空刪除
安裝并引用自動加載插件 yarn add gulp-load-plugins --dev 替換之前引入的sass 為plugins.sass 等
安裝一個服務器插件 yarn add browser-sync --dev 用于創(chuàng)建啟動一個服務器
安裝一個useref文件處理器 yarn add gulp-useref --dev
下載壓縮html js css 插件 yarn add gulp-htmlmin gulp-uglify gulp-clean-css --dev
判斷文件類型的插件 yarn add gulp-if --dev
最終整理組合任務為 清空clean 啟動服務器develop 打包 build
運行分別方式為 yarn gulp clean
運行方式為 yarn gulp develop
運行方式為 yarn gulp build
可以配置package.json 的scripts為
"clean": "gulp clean",
"build": "gulp build",
"develop": "gulp develop",
后運行方式分別為 yarn clean
后運行方式分別為 yarn develop
后運行方式分別為 yarn build