webpack 下载报错-一行配置将antd中的moment替换为dayjs(vite和webpack均适用)

2024-04-27 0 5,612 百度已收录

直接上传代码

resolve: {
    alias: {
      'rc-picker/es/generate/moment': 'rc-picker/es/generate/dayjs'
    }
}

solve 是配置文件中的解析主键。

温馨提示:虽然使用前面配置成功引入了dayjs(或者你使用了官方推荐方式引入了dayjs),但是如果你想将dayjs类型默认传递antd的时间相关组件,请不一定保证dayjs默认值。 对应的dayjs版本与rc-picker的package.json中配置的dayjs版本一致。 rc-picker 是 antd 的依赖项。 看看下面的原因

本文针对的antd版本是:4.18.9

总长DR

如果您不想读那么多,可以滚动到最后并阅读摘要

我们先看一下官方的替代方案

替换时刻的官方文档为:ant.design/docs/react/...

文档主要介绍了两种方法,一种是自己定义组件,一种是使用webpack插件。 这份文档对我来说有以下几个不解之处:

关于这些,文档中没有答案。 这里不得不再次表扬尤溪写文档的方式。 在教你如何使用它之前,我先告诉你原因。

我没有研究antd为什么默认使用moment,研究了为什么moment可以按照文档的形式进行替换。 对原理兴趣的朋友请继续阅读下文。

原因

我在项目中使用react+antd已经有半年多了。 我在使用antd的table组件时,发现文档中的使用方法并没有达到效果。 我发现文档的版本和我使用的antd版本不一致。 而且我查了老版本的文档,发现没有关于如何使用的介绍。 最后不得不选择升级antd。

依赖第三方库进行盲目升级并不是一个好的选择。 许多第三方库不保证向后兼容性。 即使这样做了,也有可能因为遗漏而没有测试到位,可能会在升级中带来新的问题

升级后进行了防火测试,发现一切正常。 我心里突然对antd刮目相看了。 大厂就是大厂,稳定性保障

直到我在项目中使用了三天的DatePicker,发现每当点击时间选择框时,都会报错clone.weekdayisnotafunction:

图中的错误是dayjs的一个实例调用了不存在工作日技能

我立即查看webpack的配置,发现webpack使用了antd-dayjs-webpack-plugin插件,将moment替换为dayjs。 而且我清楚的记得,使用这个插件的时候没有报错。 很有可能是升级antd导致bug

webpack 下载报错-一行配置将antd中的moment替换为dayjs(vite和webpack均适用)

这个时候我就非常信任antd和antd-dayjs-webpack-plugin了。 我相信这不仅仅是我的使用问题。

然后我做了以下事情:

阅读antd如何替换moment的文档,看看是否更新推断是没有更新,仍然是替换方法

我查看了antd-dayjs-webpack-plugin的github,看是否有更新说明。 我发现这个插件已经几个月没有更新了,但是我没有发现任何与我在问题中提到的类似内容。 即使我找到了,这个问题也已经存在很长时间了。 官方方面暂未回应

此时我开始对antd产生一些怀疑。

最终我选择了解决npm问题最好的办法,那就是重装是个好主意! 果然,重新安装后,问题解决了,错误消失了!

如果是别的库,故事可能到这里就结束了,但是它是antdwebpack 下载报错,它是Ant出品的,我又这么信任它,它怎么会出问题呢?

追根溯源

既然我在antd文档中找不到为什么可以按照它说的方法替换成moment,那就自己看一下吧。

首先我看了一下antd-dayjs-webpack-plugin的源码。 通过它,我大致明白了为什么可以替代moment。

该插件主要做了以下几件事:

源码地址:github.com/ant-design/...


 // set dayjs alias
    if (this.replaceMoment) {
      const { alias } = compiler.options.resolve
      if (alias) {
        alias.moment = 'dayjs'
      } else {
        compiler.options.resolve.alias = {
          moment: 'dayjs'
        }
      }
    }
    

这样,当webpack遇到引用moment的模块时,它就会转而引用dayjs。

if (this.plugins) {
  const { entry, module } = compiler.options;
  const initLoaderRule = {
    test: /init-dayjs-webpack-plugin-entry.js$/,
    use: [
      {
        loader: path.resolve(__dirname, "./init-loader.js"),
        options: {
          plugins: this.plugins,
        },
      },
    ],
  };
  if (module.rules) {
    module.rules.push(initLoaderRule);
  } else {
    compiler.options.module.rules = [initLoaderRule];
  }
  const initFilePath = path.resolve(
    __dirname,
    "init-dayjs-webpack-plugin-entry.js"
  );
  const initEntry = require.resolve(initFilePath);
  compiler.options.entry = makeEntry(entry, initEntry);
}

