将公司旧webpack3升级到5,踩坑总结

4,267 阅读5分钟

前言

由于手上目前负责公司的项目属于相对老旧的项目,每次打包构建的时候都要等近两分钟。这让我这个急性子实在无法接受。然后打算去优化一下。看了一下webpack版本是3。目前最新都是5了。据说打包时间会有一定提升。最主要的还是可以支持一些新插件和特性。我便着手进行webpack大版本的升级。这注定是一此项目地震。

先看成果

[23:20:42] Finished 'build' after 1.28 min
[23:20:42] Starting 'create:versionCatalog'...
......
[23:20:42] Starting '<anonymous>'...
[23:20:42] Finished '<anonymous>' after 36 ms
[23:20:42] Finished 'default' after 1.3 min

只看build这个过程一共花费了1.28分钟。 看看升级之后的的效果。

[21:59:37] Finished 'build' after 43 s
[21:59:37] Starting 'create:versionCatalog'...
[21:59:37] Finished 'create:versionCatalog' after 263 ms
......
[21:59:37] Starting '<anonymous>'...
[21:59:37] Finished '<anonymous>' after 31 ms
[21:59:37] Finished 'default' after 44 s

build这个过程之花了43秒,速度上面是有一定提升的。

升级过程以及关键点

具体升级细节我就不多描述了。可以参考这两篇文章。我就简单截取一些关键点。

依赖调整

一般教程推荐使用npm-check-updates进行其他适配版本的升级,但是我为了让记忆深刻点。我选择一个个发现进行升级。期间调整的依赖有以下几个。若有读者问题可以进行补充。

包名处理方式新版本号
webpack升级5.37.0
webpack-dev-server升级^4.7.4
webpack-cli升级^4.9.2
webpack-merge升级^5.8.0
html-webpack-plugin升级^5.3.2
copy-webpack-plugin-cli升级^10.2.4
css-loader升级^6.7.1
svg-sprite-loader升级^6.0.11
friendly-errors-webpack-plugin升级^1.7.0
postcss-loader升级^6.2.1
vue-loader升级^15.9.8
url-loader删除-
file-loader删除-
vue-style-loader删除-
style-loader新增^3.3.1
extract-text-webpack-plugin删除
mini-css-extract-plugin新增^2.6.0
optimize-css-assets-webpack-plugin删除
css-minimizer-webpack-plugin新增^3.4.1

plugins及一些依赖使用方式的改变

这里我只记录有哪些公共点需要调整。具体怎么调整再以上推荐文章里有提,不多做赘述。读者可以根据列出来的几点去以上文章里找对应具体修改。

  • 项目webpack-dev-server升到了4版本用来配套webpack5,所以npm run dev的命令需要相改为webpack serve启动
  • 需要再plugins里面增加VueLoaderPlugin(vue-loader)
  • extract-text-webpack-pluginoptimize-css-assets-webpack-plugin已经过时了需要由mini-css-extract-plugincss-minimizer-webpack-plugin来代替
  • webpack5自带了资源解析,所以不需要什么url-loader,file-loader之类的,直接用assets就可以解析
  • 调整copyWebpackPlugincopy-webpack-plugin)使用方法
  • webpack-merge要解构出来,const { merge } = require('webpack-merge')
  • NamedModulesPlugin已过时,由optimization的moduleIds进行替换
  • copy-webpack-plugin插件使用方式有变化
  • devServer改动很多可以参考以上文章链接,自定义参考官网devserver专题
  • UglifyJsPlugin已经过时,可以直接使用webpack5开箱提供的TerserPlugin
  • 代码拆分webpack.optimize.CommonsChunkPlugin已经过时现在使用webpack5提供的optimization.splitChunks属性来实现功能来实现
  • build->util.js文件中修改了一处 MiniCssExtractPlugin.loader。ExtractTextPlugin(extract-text-webpack-plugin)已过时,使用MiniCssExtractPlugin(mini-css-extract-plugin)进行替换。
  • devtool有做一定修改
  • 由于vue-loader升级了,所以之前css如果使用/deep/有可能出错。我是在根节点使用/deep/然后换到::v-deep就正常了。如果有类似问题,可以相应调整。

以下几点我有做自己的调整。

  • TerserPlugin进行代码压缩的时候,去除了注释。对应官网
new TerserPlugin({
  terserOptions: {
    format: {
      comments: false,
    },
  },
  extractComments: false
})

去掉了vue-style-loader使用style-loader替代。原因css-loader从V4版本开始默认开启esModule,导致css无法被vue-style-loader解析的问题,解决方案有两个我选择替换替换vue-style-loader。具体: github.com/vuejs/vue-l…

  • MiniCssExtractPlugin我调整了一下css生成位置和名字。
new MiniCssExtractPlugin({
  filename: utils.assetsPath('css/[name].css'),
  chunkFilename: utils.assetsPath('css/[id].[contenthash].css')
}),

