记录 Webpack 从版本 4 更新至 5 所遇到的问题

前端开发 Oct 30, 2020

Webpack 从 v4 迁移至 v5 问题记录

最近,出于工作中对项目优化,有打算将用到的 Webpack 从 4.* 升级至最新版本(Webpack@5.3.0);鉴于之前就有 Webpack 相关经验,略看了点文档 Webpack 从 v4 升级到 v5 后,就基于 nicelinks-vue-client 项目开始了升级之旅。因为强行升级,过程也较为曲折,有将遇到的一些问题做下梳理记录,希望对之后欲升级 webpack 的朋友,形成参考。

webpack5 构建 vue 编译报错

TypeError: Cannot read property 'properties' of undefined

重新安装依赖 webpack-cli

yarn remove webpack-cli
yarn add webpack-cli -D

[webpack-cli] Invalid configuration object.

[webpack-cli] Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema. configuration.module.rules[5] should be one of these:
["..." | object { compiler?, dependency?, descriptionData?, enforce?, exclude?, generator?, include?, issuer?, loader?, mimetype?, oneOf?, options?, parser?, realResource?, resolve?, resource?, resourceFragment?, resourceQuery?, rules?, sideEffects?, test?, type?, use? }, ...] -> A rule. Details: * configuration.module.rules[4] has an unknown property 'query'.

Compiling RuleSet failed

ERROR: Compiling RuleSet failed: A Rule must not have a 'options' property when it has a 'use' property

在 Webpack 最新版本中,rules 属性中的配置,可以有 testexcludeuseinclude 等字段,但不允许有 options 了;如果需要,可以写成下面这样:

{
  test: /\.m?js$/,
  exclude: /(node_modules|bower_components)/,
  use: {
    loader: 'babel-loader',
    options: {
      presets: ['@babel/preset-env']
    }
  }
},

TypeError: Cannot read property 'vue' of undefined

Module build failed (from ./node_modules/vue-loader/index.js):
TypeError: Cannot read property 'vue' of undefined

重新安装 vue-loader 插件:

yarn remove vue-loader && yarn add vue-loader -D

Module parse failed: Unexpected character

ERROR in ./src/assets/scss/style.scss 1:0
Module parse failed: Unexpected character
ERROR in ./src/components/markdown/markdown.css 1:0
Module parse failed: Unexpected token
ERROR in ./src/views/manage/Users.vue?vue&type=template&id=85a68250& 2:0
Module parse failed: Unexpected token (2:0)
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.

是因为在 webpack.config.js 中没有添加对 cssscss 等文件进行处理操作,添加对应规则即可:

rules: [
  {
    test: /\.s[ac]ss$/i,
    use: [
      // Creates `style` nodes from JS strings
      'style-loader',
      // Translates CSS into CommonJS
      'css-loader',
      // Compiles Sass to CSS
      'sass-loader',
    ],
  },
  {
    test: /\.css$/i,
    use: [
      // Creates `style` nodes from JS strings
      'style-loader',
      // Translates CSS into CommonJS
      'css-loader'
    ],
  }
]

vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.

Vue-loader在 15.* 之后的版本都是 vue-loader 的使用都是需要伴生 VueLoaderPlugin 的。在webpack.config.js中加入

const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
    // ......
    plugins: [
        // make sure to include the plugin for the magic
        new VueLoaderPlugin()
    ],
}

ERROR in ReferenceError: webpack is not defined

ERROR in Template execution failed: ReferenceError: webpack is not defined
ERROR in ReferenceError: webpack is not defined

HtmlWebpackPlugin 插件的自定义模版中用到了 webpack 变量;而最新版本已经不再支持这个变量,因此去掉下面这些就好:

<% for (var chunk of webpack.chunks) {
	for (var file of chunk.files) {
		if (file.match(/\.(css)$/)) { %>
			<link rel="<%= chunk.initial ? 'preload' : 'prefetch' %>" href="<%= htmlWebpackPlugin.files.publicPath + file %>" as="<%= file.match(/\.css$/)?'style':'script' %>">
<% }}} %>

TypeError: Cannot read property 'babel' of undefined

Module build failed (from ./node_modules/babel-loader/lib/index.js):
TypeError: Cannot read property 'babel' of undefined

所依赖的 babel-loader 不是最新版本,更新下即可:

yarn remove babel-loader && yarn add babel-loader -D
new webpack.DllReferencePlugin({
      context: path.resolve(__dirname, '..'),
      manifest: require('./vendor-manifest.json')
}),

[webpack-cli] TypeError: compiler.plugin is not a function

[webpack-cli] TypeError: compiler.plugin is not a function
at AddAssetHtmlPlugin.apply (/Users/x/y/z/node_modules/add-asset-html-webpack-plugin/lib/index.js:10:14)

是因为所依赖的 add-asset-html-webpack-plugin 插件不匹配新版本,更新至最新版即可:

yarn remove add-asset-html-webpack-plugin && yarn add add-asset-html-webpack-plugin -D

webpack5 构建 vue 运行报错

Cannot access 'WEBPACK_DEFAULT_EXPORT' before initialization

index.js:3 Uncaught ReferenceError: Cannot access 'WEBPACK_DEFAULT_EXPORT' before initialization at Module.default (index.js:3)

是因为在构建配置中,有部分依赖出现重复所致;重新启用 DllReferencePlugin 插件,去除这部分重复的组件即可:

new webpack.DllReferencePlugin({
  context: path.resolve(__dirname, '..'),
  manifest: require('./vendor-manifest.json')
}),

Uncaught TypeError: Cannot read property 'call' of undefined

Uncaught TypeError: Cannot read property 'call' of undefined
at webpack_require (vendor.dll.js:24767)
at eval (index.js?9552:1)

根据控制台错误提示,点击进去发现,在 webpack:///./src/index.js 下存在这样的代码:

import ContentPlaceholder from './ContentPlaceholder.vue'
export default ContentPlaceholder

事实上代码中的写法是:

import ContentPlaceholder from 'vue-content-placeholder'
export default {
	component: {
		ContentPlaceholder
	}
}

有尝试移除对该组件的依赖,就不会存在此问题,所构建出的包,也能在本地正常运行起来;略做了查纠,发现 vue-content-placeholder 该组件库,并未提供源代码,node_modules 中存在的也是构建后的内容,与当前版本 webpack(5) 不匹配所致。后续考虑重新写或者替换一个库来予以解决。

当然,webpack 打包,能引起类似报错的种类繁多,上述这种解决方法,不一定适合其他项目,具体问题需,要具体分析。

Uncaught ReferenceError: vendor_library is not defined

是因为自定义的映射文件没有注入,使用 add-asset-html-webpack-plugin 插件导入即可(vendor.dll.js):

new AddAssetHtmlPlugin({
      filepath: path.resolve(__dirname, 'dist/*.dll.js'),
}),

Tags

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.