在古代前端工程化的历史中,webpack
这个煊赫一时的模块打包工具占据着打包编译界的半壁江山,它领有丰盛的插件生态和弱小的编译能力,也正因为其过于“弱小”导致在降级时会呈现各种各样的兼容等问题,这点想必有过降级经验的应该都印象粗浅吧!那么明天咱们就来聊聊降级到 webpack5
过程中呈现的各类问题和相干解决方案。
起因
缘于公司我的项目重构和打包优化的需要,同时基于对架构对立和底层欠缺,决定采纳 webpack5
作为打包工具来减速我的项目的打包编译效率。
阐明
以下的所有贴图均为题主理论开发中遇到的错误信息,仅供参考应用。
问题
‘locals’ of undefined 报错
从上述的截图中提取到错误信息
Uncaught TypeError: Cannot read property 'locals' of undefined
起因
初看这个谬误剖析它大略意思之后,题主猜想可能跟 loader
的版本有关系(毕竟这是降级过程中的经典问题之一),而后在题主一顿 操作猛如虎之后发现的确由 loader
引起,大抵问题是 style-loader
与 mini-css-extract-plugin
这俩货在打包过程中同时应用会有抵触。
解决
在参考了相干解决方案之后,题主采纳了 去除 style-loader
的做法,贴一段示例代码作参考。
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const isDev = /* your logic */ true;
module.exports = {plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.css$/i,
use: [
// 只在 dev 应用 style-loader
isDev ? "style-loader" : MiniCssExtractPlugin.loader,
"css-loader",
],
},
],
},
};
提醒:很多
webpack
的loader
(如:css-loader
)在新版公布后会呈现breaking change
的变动,因而如果遇到问题时最好先查阅一遍该loader
的最新文档。
以下是题主解决过程中找到的相干计划可供参考
- uncaught-typeerror-cannot-read-property-locals-of-undefined
- mini-css-extract-plugin/issues
process is not defined
起因
这个问题基本上只有在我的项目中应用了 process
变量应该都会遇到,那么就会让人产生纳闷了,为什么明明我在 webpack4
都能用的,到 webpack5
就间接给干掉了?
带着这些疑难,咱们来查阅下官网文档,看看能不能找到一些正文马迹。果然,在 迁徙指南
里官网爸爸曾经对这个 breaking change
给出了具体的阐明,这里题主把要害的内容贴出来。
从圈出的内容里能够看到 webpack5
为了进步 web
的兼容性,已不再主动引入 Node
模块相干的 polyfill
了,如需应用须要咱们手动引入对应的依赖包,这也就是呈现 process
变量未定义的起因。
解决
那么咱们还能持续应用 process
作为全局变量吗?答案当然是能够的,以下是题主联合其余计划采纳的解决形式。
- 手动装置
process
依赖包到我的项目中。 - 将全局变量
process
指向process
的browser
目录主文件。 - 引入
ProvidePlugin
插件,指定process
指向。
// step 1
yarn add process
// step 2
config.resolve.alias.set("process", "process/browser");
// step 3
config.plugin("processPolyfill").use(
new webpack.ProvidePlugin({process: "process/browser",})
);
而后在题主实现实现后,开发运行时没问题,在打包构建时却呈现了 process.env.API
这一类环境变量读取不到的问题(略无解)。因而最终采纳 EnvironmentPlugin
联合 DotPlugin
读取 *.env
文件来补救这个缺点,如有更好的计划能够通知我。
config.plugin("env").use(new webpack.EnvironmentPlugin(envKeys));
if (isProd) {config.plugin("DotPlugin").use(require.resolve("dotenv-webpack"), [
{path: envFile,},
]);
}
以下是题主解决过程中找到的相干计划可供参考
- webpack-bundle-js-uncaught-referenceerror-process-is-not-defined
mini-css-extract-plugin 的 order 报错
起因
这个谬误就比拟不言而喻了,应该是插件的排序引起。
解决
间接通过 mini-css-extract-plugin
配置项 ignoreOrder
解决。
config.optimization.minimizer("css").use(MiniCssExtractPlugin, [
{filename: `css/[name].[contenthash:8].css`,
chunkFilename: `css/[name].[contenthash:8].chunk.css`,
ignoreOrder: true,
},
]);
以下是题主解决过程中找到的相干计划可供参考
- mini-css-extract-plugin/issue
- remove-order-warnings
core-js 中 define-property 报错
从上述的截图中提取到错误信息
webpack 5.0.0-beta.30 Module not found: Error: Can't resolve'../../core-js/object/define-property'
起因
乍一看这个谬误之后有点懵逼,不过在仔细察看后能够发现错误来源于 core-js
,猜想可能跟 .(m)js
文件编译有关系。
解决
在题主的多方致力之后,找到了一个可行的解决方案,即设置 fullySpecified
为 false
,可参考以下贴出的示例。
config.module
.rule("esmJs")
.test(/\.m?js/)
.resolve.set("fullySpecified", false);
以下是题主解决过程中找到的相干计划可供参考
- webpack/issue
path-to-regexp export 谬误
从上述的截图中提取到错误信息
Attempted import error: 'path-to-regexp' does not contain a default export (imported as 'pathToRegexp')
起因
通过排查比对 package.json
中的依赖版本、node_modules
中依赖的版本之后,题主发现在此次重构迁徙的过程中,依照老我的项目的形式装置了两份 path-to-regexp
,具体依赖包地位如下:
- 我的项目装置的
react-router
已蕴含了path-to-regexp
库,依赖版本为^1.7.0
- 我的项目又独自装置了
path-to-regexp
依赖,其版本为^6.1.0
解决
猜测到同时存在两个版本可能会有 API
差别,题主特意去查看了不同版本的阐明文档,果然发现版本不同其导出的 export
形式也产生了变动,因而这里采纳删除独自装置 path-to-regexp
依赖(我的项目用这个库不多,同时 react-router
已蕴含了这个库,就不反复增加了),而后在我的项目中依照低版本的形式引入。
// before
import {pathToRegexp} from "path-to-regexp";
// after
import pathToRegexp from "path-to-regexp";
以下是题主解决过程中找到的相干计划可供参考
- attempted-import-error-path-to-regexp-does-not-contain-a-default-export-impo
.plugins3 报错
从上述的截图中提取到错误信息
.plugins[3][1] must be an object, false, or undefined
这个问题个别是因为 babel
的配置文件(.babelrc
或 babel.config.js
)中的 plugin
配置不当引起的,可参考 plugins01-must-be-an-object-false-or-undefined 解决。
@pmmmwh/react-refresh-webpack-plugin 报错 $RefreshReg$
题主在此次降级过程中引入了 @pmmmwh/react-refresh-webpack-plugin
这个全新的刷新库,这个库也是官网举荐替换 react-hot-loader
的刷新库,尽管目前还没到 beta
版本,不过能够先尝鲜(个人感觉还算稳固能够试用)。在一通魔改配置之后却并没有失去想要的刷新成果,而失去了如下的错误信息。
$RefreshReg$ is not defined with ChildCompiler usage
起因
在参考配置、剖析刷新之后,题主根本确定了这个谬误跟配置的解决地位有关系。
解决
因为题主的我的项目将 react
等库抽离到 CDN
上,实现形式上有所差别,因而就不贴参考代码了,具体计划可参考 react-re 是 fresh-webpack-plugin/issue。
@babel/plugin-transform-typescript 不反对 export= 语法
从上述的截图中提取到错误信息
`export =` is not supported by @babel/plugin-transform-typescript Please consider using `export <value>;`
起因
这个全新的我的项目对立采纳了 CSS Moudles
的形式,同时联合 @teamsupercell/typings-for-css-modules-loader
生成 *.module.less.d.ts
文件以进步 less
文件的应用效率,
然而在 *.module.less.d.ts
文件中蕴含了 export =
的语法导致编译不辨认。
解决
在这个时候的 babel
的插件就很有用了,通过在插件将 export =
语法转换为 export <value>;
,那么问题就迎刃而解了。不过,题主正好在相干 issue 中找到了现成的插件就间接应用没有本人反复在轮子了,这里贴一下插件的具体代码。
import {NodePath, PluginObj} from "@babel/core";
import {TemplateBuilder} from "@babel/template";
import {TSExportAssignment} from "@babel/types";
const babelPluginReplaceTsExportAssignment = ({template,}: {template: TemplateBuilder<TSExportAssignment>,}): PluginObj => {
const moduleExportsDeclaration = template(`
module.exports = ASSIGNMENT;
`);
return {
name: "replace-ts-export-assignment",
visitor: {TSExportAssignment(path: NodePath<TSExportAssignment>) {
path.replaceWith(moduleExportsDeclaration({ ASSIGNMENT: path.node.expression})
);
},
},
};
};
export default babelPluginReplaceTsExportAssignment;