对应的utils.js里面的MiniCssExtractPlugin中的publicPath也要相应修改。

return [{
  loader: MiniCssExtractPlugin.loader,
  options: {
    publicPath: '../../'
  }
}].concat(loaders)
  • splitChunks调整。我为了将所有css合并为一个css所以调整了一下cacheGroups
splitChunks: {
  ···
  cacheGroups: {
    vendors: {
      name: 'vendors',
      test({ resource }) {
        return /[\/]node_modules[\/]/.test(resource);
      },
      priority: -10
    },
    styles: {
      name: "styles",
      chunks: "all",
      type: "css/mini-extract",
      enforce: true,
      priority: 10,
    }
  }
}

由于该项目使用glup构建工具,所以也有一定调整。调整我也列出来。

  • 由于去掉了manifest.js文件。所以对应处理replace:cdnUrl的流程也就去掉。相对应解决动态cdn的方法改为使用webpack内部变量__webpack_public_path__进行调整。具体方法。可以参考进行替代。

webpack 公共路径设置的全局变量 webpack_public_path

  • 由于使用TerserPlugin所以代码混淆会有差异。所以要调整replace:version过程替换版本号的匹配目标。 旧的:
gulp.task('replace:version', function () {
  return gulp.src(`${versionPath}/static/config/index-${env}.js`)
    .pipe($.replace(/window.SITE_CONFIG['version'] = '.*'/g, `window.SITE_CONFIG['version'] = '${version}'`))
    .pipe(gulp.dest(`${versionPath}/static/config/`))
});

新的:

// 替换${versionPath}/static/config/index-${env}.js window.SITE_CONFIG['version']配置变量
gulp.task('replace:version', function () {
  return gulp.src(`${versionPath}/static/config/index-${env}.js`)
    .pipe($.replace(/window.SITE_CONFIG.version=".*"/g, `window.SITE_CONFIG['version'] = '${version}'`))
    .pipe(gulp.dest(`${versionPath}/static/config/`))
});

全部的gulpfile.js配置我列一下。

var gulp = require('gulp');
var $    = require('gulp-load-plugins')();
var path = require('path');
var del  = require('del');

var distPath    = path.resolve('./dist');
var version     = ''; // 版本号
var versionPath = ''; // 版本号路径
var env         = ''; // 运行环境

// 创建版本号(年月日时分)
(function () {
  var d = new Date();
  var yy = d.getFullYear().toString().slice(2);
  var MM = d.getMonth() + 1 >= 10 ? (d.getMonth() + 1) : '0' + (d.getMonth() + 1);
  var DD = d.getDate() >= 10 ? d.getDate() : '0' + d.getDate();
  var h  = d.getHours() >= 10 ? d.getHours() : '0' + d.getHours();
  var mm = d.getMinutes() >= 10 ? d.getMinutes() : '0' + d.getMinutes();
  version = yy + MM + DD + h + mm;
  versionPath = distPath + '/' + version;
})();

// 编译
gulp.task('build', $.shell.task([ 'node build/build.js' ]));

// 创建版本号目录
gulp.task('create:versionCatalog', function () {
  return gulp.src(`${distPath}/static/**/*`)
    .pipe(gulp.dest(`${versionPath}/static/`))
});

// 替换${versionPath}/static/config/index-${env}.js window.SITE_CONFIG['version']配置变量
gulp.task('replace:version', function () {
  return gulp.src(`${versionPath}/static/config/index-${env}.js`)
    .pipe($.replace(/window.SITE_CONFIG.version=".*",/g, `window.SITE_CONFIG['version'] = '${version}',`))
    .pipe(gulp.dest(`${versionPath}/static/config/`))
});

// 合并${versionPath}/static/config/[index-${env}, init].js 至 ${distPath}/config/index.js
gulp.task('concat:config', gulp.series(function () {
  return gulp.src([`${versionPath}/static/config/index-${env}.js`, `${versionPath}/static/config/init.js`])
    .pipe($.concat('index.js'))
    .pipe(gulp.dest(`${distPath}/config/`))
}));

// 清空
gulp.task('clean', function () {
  return del([versionPath])
});

gulp.task('getEnv', function (cb) {
  // 获取环境配置
  env = process.env.NODE_ENV || 'prod'
  cb()
})

gulp.task('default', gulp.series('clean', 'getEnv', 'build', 'create:versionCatalog', 'replace:version', 'concat:config', function () {
  // 清除, 编译 / 处理项目中产生的文件
  return del([`${distPath}/static`, `${versionPath}/static/config`])
}));

总结

那么一套升级流程下来过程还算有收获。我将我的一些踩坑点记录在里面。前人踩坑填坑,后人走平路。希望读者有收获的话可以点下赞和收藏哦。

下一步将进行webpack打包后大小的调整。因为我发现打包之后的js文件反而变大了。 希望读者期待笔者的webpack5优化篇

听说点赞会加薪、升职、变帅、变美欸亲