记录 Webpack 从版本 4 更新至 5 所遇到的问题
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
属性中的配置,可以有 test
、exclude
、use
、include
等字段,但不允许有 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 中没有添加对 css
、scss
等文件进行处理操作,添加对应规则即可:
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'),
}),