关于前端:论如何填满-webpack5-升级天坑

15次阅读

共计 4951 个字符,预计需要花费 13 分钟才能阅读完成。

在古代前端工程化的历史中,webpack 这个煊赫一时的模块打包工具占据着打包编译界的半壁江山,它领有丰盛的插件生态和弱小的编译能力,也正因为其过于“弱小”导致在降级时会呈现各种各样的兼容等问题,这点想必有过降级经验的应该都印象粗浅吧!那么明天咱们就来聊聊降级到 webpack5 过程中呈现的各类问题和相干解决方案。

起因

缘于公司我的项目重构和打包优化的需要,同时基于对架构对立和底层欠缺,决定采纳 webpack5 作为打包工具来减速我的项目的打包编译效率。

阐明

以下的所有贴图均为题主理论开发中遇到的错误信息,仅供参考应用。

问题

‘locals’ of undefined 报错

从上述的截图中提取到错误信息

Uncaught TypeError: Cannot read property 'locals' of undefined

起因

初看这个谬误剖析它大略意思之后,题主猜想可能跟 loader 的版本有关系(毕竟这是降级过程中的经典问题之一),而后在题主一顿 操作猛如虎之后发现的确由 loader 引起,大抵问题是 style-loadermini-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",
        ],
      },
    ],
  },
};

提醒:很多 webpackloader(如: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 作为全局变量吗?答案当然是能够的,以下是题主联合其余计划采纳的解决形式。

  1. 手动装置 process 依赖包到我的项目中。
  2. 将全局变量 process 指向 processbrowser 目录主文件。
  3. 引入 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 文件编译有关系。

解决

在题主的多方致力之后,找到了一个可行的解决方案,即设置 fullySpecifiedfalse,可参考以下贴出的示例。

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,具体依赖包地位如下:

  1. 我的项目装置的 react-router 已蕴含了 path-to-regexp 库,依赖版本为 ^1.7.0
  2. 我的项目又独自装置了 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 的配置文件(.babelrcbabel.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;

正文完
 0