Skip to content

自动化构建

自动化构建

源代码 -> 生成代码

前端样式自动化构建

输入 scss scss/main.scss css/style.css 即可构建出 css

  • 缺点:每次都需要重复输入这个复杂的命令

    npm script 就是用来解决这个问题

    json
    {
      "scripts": {
        "build": "sass scss/main.scss css/style.css --watch",
      },
    }

接下来安装 browser-sync 用于启动测试服务器

bash
yarn add browser-sync --dev

运行测试服务器 npm run serve

  • --files 监听文件变化
json
{
  "scripts": {
    "serve": "browser-sync . --files \"css/*.css\"
  },
}

不过这里可能有个问题,如果在运行测试服务器之前,没有生成 css,浏览器就没办法展示样式

  • 这里就可以用到 npm script 的钩子机制 preserve 在启动任务之前,让 build 先去工作
json
{
  "scripts": {
    "preserve": "yarn build"
  },
}

如果给 build 增加 --watch 参数,scss 会阻塞命令行等待文件变化,就会导致 browser-sync 没办法直接去工作

  • 这里就需要用 npm-run-all 同时执行多个命令

    bash
    yarn add npm-run-all --dev
json
{
  "scripts": {
    "start": "run-p build serve"
  },
}

常用工具

  • 严格来说 Webpack 是模块打包工具
  • Grunt、Gulp、FIS 是自动化构建工具

常用自动化构建工具

  • Grunt 老牌构建工具,插件生态完善,但是它的工作过程是基于临时文件实现的,所以构建速度较慢(Scss 编译后就会将结果写入到临时文件,下一个插件读取这个临时文件进行操作,环节越多读取文件次数越多)
  • Gulp 基于内存实现的,对文件的处理都是在内存中实现,速度快一些,默认同时支持多个任务,目前比较流行
  • FIS 百度团队研发,把项目中最典型需求都集成到内部,大而全

Grunt

基本使用

bash
yarn init –yes
yarn add grunt

新建 gruntfile.js

  • Grunt 的入口文件,用于定义一些需要 Grunt 自动执行的任务
  • 需要导出一个函数,该函数接收一个 grunt 对象,内部提供一些创建任务可以用到的 API
js
module.exports = grunt => {
  grunt.registerTask('foo', '任务描述', () => {
    console.log('foo')
  })
  grunt.registerTask('bar', () => {
    console.log('bar')
  })
  // 第二个参数可以指定此任务的映射任务
  // 这样执行 default 就相当于执行对应的任务
  // 这里映射的任务会按顺序依次执行,不会同步执行
  grunt.registerTask('default', ['foo', 'bar'])
  // 由于函数体中需要使用 this,所以这里不能使用箭头函数
  grunt.registerTask('async-task', function () {
    const done = this.async()
    setTimeout(() => {
      console.log('async task working~')
      done()
    }, 1000)
  })
}

标记任务失败

  • 任务函数执行过程中如果返回 false,则意味着此任务执行失败

  • 如果一个任务列表中的某个任务执行失败,则后续任务默认不会运行

    除非 grunt 运行时指定 --force 参数强制执行

  • 异步函数中标记当前任务执行失败的方式是为回调函数指定一个 false 的实参

js
module.exports = grunt => {
  grunt.registerTask('bad', () => {
    console.log('bad working~')
    return false
  })
  grunt.registerTask('foo', () => {
    console.log('foo working~')
  })
  grunt.registerTask('bar', () => {
    console.log('bar working~')
  })
  grunt.registerTask('default', ['foo', 'bad', 'bar'])
  grunt.registerTask('bad-async', function () {
    const done = this.async()
    setTimeout(() => {
      console.log('async task working~')
      done(false)
    }, 1000)
  })
}

配置选项方法

init 配置,用 grunt.config 获取属性值

js
module.exports = grunt => {
  grunt.initConfig({
    foo: {
      bar: 123,
    },
  })
  grunt.registerTask('foo', () => {
    console.log(grunt.config('foo.bar'))
  })
}

多目标任务

init 配置,通过 this 拿到执行的名称和数据

js
module.exports = grunt => {
  // 多目标模式,可以让任务根据配置形成多个子任务
  grunt.initConfig({
    build: {
      options: {
        msg: 'task options',
      },
      foo: {
        options: {
          msg: 'foo target options',
        },
      },
      bar: '456',
    },
  })
  grunt.registerMultiTask('build', function () {
    console.log(this.options())
    console.log(`target:${this.target},data:${this.data}`)
  })
}