上面代码的意思是在webpack的入口中添加一个“init-dayjs-webpack-plugin-entry.js”,这样webpack就会加载这个js文件,然后插件就会写一个特殊的叫init-loader.js 加载器来解析“init-dayjs-webpack-plugin-entry.js”。 init-loader.js主要做的事情就是注入js代码

源代码位于:github.com/ant-design/...

const { getOptions } = require("loader-utils");
module.exports = function loader(source) {
  const options = getOptions(this);
  options.plugins.forEach((plugin) => {
    source += `var ${plugin} = require('dayjs/plugin/${plugin}');`;
  });
  options.plugins.forEach((plugin) => {
    source += `dayjs.extend(${plugin});`;
  });
  // special plugin
  source += `var antdPlugin = require('antd-dayjs-webpack-plugin/src/antd-plugin');dayjs.extend(antdPlugin);`;
  return source;
};

至此,插件的工作完成了。 它产生了以下治疗效果。 这种治疗效果非常重要。 请务必了解

webpack编译出来的boundle包会包含以下代码(有些省略,主要是引入dayjs后为dayjs安装各种插件):

var dayjs = __webpack_require__(/*! dayjs/dayjs.min */ "./node_modules/.pnpm/registry.npmmirror.com+dayjs@1.10.7/node_modules/dayjs/dayjs.min.js");
var isSameOrBefore = __webpack_require__(/*! dayjs/plugin/isSameOrBefore */ "./node_modules/.pnpm/registry.npmmirror.com+dayjs@1.10.7/node_modules/dayjs/plugin/isSameOrBefore.js");
dayjs.extend(isSameOrBefore);
//...省略部分安装其他插件的代码

这个插件的作用就是注入一段代码,然后使用alias将moment的引用改为dayjs。 然后我们就可以愉快的使用dayjs了。

似乎没有问题。 antd曾经引用的那一刻,现在被webpack引用到了dayjs,但是插件也安装了。 为什么会报错? 等等,好像有什么不对劲?

webpack只引入项目根目录下package.json中配置的dayjs指向的版本,并安装该版本的插件。 如果antd没有引用这个版本怎么办?

是的,我们升级 antd 后,antd 引用的 dayjs 版本与 antd-dayjs-webpack-plugin 插件引入的 dayjs 版本不一致。 事实上,通过antd插件,确实引用了dayjs而不是moment,而且引用的并不是同一个版本。 antd引用的dayjs只是一段核心代码,没有安装任何插件,从而导致错误。

antd如何指代时刻

具体来说,antd中引用moment是通过antd引用rc-picker,然后rc-picker引用moment。 虽然我们的项目没有在package.json中配置对dayjs的依赖,但是antd引用的rc-picker也会安装对dayjs的依赖。 然而,这个依赖只能被rc-picker引用。 这就提出了一个严肃的问题:

一旦 rc-picker 引用的 dayjs 和 antd-dayjs-webpack-plugin 引用的 dayjs 不是同一个版本,antd-dayjs-webpack-plugin 插件会导致 antd 中使用 dayjs 的组件报错。

我的项目中,第一次配置时使用了antd-dayjs-webpack-plugin引入了dayjs的1.10.7版本,而antd此时也引用了1.10.7版本(由于在package.json中的配对) rc-picker dayjs 的依赖配置为:“^1.8.30”,初始化项目时,dayjs 最高版本为 1.10.7)。 因为版本一致,所以webpack编译后antd引用的dayjs就是antd-dayjs-webpack-plugin处理的dayjs,所以不会有问题。

升级antd后,antd引用的dayjs升级到1.10.8。 此时插件处理的是dayjs版本1.10.7。 结果antd引用的dayjs只有核心代码,没有任何插件,所以报错。

至此,你就可以解释一下文章开头的配置是如何生效的了。

看看antd是怎么指moment的,

源代码位于:github.com/ant-design/...

import momentGenerateConfig from 'rc-picker/lib/generate/moment';

打开rc-picker的源码,发现rc-picker/lib/generate目录下有对应的dayjs实现webpack 下载报错,即rc-picker/es/generate/dayjs模块。

那么直接让antd引用这个现成的dayjs模块不就可以了吗,于是就有了文章开头的配置。

总结一下对antd的一些期望

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 webpack webpack 下载报错-一行配置将antd中的moment替换为dayjs(vite和webpack均适用) https://www.wkzy.net/game/201294.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务