在 create-react-app 中从 node_modules 导入使用基于路由的延迟加载的模块时,代码拆分是否应该以相同的方式工作?

When importing a module from node_modules that uses route based lazy loading in create-react-app, should code splitting work in the same way?

我使用 create-react-app (react ^17.0.2, react-scripts 4.0.3) 构建了一个简单的应用程序,它使用基于路由的延迟加载来执行代码拆分。当我构建这个应用程序时,我看到每个延迟加载的组件都创建了单独的块,这一切都很好,因为我的所有组件都是使用默认导出的。我的输出是:

build/static/js/2.xxxxxxxx.chunk.js
build/static/js/runtime-main.xxxxxxxx.js
build/static/js/main.xxxxxxxx.chunk.js
build/static/js/3.xxxxxxxx.chunk.js
build/static/js/5.xxxxxxxx.chunk.js
build/static/js/4.xxxxxxxx.chunk.js

然后我更新了我的 package.json 文件以包含以下条目:

{
  ...
  "main": "dist/App"
  "publishConfig": { "registry": "http://my-private-repo" }
  ...
  "scripts" : {
    ...
    "prepublishOnly": "rm -rf dist && mkdir dist && npx babel src -d dist --copy-files"
  },
  ...
  "devDependencies": {
    "@babel/cli: "^7.16.0",
    "@babel/core: "^7.16.5"
  },
  ...
  "files": [
    "dist/*"
  ]
}

使用这个配置和一个 babel.config.js 文件,然后我将我的应用程序发布到我的私人仓库,有效地使用 Babel CLI 转换 src 目录中的所有内容,在发布内容之前将其复制到 dist 文件夹那个文件夹。 babel.config.js 仅包含:

module.exports = {
  presets:[
    "@babel/preset-env",
    "@babel/preset-react"
  ]
}

接下来,我创建了另一个 create-react-app,并在其根目录中创建了一个 .yarnrc 文件,其中的注册表项包含我的私有存储库。例如:

registry "http://my-private-repo"

然后我执行了一个 yarn add 命令:

yarn add 'my-other-application'

这会将第一个应用程序添加为这个应用程序的依赖项。这成功地将代码复制到 node_modules

在第二个应用程序的 index.js 中,然后我使用以下方法导入我的第一个应用程序:

import App from 'my-other-application'

然后我使用标准渲染:

<ReactDOM.render(
  <ReactStrictMode>
    <App />
  </ReactStrictMode>
);

运行 第二个应用程序,一切都呈现出来,我可以很好地在路线上导航。但是我注意到第一个应用程序的延迟加载行为似乎并没有发生。我通过构建应用程序确认了这一点,并且可以看到生成的块数少于我的第一个应用程序:

build/static/js/2.xxxxxxxx.chunk.js
build/static/js/runtime-main.xxxxxxxx.js
build/static/js/main.xxxxxxxx.chunk.js

这对我来说表明,我的位于 node_modules 的模块的动态导入的代码拆分并没有以我期望的方式得到尊重。我期待看到与我的第一个应用程序类似的分块模式。通过阅读有关该主题的文章,我目前可以得出的唯一结论是,我的第一个应用程序的代码最终进入了供应商块,并且没有发生进一步的拆分。有谁能对此有所了解吗?我期望通过 create-react-app 提供的默认 webpack 配置可以实现吗?

免责声明:这些技术对我来说是相当新的,所以如果我从根本上误解了某些事情或者我正在尝试做一些完全非常规的事情,我深表歉意。

在发布上述内容后不久,在橡皮鸭调试的经典意义上。我意识到我可以测试我关于代码拆分由于从 node_modules 加载模块而不起作用的理论。只需将我的转译代码直接发布到我的 /src 文件夹中,然后从那里加载组件即可。我这样做了,代码拆分仍然没有发生,这就免除了 create-react-app webpack 配置的参与。

相反,它在转译阶段提出了一个问题,并且通过更集中的 google 搜索,我在这个线程中找到了答案:https://github.com/babel/babel/issues/10273#issuecomment-517838332

问题出在我的 babel.config.js 它需要更新以包含 preset-env 的 false 模块值。例如:

module.exports = {
  presets:[
    ["@babel/present-env, { modules: false }],
    "@babel/preset-react"
  ]
}

在我这样做之后,一切都开始按我预期的那样工作。关键指标是生成的转译组件保留了所有导入语句。而不是将它们转换为承诺,这是在配置更改之前发生的事情,也是阻止 webpack 执行代码拆分的原因。