Grunt 插件

安装 grunt-contrib-clean

bash
yarn add grunt-contrib-clean --dev

将 temp 目录下所有文件都清除

bash
module.exports = grunt => {
  grunt.initConfig({
    clean: {
      temp: 'temp/**',
    },
  })

  grunt.loadNpmTasks('grunt-contrib-clean')
}

安装 grunt-sasssass

bash
yarn add grunt-sass sass --dev

安装 grunt-babalbabel

bash
yarn add grunt-babel @babel/core @babel/preset-env --dev

随着 gruntfile.js 越来越复杂,loadNpmTasks 操作也会越来越多,可以使用 load-grunt-tasks

bash
yarn add load-grunt-tasks --dev

当文件修改完,需要自动去编译,这时需要另外一个插件 grunt-contrib-watch

bash
yarn add grunt-contrib-watch --dev

Grunt 使用插件

js
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: {
        sourceMap: true,
        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'],
      },
    },
  })

  loadGruntTasks(grunt) // 自动加载所有 grunt 插件中的任务
  grunt.registerTask('default', ['sass', 'babel', 'watch'])
}

Gulp

基本使用

Gulp 核心特点:高效易用

  • 安装 Gulp 同时会自动安装一个叫 gulpcli 模块
bash
yarn init --yes
yarn add gulp --dev

创建 gulpfile.js 入口,导出一个 foo 函数

js
exports.foo = () => {
  console.log('foo task working~')
}

执行 yarn gulp foo,发现有报错

  • gulp 取消了同步代码模式,约定每一个任务都是异步的,当任务执行完需要通过回调函数标记任务执行完毕
bash
[11:04:54] The following tasks did not complete: foo
[11:04:54] Did you forget to signal async completion?
error Command failed with exit code 1.

gulp 4.0 以后的保留了 gulp.task API

  • gulp 4.0 以后推荐使用导出函数成员方式
js
exports.foo = done => {
  console.log('foo task working~')
  done() // 标识任务执行完成
}

// default 是默认任务
exports.default = done => {
  console.log('default task working~')
  done()
}

// v4.0 之前需要通过 gulp.task() 方法注册任务
const gulp = require('gulp')
gulp.task('bar', done => {
  console.log('bar task working~')
  done()
})

组合任务

通过 seriesparallel 组合多个任务

  • 编译 CSS、JS 任务互不干扰可以并行处理
js
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)

异步任务

  1. 回调函数
  2. Promsie、async 和 await(Node 8 以上的版本)
  3. Stram 方式
js
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) // pipe导入写入流中
  // gulp 只是注册了 end 事件去结束
  /* readStream.on('end', () => {
    done()
  }) */
  return readStream
}

核心工作原理

  • The streaming build system

stream 的 Transform 类型可以创建文件转换流对象,里面需要指定 transform 属性(转化流核心转换过程)

js
const fs = require('fs')
const { Transform } = require('stream')

exports.default = () => {
  // 文件读取流
  const readStream = fs.createReadStream('normalize.css')
  // 文件写入流
  const writeStream = fs.createWriteStream('normalize.min.css')
  // 文件转换流
  const transformStream = new Transform({
    // 核心转换过程
    transform: (chunk, encoding, callback) => {
      const input = chunk.toString()
      const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')
      callback(null, output)
    },
  })

  return readStream
    .pipe(transformStream) // 转换
    .pipe(writeStream) // 写入
}

Gulp核心工作原理

文件操作 API

bash
yarn add gulp-clean-css --dev
yarn add gulp-rename --dev

通过 src 去 pipe 到插件转换流,再去 pipe 到写入流的过程就是使用 gulp 常规过程

js
const { src, dest } = require('gulp')
const cleanCSS = require('gulp-clean-css')
const rename = require('gulp-rename')

exports.default = () => {
  return src('src/*.css')
    .pipe(cleanCSS())
    .pipe(rename({ extname: '.min.css' }))
    .pipe(dest('dist'))
}

Gulp 案例

样式编译

下载代码

bash
git clone https://github.com/zec/zec-gulp-demo.git

安装 gulpgulp-sass

  • 安装 gulp-sass 会安装 node-sass(是 C++ 模块),内部会有对 C++ 程序集的依赖,二进制包需要国外站点去下载,有时会下载不下来,可以配置淘宝镜像源下载
yarn add gulp --dev
yarn add gulp-sass --dev
js
const { src, dest } = require('gulp')
const sass = require('gulp-sass')

