Go straight to code

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

Resolve is the Resolve field in the WebPack or Vite configuration file.

Tips: Even if you successfully imported dayJS using the above configuration (or if you imported dayjs using the official recommended method), if you want to pass the default value of dayJS type to the time-dependent component of ANTD, Make sure that the dayJS version of this default value is the same as the dayJS version configured in rC-picker’s package.json. Rc-picker is an dependence of ANTD. See below for reasons.

The ANTD version in this article is: 4.18.9

TLTR

You don’t want to read that much, you can just drag it out and see the summary.

First look at the official alternative

Design /docs/react/…

There are two main methods described in the documentation, one is to define your own components, and the other is a plug-in for WebPack. For me, this document has the following puzzles:

  • Why antD uses moment by default?

  • Why is it possible to replace moment with the method in the documentation?

There are no answers in the documentation. Here again, I have to compliment you on the way You document it, and tell you why before I teach you how to use it.

I have not researched why ANTD uses moment by default, but I have researched why moment can be replaced according to the documentation. For those of you who are interested in the principle, please read on.

The cause of

It has been more than half a year since REACT + ANTD was used in the project. When I used the Table component of ANTD, I found that the usage method in the document could not achieve the effect. Later, I found that the version of the document was inconsistent with the ANTD version I used. I checked the documentation for older versions and found no instructions on how to use them. Finally, I had to choose to upgrade ANTD.

It is not a good choice to rely on three-party brainless upgrades. Many three-party libraries are not guaranteed to be backward-compatible, and even if they are, they may inadvertently fail to test properly and cause new problems with the upgrade.

After the upgrade, there was probably a smoke test and everything was fine. I admired ANTD immediately. Big factory is big factory, and its stability is guaranteed.

Clone error is generated when you click on the time selection box.

An instance of dayJS called a nonexistent weekday method.

I immediately went to see the configuration of Webpack, and found that webpack uses antD-dayjs-webpack-plugin to replace moment with dayjs. I clearly remember that there was no error when I used this plug-in before, which is probably caused by antD upgrade.

At this time, I trust ANTD and antD-dayjs-webpack-plugin very much. I believe it is the way I use it that has the problem.

Then I did the following:

  1. Check antD’s documentation on how to replace moment to see if it’s updated. The conclusion is that there is no update, it is still the old way of replacement.

  2. I checked the github of ANTD-dayjs-webpack-plugin to see if there is any update description. I found that this plug-in has not been updated for several months, and I did not find the situation similar to what I said in Issues. Even if I found it, there has been no official reply from issues for a long time.

At this point I began to have some doubts about ANTD.

In the end, I chose the best way to solve the NPM problem, and that is, re-install it! Sure enough, after reloading, the problem was solved and the error disappeared!

If it were any other library, the story would probably end here, but it is ANTD, it is ant produced, I trust it so much, how can it go wrong?

warren

Since there’s nothing in the ANTD documentation to find out why you can replace the moment as it says, take a look for yourself.

First look at the source code of ANTD-dayjs-webpack-plugin, from which I can understand why I can replace moment.

The plugin does the following:

  • It adds a resolve.alias configuration to Webpack, which adds a resolve.alias configuration to webpackmomentThe module reference points todayjsModule:

Source code address: 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'}}}Copy the code

So webPack will refer to DayJS instead when it encounters a module reference moment.

  • It then installs plug-ins for DayJS by injecting JS code directly.
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);
}

Copy the code

Add an “init-dayjs-webpack-plugin-entry.js” to the webpack entry so that the webpack will load the JS file. The plugin then writes a loader called init-loader.js to parse “init-dayjs-webpack-plugin-entry.js”. The main thing init-loader.js does is inject js code:

Source: 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;
};
Copy the code

At this point, the plug-in is done, and it produces the following effect, which is important enough to know:

The boundle package compiled by WebPack contains the following code (omitted, mainly importing DayJS and installing various plug-ins for DayJS) :

