作者:键盘上的泪g_752 | 来源:互联网 | 2023-09-24 07:00
域名:
检查repo - common.js 包含所有依赖项,即使在相应页面上只使用了一个。
- http://localhost:3000/components/ComponentOne
- http://localhost:3000/components/ComponentTwo
现场演示:点击这里
更多细节:
我有一个应用程序(找到一个非常简化的版本),其中根据用户输入呈现不同的组件。通过组件映射找到要渲染的组件。common.js 包含切换器页面的所有依赖项是有道理的,其中两个组件都必须可访问(以及它们的依赖项)。但是单个页面包含各自的其他依赖项是没有意义的。
总结一下:
- 我希望能够拥有大量组件,这些组件可以根据用户的输入进行呈现。我的用例对它们进行序列化和反序列化(如此处所示)是不可行的,因为组件非常不同并且需要不同的依赖项
- 我还想将每个组件呈现到它自己的静态生成页面,在那里我从数据库中检索其他 SEO 信息。但是,在这种情况下,我只想为手头的特定组件加载所需的依赖项。
http://localhost:3000
Selecting ComponentOne results in:
使用 recharts.js
Selecting ComponentTwo results in:
使用victory.js
回答
问题
TLDR:Next 的 Webpack 配置将动态加载的组件分块作为自己的块,这可能会创建重复或组合的块依赖项。
在您的示例中,我将组件 1 和 2 分别复制为组件 3 和 4。但是,对于组件 4(它是组件 2 的副本),我添加了一个额外的moment-timezone
依赖项。结果是一个具有重复victory-pie
依赖项的分离块(它还为包和包导入了整个库):
victory
moment-timezone
解释
即使两个 3rd 方图表包之间存在相当多的依赖共享(主要是两者共享d3
依赖),如果组件正在重用恰好具有共享依赖并跨多个路由动态加载的 3rd 方库,Webpack 可能会尝试将这些 3rd 方块组合成一个组合块:
而不是预期的两个或更多块:
但是,正如您在上面的块截图中注意到的那样,即使第 3 方包没有在多个路由中重用/重新导入,您仍然有重复的依赖项(例如,大桃子和柠檬绿色块在上面的屏幕截图包含重复的d3-scale
、d3-time
、d3-path
等依赖块)。
不幸的是,这是通过next/dynamic
(也适用于使用 Webpack 的动态import
语句)导入的组件的必要和预期行为,因为它必须遍历整个每个动态导入的组件的依赖关系图,并(可能)将它们添加为自己的块——换句话说,在动态加载组件的情况下,Webpack 不知道运行时正在加载什么组件,因此它必须创建一个整个块以便能够根据请求加载(即使其他组件可能共享相同的依赖项,它也不会知道)。不仅如此,因为它不知道动态组件中正在导入/使用什么,所以它不能摇树依赖!因此,当您添加更多动态加载的组件时,这会创建非常大且重复的块。
解决方案
不幸的是,真的没有办法解决。即使我尝试手动将这些依赖项分离和分组为它们自己单独的块(以减少冗余/构建大小),组件也将不再呈现。这是有道理的,当每个组件都以某种方式在主应用程序中成为自己独立的“应用程序”时。
在这种情况下,最简单的解决方案是渲染静态图像而不是动态加载的 React 组件(如视频的缩略图)。
其他想法
我查看了 Next 的 Webpack 配置,并取得了一些进展。您可以创建自己的 webpack splitChunks规则供 Next 使用,这将有助于减少一些块冗余;但是,即便如此,我仍然收到重复的块(主要来自d3
共享依赖项)。你可以试试看。绝对不适合胆小的人,因为您将在一个黑洞中追逐一只兔子,并且您将无法实现块分布的完美。也就是说,它确实有助于减少构建尺寸......
以下是一些可用作next.config.js
文件基础的初步工作:
下一个.config.js
module.exports = {
webpack(config, { isServer }) {
/* adds client-side webpack optimization rules for splitting chunks during build-time */
if (!isServer) {
config.optimization.splitChunks.cacheGroups = {
...config.optimization.splitChunks.cacheGroups,
victory: {
test: /[/]node_modules[/](victory-pie|victory-core|victory-pie/es)[/]/,
name: "victory",
priority: 50,
reuseExistingChunk: true,
},
recharts: {
test: /[/]node_modules[/](recharts|recharts-scale)[/]/,
priority: 20,
name: "recharts",
reuseExistingChunk: true,
},
lodash: {
test: /[/]node_modules[/](lodash)[/]/,
name: "lodash",
reuseExistingChunk: true,
priority: 40,
},
};
}
/* return new config to next */
return config;
},
};
When building the app for production, Webpack attempts to group/split dependencies into shareable chunks. That way you have a smaller and more optimized build size. Instead, Webpack can’t automatically determine how to chunk these dependencies, so by using Next’s Webpack configuration in combination with custom rules, we can help Webpack optimize the production build. Take a look at the [Webpack documentation](https://webpack.js.org/concepts/) for more information.