记录一次vue-cli2下的webpack3.x升级webpack4.x的历程

简介: 由于公司项目是19年创建的,因此还是基于vue/cli2搭建的,webpack版本也是3.6.0。(当时有vue/cli3和webpack4不知道为啥不用(`・ω・´))每次打包的时候都要等好久,一直有人在解决这个问题。但是好像一直没结果,这次公司举行首席前端的竞选。把项目升级和提升打包速度作为了考核,所以来搞一下。听说升级到webpack4之后打包速度贼快,不知道是不是真的。下面就记录一下vue/cli2下的webpack3升级webpack4中遇到的一些问题及解决方案。

安装 webpack-cli ,升级webpack

npm i --save-dev webpack webpack-cli

在执行上述命令之后,webpack还是3.x的版本,那很可能是你的package-lock.json中锁定了webpack的最高版本。所以我们直接指定webpack4.x的版本进行安装。

npm i --save-dev webpack@4
  • 安装之前

image.png

  • 安装之后

image.png

重新安装node包

此时运行npm run dev ,项目会出现Error:Cannot find module 'array-includes'错误
image.png
解决办法:

  1. 删掉项目中的node_modules文件夹,
  2. 执行 npm cache clean 或者 cnpm cache clean 命令清除掉cache缓存,
  3. 然后cnpm install 和npm run dev就可以在这台电脑运行你的项目

升级webpack-dev-server至3.X

此时我们运行npm run dev,会发现报错:Error: Cannot find module ‘webpack/bin/config-yargs’
image.png
这是由于webpack-dev-server的版本和webpack4的版本不兼容导致的,webpack3对应的最高webpack-dev-server版本为2.11.5,所以我们要安装2.11.5以上的版本。查阅npm官网,安装目前webpack4对应最新的webpack-dev-server版本为3.11.1

npm i webpack-dev-server@3.11.1 --save-dev

如果安装完后运行依旧报这个错误的话,则需要查看webpack-cli的版本是不是过高。

解决:

  • 卸载当前的 webpack-cli npm uninstall webpack-cli
  • 安装 webpack-cli 3.* 版本 npm install webpack-cli@3 -D

升级html-webpack-plugin

安装完毕之后,再次执行npm run dev,发现之前的报错消失了。但是又有新的错误提示:compilation.mainTemplate.applyPluginsWaterfall is not a function
image.png
这是因为html-webpack-plugin 版本不兼容导致的,所以我们需要升级一下html-webpack-plugin。

npm i html-webpack-plugin@3 -D

升级vue-loader

安装完毕之后,再次执行npm run dev,发现之前的报错消失了。但是又有新的错误提示:
*Module build failed (from ./node_modules/vue-loader/index.js):
TypeError: Cannot read property ‘vue’ of undefined*
image.png
这是因为vue-loader的版本不兼容webpack4导致的,所以我们升级一下vue-loader

npm i vue-loader@15 -D

增加VueLoaderPlugin插件代码

安装完毕之后,再次执行npm run dev,发现之前的报错消失了。但是又有新的错误提示:
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.
File was processed with these loaders:

  • ./node_modules/vue-loader/lib/index.js

You may need an additional loader to handle the result of these loaders.

image.png
这里是因为最新版的 vue-loader 需要加一个新的配置 VueLoaderPlugin。
打开webpack.dev.conf.js,增加如下代码,…表示省略部分已有的代码

//webpack.dev.conf.js
...
// 引入
const { VueLoaderPlugin } = require('vue-loader')
...
// 找到plugins数组,增加一个数组项
plugins: [
    ...
    new VueLoaderPlugin()
]

然后打开webpack.prod.conf.js,进行同样的修改:

// webpack.prod.conf.js
...
// 引入
const { VueLoaderPlugin } = require('vue-loader')
...
// 找到plugins数组,增加一个数组项
plugins: [
    ...
    new VueLoaderPlugin()
]

安装babel-plugin插件转换es6代码。

安装完毕之后,再次执行npm run dev,发现之前的报错消失了。项目似乎已经可以正常运行了。但,打开项目地址一看,一片空白。F12控制台一样,鲜红的报错:
Uncaught TypeError: Cannot assign to read only property ‘exports’ of object ‘#

image.png
点开报错信息,发现直指BaseClient.js,该文件是node_modules下webpack-dev-server中的文件。经过查询得知,出现该种报错信息的原因是因为混用了import和module.exports,一个是es6的用法,一个是es5的用法。
网上的解决办法是建议统一使用es6或者es5的写法 。但是这里的文件并不是我写的,而是npm插件中生成的,所以肯定不能修改写法。于是想到了是不是没有配置babel转换导致的。
安装以下插件

npm install babel-plugin-transform-es2015-modules-commonjs -D

在项目根目录的.babelrc文件中加入:

  "plugins": ["transform-es2015-modules-commonjs"]

同时安装webpack webpack-dev-server webpack-cli

安装完后再次运行项目,报错信息:'webpack-dev-server' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
image.png

解决方法:

现在使用webpack要同时安装webpack-cli这个包,才可以调用webpack和webpack-dev-server这些命令。
    cnpm install webpack webpack-dev-server webpack-cli --save-dev

安装完后再次运行项目,打开项目地址,ok,终于可以正常运行了!
至此,dev环境下的修改已经全部完成。
简单来说就是编译时,遇到can not find xxx,can not find xxx 此类的错误,就需要升级对应的插件,倒也还好。

可能会出现某些模块找不到的错误
image.png
image.png
这可能是复制的问题,删除 node_modules 文件夹重新安装一次就好了应该是 node_modules 文件夹有些文件复制不过去。

配置optimization.splitChunks,删除optimize.CommonsChunkPlugin

接下来还得继续配置product环境,执行npm run build ,依然是醒目的报错信息:
Error: webpack.optimize.CommonsChunkPlugin has been removed, please use config.optimization.splitChunks instead.
image.png
这是因为webpack4已经弃用了webpack.optimize.CommonsChunkPlugin插件,改用了config.optimization.splitChunks属性来进行更加灵活的配置。
打开webpack.prod.conf.js,找到plugins同级的位置增加以下代码。

// plugins
const webpackConfig = merge(baseWebpackConfig, {
  module: {...},
  optimization: { // 增加此处代码
    // Setting optimization.runtimeChunk to true adds an additonal chunk to each entrypoint containing only the runtime.
    // The value single instead creates a runtime file to be shared for all generated chunks.
    runtimeChunk: 'single',
    minimize: env === 'production' ? true : false, //生产环境下才进行代码压缩。
    splitChunks:{
      //As it was mentioned before this plugin will affect dynamic imported modules. Setting the optimization.
      //splitChunks.chunks option to "all" initial chunks will get affected by it (even the ones not imported dynamically). 
      //This way chunks can even be shared between entry points and on-demand loading.
      //This is the recommended configuration.
      //官方推荐使用all.
      chunks: 'all',
      minSize: 30000, //模块大于30k会被抽离到公共模块
      minChunks: 1, //模块出现1次就会被抽离到公共模块
      maxAsyncRequests: 5, //异步模块,一次最多只能被加载5个
      maxInitialRequests: 3, //入口模块最多只能加载3个
      name: true, // 拆分出来块的名字(Chunk Names),默认由块名和hash值自动生成;设置为true则表示根据模块和缓存组秘钥自动生成。
      cacheGroups: {
        // 详情建议参看官网 http://webpack.html.cn/plugins/split-chunks-plugin.html
        default: {
          minChunks: 2,
          reuseExistingChunk: true,
        },
        //打包重复出现的代码
        vendor: {
            // chunks: 'initial',
            // 省略test默认选择所有的模块。
            chunks: 'all',
            minChunks: 2,
            name: 'vendor'
        },
        //打包第三方类库
        commons: {
            // chunks: "initial",
            chunks: "all",
            name: "commons",
            minChunks: Infinity
        }
      }
    }
  },
  plugins: [...]
})

同时,注释或者删除plugins中含有CommonsChunkPlugin的代码,应该是3块:

// 去掉 plugins 中的这3部分代码
...
new webpack.optimize.CommonsChunkPlugin({
   name: 'vendor',
   minChunks (module) {
     // any required modules inside node_modules are extracted to vendor
     return (
       module.resource &&
       /\.js$/.test(module.resource) &&
       module.resource.indexOf(
         path.join(__dirname, '../node_modules')
       ) === 0
     )
   }
 }),
 // extract webpack runtime and module manifest to its own file in order to
 // prevent vendor hash from being updated whenever app bundle is updated
 new webpack.optimize.CommonsChunkPlugin({
   name: 'manifest',
   minChunks: Infinity
 }),
 // This instance extracts shared chunks from code splitted chunks and bundles them
 // in a separate chunk, similar to the vendor chunk
 // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
 new webpack.optimize.CommonsChunkPlugin({
   name: 'app',
   async: 'vendor-async',
   children: true,
   minChunks: 3
 }),
 ...

升级extract-text-webpack-plugin到4.0.0,或者去除extract-text-webpack-plugin,安装 mini-css-extract-plugin

再次执行npm run build,发现之前的报错信息没有了,但是仍然有新的报错提示:
Error: Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead

这里是因为官方已经不推荐使用 extract-text-webpack-plugin 提取 css 样式,可以使用 mini-css-extract-plugin 替代
如果不想改变的话可以升级 extract-text-webpack-plugin到4.0.0-beta.0版本。

 cnpm install extract-text-webpack-plugin@next --save-dev      

使用mini-css-extract-plugin,因为它可以根据页面按需加载,分割css代码,使得以前一大坨CSS彻底成为过去式。
首先安装mini-css-extract-plugin

npm i mini-css-extract-plugin -D

然后卸载extract-text-webpack-plugin

npm uninstall extract-text-webpack-plugin

然后去除所有和extract-text-webpack-plugin相关的代码。一共有2处位置需要修改:
第一个是utils.js中的:

// utils.js
'use strict'
...
// const ExtractTextPlugin = require('extract-text-webpack-plugin') //删除或注释此段。
// 引入
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
...

// 修改此处的generateLoaders函数。
  // generate loader string to be used with extract text plugin
  function generateLoaders(loader, loaderOptions) {
    const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]

    if (loader) {
      loaders.push({
        loader: loader + '-loader',
        options: Object.assign({}, loaderOptions, {
          sourceMap: options.sourceMap
        })
      })
    }
    // Extract CSS when that option is specified
    // (which is the case during production build)
    if (options.extract) {
     /**注释或删除此处代码,开始 */
     // return ExtractTextPlugin.extract({
     //   use: loaders,
     //   publicPath: '../../',
     //   fallback: 'vue-style-loader'
     // })
     /**注释或删除此处代码,结束 */
     /**增加此处代码开始 */
     return [MiniCssExtractPlugin.loader].concat(loaders)
     /**增加此处代码结束 */
    } else {
      return ['vue-style-loader'].concat(loaders)
    }
  }

第二处是webpack.prod.conf.js中的:

...
//webpack.prod.conf
/**注释或删除此处代码,开始 */
// const ExtractTextPlugin = require('extract-text-webpack-plugin')
/**注释或删除此处代码,结束 */
/**增加此处代码,开始 */
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
/**增加此处代码,结束 */
...

plugins:[
  ...
  /**注释或删除此处代码,开始 */
  // extract css into its own file
  // new ExtractTextPlugin({
  //   filename: utils.assetsPath('css/[name].[contenthash].css'),
  //   // Setting the following option to `false` will not extract CSS from           codesplit chunks.
  //   // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
  //   // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 
  //   // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
  //   allChunks: true,
  // }),
  /**注释或删除此处代码,结束 */
  /**增加此处代码,开始 */
  new MiniCssExtractPlugin({
    filename: utils.assetsPath('css/[name].[contenthash].css'),
    allChunks: true,
  }),
  /**增加此处代码,结束 */
  ...
]
我这里使用的是升级extract-text-webpack-plugin,因为使用mini-css-extract-plugin导致的css-loder版本问题一直没有找到合适的方法,网上大部分是要去掉minimize这个属性,4.0的脚手架,安装的css-loader是3.2版本的所以没有这个属性。网上找到一种方式是降级到0.28.0版本,我的项目还是打包不成,这个也暂时搁浅了。同学们有好的方法可以私聊我(#^.^#)

更换追加hash的方式

继续打包之前的错误没了,但是又出现了新的问题。还是webPack 升级到 4.x导致extract-text-webpack-plugin 无法使用
image.png
解决方法:
image.png
再次运行npm run build,这次终于运行成功了!
image.png
image.png

在打包的时候可能会出现一个新的错误。
image.png
网上好多人说加一个属性:minimize: true,过滤掉错误信息。不过好像没什么用。删掉项目中的node_modules文件夹,重新安装一次就可以解决这个问题了。至此,vue/cli2下的webpack3升级webpack4工作已经全部完成,希望对那些需要升级的同学有帮助ღ( ´・ᴗ・` )比心
相关文章
|
JSON 编解码 监控
【Webpack】Webpack4.x 常用操作 | 案例 | 相关构建工具 下
【Webpack】Webpack4.x 常用操作 | 案例 | 相关构建工具
156 0
【Webpack】Webpack4.x 常用操作 | 案例 | 相关构建工具 下
|
前端开发 JavaScript
【Webpack】Webpack4.x 常用操作 | 案例 | 相关构建工具 上
【Webpack】Webpack4.x 常用操作 | 案例 | 相关构建工具
153 0
【Webpack】Webpack4.x 常用操作 | 案例 | 相关构建工具 上
|
2月前
|
JavaScript
webpack打包TS
webpack打包TS
132 60
|
1月前
|
缓存 前端开发 JavaScript
Webpack 打包的基本原理
【10月更文挑战第5天】
|
1月前
|
前端开发 JavaScript
ES6模块化和webpack打包
【10月更文挑战第5天】
|
1月前
|
缓存 前端开发 JavaScript
深入了解Webpack:模块打包的革命
【10月更文挑战第11天】深入了解Webpack:模块打包的革命
|
2月前
|
JavaScript 测试技术 Windows
vue配置webpack生产环境.env.production、测试环境.env.development(配置不同环境的打包访问地址)
本文介绍了如何使用vue-cli和webpack为Vue项目配置不同的生产和测试环境,包括修改`package.json`脚本、使用`cross-env`处理环境变量、创建不同环境的`.env`文件,并在`webpack.prod.conf.js`中使用`DefinePlugin`来应用这些环境变量。
106 2
vue配置webpack生产环境.env.production、测试环境.env.development(配置不同环境的打包访问地址)
|
1月前
|
缓存 前端开发 JavaScript
Webpack技术深度解析:模块打包与性能优化
【10月更文挑战第13天】Webpack技术深度解析:模块打包与性能优化
|
1月前
|
前端开发 JavaScript 开发者
深入了解Webpack:现代JavaScript应用的打包利器
【10月更文挑战第11天】 深入了解Webpack:现代JavaScript应用的打包利器
|
2月前
|
缓存
webpack 打包多页面应用
webpack 打包多页面应用
24 1
下一篇
无影云桌面