var dayjs = __webpack_require__(/ *! dayjs/dayjs.min */ ". / node_modules/.pnpm/registry.npmmirror.com + [email protected] / node_modules/dayjs/dayjs. Min. Js. "");
var isSameOrBefore = __webpack_require__(/ *! dayjs/plugin/isSameOrBefore */ ". / node_modules/.pnpm/registry.npmmirror.com + [email protected] / node_modules/dayjs/plugins/isSameOrBefore js. "");
dayjs.extend(isSameOrBefore);
/ /... Omit some of the code that installs other plug-ins
Copy the code

What this plugin does is it injects this code, then uses alias to change the reference to dayJS for the moment and we can use DayJS happily.

The moment referenced by antd is now referenced by dayjs by webpack, and the plugin is installed. Wait, what seems to be wrong?

Webpack only imports the version pointed to by dayjs configured in package.json in the project root directory and installs the plugin for this version, so what if ANTD is not referencing this version?

Yes, after we upgraded ANTD, the version of dayJS referenced by ANTD was inconsistent with the version of dayJS introduced by antD-Dayjs-webpack-plugin. While antd does eventually refer to dayJS instead of moment via the plugin, it does not refer to the same version, and the dayJS referenced by ANTd is just a piece of core code without any plug-ins installed, thus generating the above error.

How does ANTD quote moment

Specifically, antD references moment by referring to an RC-picker via ANTD, which in turn references moment. The RC-picker referenced by ANTD will have the dayJS dependency installed even if the dependency is not configured in package.json in our project, but only if it is referenced by the RC-picker. This leads to this serious problem:

If the DAYJS referenced by rC-Picker is not the same version as the dayJS referenced by antD-dayjs-webpack-plugin, the antD-dayjs-webpack-plugin will cause an error in antD components that use dayJS

In my project, antD-dayjs-webpack-plugin was used to introduce 1.10.7 version of DAYJS in the first configuration. Antd is also referenced to version 1.10.7 (because dayJS dependence in package.json in RC-picker is set to “^1.8.30”, dayJS is the highest version 1.10.7 when the project is initialized). Since the versions are consistent, the dayJS referenced by ANTD after webPack compilation is the dayJS processed by ANTD-dayjs-webpack-plugin, so there will be no problems.

After antD was upgraded, dayJS referenced by ANTD was upgraded to 1.10.8. At this time, dayJS referenced by ANTD was processed by 1.10.7 version of DayJS. As a result, dayJS referenced by ANTD only had core code without any plug-ins, so an error was reported.

Can you explain how the configuration at the beginning of this article works

See how ANTD quotes moment,

Source: github.com/ant-design/…

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

The rc-picker/es/generate/dayjs module can be found in the rc-picker/lib/generate directory.

Antd can refer to the existing dayJS module directly, so you have the configuration at the beginning of this article.

So just to summarize

  • First of all, this configuration is simple, but it is not tree-shaking for the dayJS plug-in. This configuration basically lets RC-Picker use its own dayJS import. Thus the introduction of weekday, localeData, weekOfYear, weekYear, advancedFormat, customParseFormat plug-ins. Some of these plug-ins are required by ANTD, and some probably aren’t. (ANTD should not use all the functionality of rC-Picker. However, the addition of plug-ins is not big, after the introduction of the problem is not big)

  • Even if you use the official way of introducing DayJS, please pay attention to the warning at the beginning of this article. Make sure that the version of the dayJS object you give antD is the same as the version of dayJS that it refers to itself (this is not specifically pointed out in the official documentation today, it is a pit).

A little expectation of ANTD

  • Hopefully, the official documentation will explicitly tell users to be aware of dayJS versions when passing in default DayJS objects.

  • We hope that the official documentation can tell users why antD uses moment and how antd uses moment. Then tell the reader why you can replace moment with the plugin or replacement code provided by the official website. Currently, the two alternatives provided by the authorities do not tell users how to choose at all, thus causing greater mental burden to users.

  • Finally, is it possible to change the way ANTD currently introduces moment to make it easier to replace moment, since this is really a very common requirement?