自动化构建02

常用的自动化构建工具 Grunt Gulp FIS
image.png
  • Grunt

yarn init --yes  添加package.json
yarn add grunt  添加grunt模块
code gruntfile.js 添加gruntfile文件  (Grunt 的入口文件,用于定义一些需要Grunt自动执行的任务)使用
// Grunt 的入口文件
// 用于定义一些需要Grunt自动执行的任务
/**
 * 需要导出一个函数
 * 次函数接收一个grunt的形参,内部提供一些创建任务时候可以用到的API
 * 
 */

module.exports = grunt => {
    // 使用registerTask 注册一个任务
    grunt.registerTask('foo', () => {
        console.log('hello grunt 测试');
    })
    grunt.registerTask('bar', '任务描述', () => {
        console.log('第二个参数是当前任务的描述');
    })
    // grunt.registerTask('default',() => {
    //     console.log('默认任务,调用不需要指定人物名');
    // })
    // grunt.registerTask('default', ['foo', 'bar']); //默认同时执行两个任务

    grunt.registerTask('asyncTask', () => {
        setTimeout(() => {
            console.log('grunt 默认支持同步任务当前写法不打印');
        }, 1000);
    })

    grunt.registerTask('asyncTask1', function () {
        const done = this.async();
        setTimeout(() => {
            console.log('grunt 异步 需要使用this,所以不使用箭头函数,当done()被执行,grunt才会结束任务');
            done();
        }, 1000);
    })
}
yarn grunt <任务名>   执行

  • 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,所以不使用箭头函数,当done()被执行,grunt才会结束任务');
         done(false);
      }, 1000);
})
当任务里有return false,后面的语句将都不会执行;
当运行yarn grunt default --force ,即使运行失败了,后面也会执行

异步任务标记失败,需要在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";//会覆盖原有的配置项
                },
            }
        }
    })

    // 多目标模式,可以让任务根据配置形成多个子任务
    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 常用插件及总结

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");
};


//执行
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插件中的任务
};


//执行任务
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 自动执行的任务)使用

gulpfile.js

// glup 入口文件

exports.foo = (done)=>{
    console.log('foo task working')
    done();//标识任务完成
}

exports.default = (done)=>{  //默认执行任务不需要带名字
    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自动按照顺序自动执行任务
exports.bar = parallel(task1,task2,task3) // parallel 并行执行任务
执行 yarn gulp foo
执行 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 构建过程核心工作原理
const fs = require('fs') 
const {Transform} = require('stream')


exports.default = ()=>{
    // 读取文件流
    const read = fs.createReadStream('normalize.css')
    // 文件写入流
    const write = fs.createWriteStream('normalize.min.css')

    // 文件转换流
    const transform = new Transform({
        transform:(chunk,encoding,callback)=>{
            // 核心转换过程
            // chunk ==>读取流中的内容(Buffer)
            const input = chunk.toString();
            const output = input.replace(/\s+/g,'').replace(/\/\*.+?\*\//g,'')
            callback(null,output)
        }
    })

    // 把读取数来的文件流倒入写入文件流
    read.pipe(transform).pipe(write)

    return read;
}
  • Gulp 文件操作API

压缩转换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   安装压缩图片依赖

因为依赖包里面有二进制文件,这些二进制文件不好下载,所以当下在包出现问题的时候可以参考

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 案例- 开发服务器
yarn add browser-sync --dev   //会提供给我们一个开发服务器
  • Gulp 案例- 监视变化以及构建优化
 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
  ); //优化上面写法
  • 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  //判断文件类型的插件
// 实现这个项目的构建任务
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(); //创建一个服务器

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下面的文件结构
  //   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 })
};

// 图片转换
const image = () => {
  return src("src/assets/images/**", { base: "src" })
    .pipe(plugins.imagemin())
    .pipe(dest("dist"));
};

// 文字转换
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   会标记任务结束
  return del(["dist", "temp"]);
};

// 创建服务器的相关配置
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
  ); //优化上面写法
  bs.init({
    notify: false, //浏览器右上角提示
    port: 2021, //端口
    // open:false,//是否自动打开浏览器
    //当什么文件发生变化时候刷新页面  为路径
    // 当.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); //先进性编译样式脚本页面,然后在启动服务器

// 上线之前执行的任务
const build = series(
  clean,
  parallel(series(compile, useref), image, font, extra)
);

module.exports = {
  clean,
  build,
  develop,
};

总结--流程

安装并且引入gulp       yarn add gulp
安装并且引入gulp-sass  yarn add gulp-sass sass --dev    用于转换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   用于创建启动一个服务器
安装一个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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容