如何去提取一个可复用的自动化构建工作流

419 阅读5分钟

前言

在日常开发中,我们开发多个同类型项目时,自动化构建流大致都是相同的。而我们需要在每个项目都去重复配置构建任务,所以针对此问题,我们去提取一个可复用的自动化工作流

☆ 主要考虑:gulpfile 复用的问题,对于gulpfile的配置可以去看gulp的基本使用方式,此文中提到的gulpfile配置都可以在上面找到

思路

通过我们创建一个模块,去包装一下gulp 以及gulpfile, 把自动化构建工作流包装到这个模块里面去。之后提供此模块去构建项目

准备工作

  • 创建一个模块,然后把这个模块发布到npm仓库上,最后在项目中使用
  • github上面创建一个仓库yp-gulp
  • 在本地创建一个新的目录文件,并yarn init --yes 初始化这个项目
  • 创建一个lib/index.js 作为这个模块的入口文件

提取gulpfile

  • 把gulpfile中的内容全部copy到 lib/index.js中
  • 在dependencies中加上gulpfile需要的依赖, 执行yarn去安装这些依赖
  • 开发阶段通过yarn link的方式把我们开发的模块link到全局
  • 之后我们根据这个模块运行时候的问题进行修改
  • 在需要构建的项目中,通过yarn link "yp-gulp"去使用这个模块
  • 因为yp-gulp模块导出的就是一个gulpfile,所以先在项目的 gulpfile.js中引入并导出这个模块module.exports = require('yp-gulp') (后面会对这个操作进行处理,暂时先这样写)
  • 在项目中执行yarn build 会发生报错 gulp: command not found, 这个地方我们先把gulp安装进来,等后续进行处理yarn add gulp gulp-cli --dev

解决模块中出现的问题

主要去解决在工作模块中不应该被提取的东西,全部抽象出来

抽象data

  • 在项目中运行yarn build的时候,出现报错Cannot find module './package.json'
  • 在项目根目录初始化一个配置文件pages.config.js,然后在yp-gulp/lib/index.js 中读取这个配置文件,用于去替换之前写死的data
// 项目中 pages.config.js 的配置
module.exports ={
  data: {
    menus: [
      {
        name: "Home",
        icon: "aperture",
        link: "index.html"
      },
      {
        name: "Features",
        link: "features.html"
      },
      {
        name: "About",
        link: "about.html"
      }
    ],
    pkg: require('./package.json'),
    date: new Date()
  }
}
// yp-gulp/lib/index.js 中的data读取改成读取当前命令目录下的配置文件
const cwd = process.cwd() // 会返回当前命令行工作的目录
let config = {
  // default config
}

try {
  const loadConfig = require(`${cwd}/pages.config.js`)
  config = Object.assign({},config,loadConfig)
}catch(e){}
  • 然后运行yarn build 就会显示新的报错PluginError: Cannot find module '@babel/preset-env'

更改babel-preset的引入方式

这个模块是我们在创建script任务配置babel的时候指定的preset,babel转换会通过preset去找对应的preset模块,然后转换ES模块,其查找规则是到项目根目录下的node_modules/@babel-preset模块,但是此时项目中并没有这个模块,解决问题的方式也很简单,就是吧preset中的配置去做一个修改,通过require的方式载入

require的方式是先到当前目录下面依次查找,也就是先从lib查找,最后找到上一级的node_modules 中找到

const script = ()=>{
  return src('src/assets/scripts/*.js', { base: 'src' })
  .pipe(plugins.babel({presets: [require('@babel/preset-env')]})) // 去修改这个地方,通过require的方式载入
  .pipe(dest('temp'))
  .pipe(bs.reload({stream: true}))
}

  • 再去运行yarn build 发现build 正常执行了,并且项目下成功生成了dist文件

抽象路径配置

为我们lib/index.js文件中固定的路径改写成可配置的路径

  • 实现方法就是在我们lib/index.js 的配置中填写一个默认的config,把模块中写死的路径改成可配置,用户可以通过配置来实现模块路径的改写
// lib/index.js 下面的文档路径配置
let config = {
  // default config
  build:{
    src:'src',
    dist: 'dist',
    temp: '.temp',
    public: 'public',
    paths:{
      pages: '*.html',
      script: 'assets/scripts/*.js',
      style: 'assets/styles/*.scss',
      image: 'assets/images/**',
      font: 'assets/fonts/**'
    }
  }
}
  • 改变下模块中每个文件的路径配置,拿script任务为例(需要需改的配置地方比较多,可以在github上找到所有的配置)
const script = ()=>{
  return src(config.build.paths.script, { cwd: config.build.src , base: config.build.src })
  .pipe(plugins.babel({presets: [require('@babel/preset-env')]}))
  .pipe(dest(config.build.temp))
  .pipe(bs.reload({stream: true})) // 内部以流的方式推到浏览器,
}

包装Gulp Cli

需求:目前我们通过在gulpfile导出yp-gulp模块来实现构建,我们希望没有和这个导出步骤,模块也能正常工作

  • 我们在项目中删除gulpfile然后运行 yarn gulp build --gulpfile ./node_modules/yp-gulp/lib/index.js --cwd . 也是可以正常工作的
    • --gulpfile:去指定gulpfile所在的目录
    • --cwd:指定当前的工作目录(不指定的话当前的工作目录会在 ~/lagou/gulpConf/node_modules/yp-gulp/lib)
  • 项目运行参数过于繁琐,所以我们尝试在模块中封装一个cli,来把gulp-cli的操作封装起来
  • 在yp-gulp 模块去创建 bin/yp-gulp.js 作为我们cli的入口文件
  • 在package.json 中加入bin 字段bin: bin/yp-gulp.js
yp-gulp.js 的配置
#!/usr/bin/env node

// 命令行中传递的参数可以通过process.argv 来拿到,这是一个数组 
// 所以在代码运行前,我们可以现在cli中push 对应的参数

process.argv.push('--cwd')
process.argv.push(process.cwd()); // 当前命令行所在目录
process.argv.push('--gulpfile')
process.argv.push(require.resolve('..'))

require('gulp/bin/gulp') // 自动去载入gulp-cli
  • ✨ 这里需要注意的一点是 在Mac中需要将cli的可读权限设置为chmod 755 bin/yp-gulp.js
  • 重新link这个模块,运行yp-gulp build 就可以对文件进行build操作

发布模块

这边需要注意一个小点,我们通过npm publish 的时候默认会把项目根目录下的文件,和在package.json中files 配置的目录发布到仓库中,所以需要在files中加上bin和lib

// package.json
files:[
  "lib","bin"
]

保存过后,我们进入命令行执行 yarn publish --registry https://registry.yarnpkg.com 就成功发布这个模块啦