记一次dll构建时机优化

732 阅读2分钟

之前dll文件是在构建机器上每次都重新构建一次,后来发现是可以根据packages的版本号进行对比,从而判断是否需要重新构建dll。

所以写了一个文件在每次提交时判断是否需要重新构建

优化dll构建

build.dll.js

'use strict';

function exec(cmd) {
  // 将输出实时打印在控制台
  require('child_process').execSync(cmd, { stdio: [0, 1, 2] });
}

const fs = require('fs');
const chalk = require('chalk');
const _ = require('lodash');
// 项目package.json
const packageJson = require('../package.json');
// 用于判断的版本记录文件
const dllJson = require('./build.dll.json');
const dllConfig = require('./webpack.dll.config');

console.log(chalk.yellow(' 正在检查是否需要更新dll文件'));
// 可能webpack.dll.config有多个入口
const vendors = Object.values(dllConfig.entry).reduce((result, it) => result.concat(it), []);
const oldPackages = dllJson.packages;
const newPackages = _.pick(packageJson.dependencies, vendors);
const isEqual = _.isEqual(oldPackages, newPackages);
if (!isEqual) {
  console.log(chalk.cyan(' => 正在重新构建\n'));
  // 执行dll
  exec('npm run build:dll');
  // 构建后将新的版本记录写入文件,version用于HtmlWebpackPlugin写入index.html
  fs.writeFileSync(
    'build/build.dll.json',
    JSON.stringify({ packages: newPackages, version: dllJson.version + 1 }, null, 2)
  );
  console.log(chalk.green(' => 构建完成\n'));
} else {
  console.log(chalk.green(' => 不需要重新构建\n'));
}

build.dll.json

{
  "packages": {
    "vuex": "^2.3.1",
    "vue-router": "^2.3.1",
    "vue-tables-2": "^0.6.64",
    "echarts": "^3.8.5"
  },
  "version": 4
}

之后为了自动的改动vendor.dll.jsindex.html的版本号(用于浏览器缓存),需要在webpack.dev.conf.jswebpack.prod.conf.js加入HtmlWebpackPlugin参数

new HtmlWebpackPlugin({
  // ...省略
  customInfo: {
    vendorVersion: vendorVersion,
  },
}),

index.html加入版本号的参数

<script src="/static/js/vendor.dll.js?v=<%= htmlWebpackPlugin.options.customInfo.vendorVersion %>"></script>

最后一步,在pre-commit加上执行这个文件(需要装husky),这样每次提交就会先进行检查,如果需要构建就会将构建后的文件上传git

npm i -D husky

"husky": {
    "hooks": {
      "pre-commit": "node build/build.dll.js
    }
  }

总结

这样虽然会减少线上构建的时间,但是因为vendor.dll.js是在本地构建的,可能会出现本地和线上版本不同的问题,之后可以想想怎么进一步改造

附件(webpack.dll.config.js)

'use strict';
const path = require('path');
const webpack = require('webpack');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

const context = path.join(__dirname, '..');

module.exports = {
  // 你想要打包的模块的数组
  entry: {
    vendor1: [
      'vuex',
      'vue-router',
      'lodash',
      'vue-tables-2',
    ],
    vendor2: [
      'echarts',
    ],
  },
  output: {
    path: path.join(context, 'static/js'), // 打包后文件输出的位置
    filename: '[name].dll.js',
    library: '[name]_library',
    // vendor.dll.js中暴露出的全局变量名。
    // 主要是给DllPlugin中的name使用,
    // 故这里需要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(__dirname, '.', '[name]-manifest.json'),
      name: '[name]_library',
      context: context,
    }),
    // 压缩打包的文件
    new UglifyJsPlugin({
      uglifyOptions: {
        compress: {
          warnings: false,
        },
      },
      sourceMap: false,
      parallel: true,
    }),
  ],
};