自動化構(gòu)建02

常用的自動化構(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)問題的時候可以參考

https://gitee.com/lagoufed/fed-e-questions/blob/master/part2/%E4%B8%8B%E8%BD%BD%E5%8C%85%E6%98%AF%E5%87%BA%E9%94%99%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E5%BC%8F.md

 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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容