const style = () => {
  return src(`src/assets/styles/*.scss`, { base: 'src' })
    .pipe(sass({ outputStyle: 'expanded' }))
    .pipe(dest('dist'))
}

module.exports = {
  style,
}

脚本编译

安装 gulp-babel@babel/core@babel/preset-env

bash
yarn add gulp-babel --dev
yarn add @babel/core @babel/preset-env --dev
js
const { src, dest } = require('gulp')
const babel = require('gulp-babel')

const script = () => {
  return src(`src/assets/scripts/*.js`, { base: 'src' })
    .pipe(babel({ presets: ['@babel/preset-env'] }))
    .pipe(dest('dist'))
}

module.exports = {
  script,
}

页面模板编译

安装 gulp-swig

bash
yarn add gulp-swig --dev
js
const { src, dest, parallel } = require('gulp')
const swig = require('gulp-swig')

const data = {
  menus: [
    {
      name: 'Home',
      icon: 'aperture',
      link: 'index.html',
    },
    {
      name: 'Features',
      link: 'features.html',
    },
    {
      name: 'About',
      link: 'about.html',
    },
    {
      name: 'Contact',
      link: '#',
      children: [
        {
          name: 'Twitter',
          link: 'https://twitter.com/w_zce',
        },
        {
          name: 'About',
          link: 'https://weibo.com/zceme',
        },
        {
          name: 'divider',
        },
        {
          name: 'About',
          link: 'https://github.com/zce',
        },
      ],
    },
  ],
  pkg: require('./package.json'),
  date: new Date(),
}

const page = () => {
  return src(`src/**/*.html`, { base: 'src' }).pipe(swig({ data })).pipe(dest('dist'))
}

const compile = parallel(style, script, page)

module.exports = {
  compile
}

图片和字体文件的转换

安装 gulp-imagemin

  • 内部依赖的模块也是通过 C++ 模块,需要下载二进制程序集(大部分 GitHub 下载),但是这个没办法配置镜像
bash
yarn add gulp-imagemin --dev
js
const { src, dest, parallel } = require('gulp')
const imagemin = require('gulp-imagemin')

const image = () => {
  return src(`src/assets/images/**`, { base: 'src' }).pipe(imagemin()).pipe(dest('dist'))
}

const font = () => {
  return src(`src/assets/fonts/**`, { base: 'src' }).pipe(imagemin()).pipe(dest('dist'))
}

const compile = parallel(style, script, page, image, font)

module.exports = {
  compile
}

其它文件及文件清除

安装 del

bash
yarn add del --dev
js
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))

module.exports = {
  build,
}

自动加载插件

安装 gulp-load-plugins

bash
yarn add gulp-load-plugins --dev
js
const { src, dest, parallel, series } = require('gulp')
const del = require('del')
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()

const data = {...}

const clean = () => {
  return del(['dist'])
}

const style = () => {
  return src(`src/assets/styles/*.scss`, { base: 'src' })
    .pipe(plugins.sass({ outputStyle: 'expanded' }))
    .pipe(dest('dist'))
}

const script = () => {
  return src(`src/assets/scripts/*.js`, { base: 'src' })
    .pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
    .pipe(dest('dist'))
}

const page = () => {
  return src(`src/**/*.html`, { base: 'src' }).pipe(plugins.swig({ data })).pipe(dest('dist'))
}

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 compile = parallel(style, script, page, image, font)

const build = series(clean, parallel(compile, extra))

module.exports = {
  build,
}

热更新开发服务器

安装 browser-sync

bash
yarn add browser-sync --dev
  • 编译过程中并没有处理 node_modules 模块下面的拷贝

    可以给 browser-sync 增加一个单独的路由(routes),这个路由优先级比 baseDir

js
const browserSync = require('browser-sync')

const bs = browserSync.create()

const serve = () => {
  bs.init({
    notify: false,
    port: 2080,
    // open: false,
    files: 'dist/**',
    server: {
      baseDir: 'dist',
      routes: {
        '/node_modules': 'node_modules',
      },
    },
  })
}

module.exports = {
  serve,
}

监听变化及构建优化

  • stylescriptpage 文件改变可以 .pipe(bs.reload({ stream: true }))

    这样 files: 'dist/**' 就不需要了

js
const { src, dest, parallel, series, watch } = require('gulp')

const style = () => {
  return src(`src/assets/styles/*.scss`, { base: 'src' })
    .pipe(plugins.sass({ outputStyle: 'expanded' }))
    .pipe(dest('dist'))
    .pipe(bs.reload({ stream: true }))
}

const script = () => {
  return src(`src/assets/scripts/*.js`, { base: 'src' })
    .pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
    .pipe(dest('dist'))
    .pipe(bs.reload({ stream: true }))
}

const page = () => {
  return src(`src/**/*.html`, { base: 'src' })
    .pipe(plugins.swig({ data }))
    .pipe(dest('dist'))
    .pipe(bs.reload({ stream: true }))
}

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/images/**', 'src/assets/fonts/**', 'public/**'], bs.reload)

  bs.init({
    notify: false,
    port: 2080,
    // open: false,
    // files: 'dist/**',
    server: {
      baseDir: ['dist', 'src', 'public'],
      routes: {
        '/node_modules': 'node_modules',
      },
    },
  })
}

const compile = parallel(style, script, page)
const build = series(clean, parallel(compile, image, font, extra))
const develop = series(compile, serve)

useref 文件引用处理

有些文件依赖的是 node_modules 下的文件,这里并没有将其拷贝到 dist 目录,如果上线肯定找不到,本地能找到是因为做了路由映射

bash
yarn add gulp-useref --dev

构建注释

html
<!-- 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 -->
js
const useref = () => {
  return src('dist/*.html', { base: 'dist' })
    .pipe(plugins.useref({ searchPath: ['dist', '.'] }))
    .pipe(dest('dist'))
}

分别压缩 HTML、CSS、JS

  • 另外还需要判断对不同文件的操作,这个时候就需要一个额外的插件去判断
bash
yarn add gulp-htmlmin gulp-uglify gulp-clean-css --dev
yarn add gulp-if --dev

操作时会发现 main.css 没有内容,这时因为文件读写冲突,一边读一边写

  • 可以把最终转换的结果放在其他目录中
js
const useref = () => {
  return src('dist/*.html', { base: 'dist' })
    .pipe(plugins.useref({ searchPath: ['dist', '.'] }))
    .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('release'))
}

重新规划构建过程

useref 打破了我们的目录结构

  • 打包上线是 dist 目录,而 useref 把目录改成了 release

增加临时目录 temp

  1. scriptstylepage 放到 temp 目录
  2. imagefontextra 不需要改,这三个只需要 build 时候去做,只有被 useref 影响才需要
  3. serve 里的 baseDir 需要改为 temp
  4. useref src 从 temp 里取,把结果放到 dist 目录里
js
const { src, dest, parallel, series, watch } = require('gulp')
const del = require('del')
const browserSync = require('browser-sync')
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
const bs = browserSync.create()

const clean = () => {
  return del(['dist', 'temp'])
}

const style = () => {
  return src('src/assets/styles/*.scss', { base: 'src' })
    .pipe(plugins.sass({ outputStyle: 'expanded' }))
    .pipe(dest('temp'))
    .pipe(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 }))
}

const page = () => {
  return src('src/*.html', { base: 'src' })
    .pipe(plugins.swig({ data, defaults: { cache: false } })) // 防止模板缓存导致页面不能及时更新
    .pipe(dest('temp'))
    .pipe(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 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/images/**',
    'src/assets/fonts/**',
    'public/**'
  ], bs.reload)

  bs.init({
    notify: false,
    port: 2080,
    // open: false,
    // files: 'dist/**',
    server: {
      baseDir: ['temp', 'src', 'public'],
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

const useref = () => {
  return src('temp/*.html', { base: 'temp' })
    .pipe(plugins.useref({ searchPath: ['temp', '.'] }))
    // 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 build =  series(
  clean,
  parallel(
    series(compile, useref),
    image,
    font,
    extra
  )
)
const develop = series(compile, serve)

module.exports = {
  clean,
  build,
  develop
}

构建完这套系统,如果你不想写文档说明,导出几个常用即可,cleanbuilddevelop

  • 并在 package.json 中增加 script 命令
json
"scripts": {
  "clean": "gulp clean",
  "build": "gulp build",
  "develop": "gulp develop"
},

封装工作流

提取多个项目共同的自动化构建过程(Don't repeat yourself)

gulp自动化工作流构建

提取 gulpfile

zce-gulp-demo 这里叫 A,zce-pages 这里叫 B

  • 在命令行输入 code . -a 在同一窗口打开这个项目

把 A 项目工作流提取到 B 项目中,操作步骤如下:

  1. 把 A 的 gulpfile.js 内容复制到 B 的 lib/index.js
  2. 把 A 的 package.json 中的 devDependencies 复制到 B 中 dependencies
  3. 把 A 的 package.json 中的 devDependencies 全部删除,并把 node_modules 全部删除
  4. 把 B link 到全局,切换到 A 输入命令 yarn link zce-pages,B 项目会通过软链接形式链过来
  5. 在 B 中新建 gulpfile.js 新增 module.exports = require('zce-pages') 内容
  6. 执行 yarn build

执行 yarn build 我这边报错了,是因为 gulp-sass 没有下载下来

bash
Error in plugin "gulp-sass"
Message:

gulp-sass no longer has a default Sass compiler; please set one yourself.
Both the "sass" and "node-sass" packages are permitted.

解决:安装 sass

bash
yarn add sass

修改 lib/index.js

js
const sass = require('gulp-sass')(require('sass'))

const style = () => {
  return src('src/assets/styles/*.scss', { base: 'src' })
    .pipe(sass({ outputStyle: 'expanded' }))
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }))
}

抽象路径配置

对于代码里写死的路径,如 sass 的路径,这样不是很灵活,我们可以抽象一下形成配置

  • cwd 返回命令行工作目录,然后拿到工作文件 pages.config.js

    require 不存在的目录会报错,所以这里用 try...catch... 包裹一下

js
const cwd = process.cwd()
let config = {
  build: {
    src: 'src',
    dist: 'dist',
    temp: 'temp',
    public: 'public',
    paths: {
      styles: 'assets/styles/*.scss',
      scripts: 'assets/scripts/*.js',
      pages: '*.html',
      images: 'assets/images/**',
      fonts: 'assets/fonts/**'
    }
  }
}

try {
  const loadConfig = require(`${cwd}/pages.config.js`)
  config = Object.assign({}, config, loadConfig)
} catch (e) {}

const style = () => {
  return src(config.build.paths.styles, { base: config.build.src, cwd: config.build.src })
    .pipe(sass({ outputStyle: 'expanded' }))
    .pipe(dest(config.build.temp))
    .pipe(bs.reload({ stream: true }))
}

包装 Gulp Cli

gulpfile.js 里只是写了个 module.exports = require('zce-pages'),其实有点冗余,我们希望没有 gulpfile.js 也能正常工作

  • 这里需要制定一下工作目录为当前
bash
yarn gulp build --gulpfile ./node_modules/zce-pages/lib/index.js --cwd .

不过这么多参数就很复杂了,可以集成 cli

  1. 创建 bin/zce-pages.js 作为 cli 执行入口

  2. package.json 中增加 bin 字段

    json
    "bin": "bin/zce-pages.js",

修改 zce-pages.js

  • process.argv 是一个数组
  • require 是载入这个模块,require.resolve 是找到这个模块所在的路径
js
#!/usr/bin/env node

process.argv.push('--cwd')
process.argv.push(process.cwd())
process.argv.push('--gulpfile')
process.argv.push(require.resolve('..'))

require('gulp/bin/gulp')

代码提交完,就可以使用 publish 提交 git

bash
yarn publish --registry https://registry.yarnpkg.com

同步时可能会有问题,因为你发布的是 npm 源,但是你是从淘宝源下载,可能会存在同步问题,可以进入淘宝镜像搜一下你 publish 的包,然后更新

总结

  1. 新建项目如果想要使用工作流,直接运行 package.json 中的命令即可

  2. 创建的 cli 是 node_modules/bin/zce-pages.cmd,这个文件中是通过 node 去执行 zce-pages/bin/zce-pages.js

  3. node_modules 找到 zce-pages/bin/zce-pages.js,里面就是告诉 gulp 工作时的工作目录和 gulpfile 的工作目录

    之后执行 gulp/bin/gulp 就可以执行 gulpifle 了,完成整个工作流过程

FIS

高度集成,只需要简单配置

bash
yarn global add fis3

relase 解决的资源定位

bash
fis3 realse -d output

新建 fis-conf.js

  • 编译与压缩

    安装 yarn add fis-parser-node-sassyarn add fis-parser-babel-6.x

js
fis.match('*.{js,scss,png}', {
  release: '/assets/$0',
})

fis.match('**/*.scss', {
  rExt: '.css',
  parser: fis.plugin('node-sass'),
  optimizer: fis.plugin('clean-css'),
})

fis.match('**/*.js', {
  parser: fis.plugin('babel-6.x'),
  optimizer: fis.plugin('uglify-js'),
})

查看转换过程中转换的配置

bash
fis3 inspect

常备不懈,才能有备无患