是2019年! 每个人都认为他们知道代码拆分。 所以-让我们仔细检查!

代码拆分代表什么?
简而言之-代码拆分几乎不会加载整个东西。 然后,您正在阅读此页面,而不必加载整个网站。 当您从数据库中选择一行时-您不必全部使用。
明显吗? 代码拆分也很明显,不仅涉及数据,还涉及代码。
谁(什么?)正在拆分代码?
React.lazy
吗? 不-它只使用它。 代码拆分是在捆绑程序级别上完成的-Webpack,宗地,或者只是您的文件系统,以防使用“本地” esm模块。 代码拆分只是文件,可以在“后期”加载的文件。 所以-对于“ 什么是增强代码拆分能力? ”的问题-答案是-“捆绑程序”。
谁在使用代码拆分?
React.lazy
正在使用。 仅使用捆绑程序的代码拆分。 渲染时只调用import。 仅此而已。
什么是React-loadable?
React.lazy
取代了它。 并提供了更多功能,例如Suspense
来控制加载状态。 所以-使用React.Lazy
代替。
是的,仅此而已。 感谢您的阅读,并祝您愉快。
为什么文章没有完成?
好吧 我忘了提到关于React.lazy
和代码拆分的一些灰色区域。
灰色区域1-测试
由于React.lazy
的异步性,要测试它并不容易。 只要尚未加载(即使已加载),它就是“空”- Promises
和import
返回,并且懒惰地接受, 保证 ,总是在下一个tick中执行。
建议的解决方案? 您不会相信,但是建议的解决方案是使用同步容器 - 请参阅pull request 。 所以-让我们的imports
同步! (以解决测试或其他服务器端情况的延迟问题)
const LazyText = lazy(() => ({ then(cb) { cb({default: Text});
将导入函数转换为记忆同步同步并不难。
const syncImport = (importFn) => { let preloaded = undefined; const promise = importFn().then(module => preloaded = module);
灰色区域2-SSR
如果您不需要SSR,请继续阅读本文!
React.lazy
是SSR友好的。 但这需要Suspense
起作用,并且Suspense 不是服务器端友好的 。
有两种解决方案:
这是一个不错的选择,但它对客户端不十分友好。 怎么了 让我们定义第二种可能的解决方案:
- 在React水合之前,使用专门的库来跟踪使用的脚本,块和样式,并将它们加载到客户端(尤其是样式!)上。 否则-您将呈现空洞而不是代码拆分的组件。 再说一遍-您没有加载刚刚拆分的代码,因此您无法渲染任何内容。
看代码拆分库
- 通用组件 -最古老且仍可维护的库。 它从“教导” Webpack到代码拆分方面“发明”了代码拆分。
- React-loadable-非常流行,但是没有维护。 使代码随处可见。 问题已经关闭,因此周围没有社区。
- 可加载组件 -功能齐全的库,很高兴与周围最活跃的社区一起使用。
- 导入的组件 -不绑定到Webpack的单个库,即能够处理包裹或esm。
- React-async-component-已经死了的库(至今很流行),它对代码拆分,自定义React树遍历和SSR周围的一切都产生了重大影响。
- 另一个库-有很多库,其中许多库都无法在Webpack演进或React 16中生存-我没有在这里列出它们,但是如果您知道一个不错的候选人-DM我。
选择哪个图书馆?
它很容易- 不可加载 -它笨重且无法维护,即使它仍然非常流行也是如此。 (再次感谢您推广代码拆分)
可加载组件 -可能是一个很好的选择。 它编写得很好,积极维护并支持所有现成的东西。 支持“完全动态导入”,允许您根据给定的道具导入文件,但无法键入。 支持Suspense,因此可以替换React.lazy。
通用组件 -实际上是完全动态导入的“发明人”-他们在Webpack中实现了它。 还有许多其他低级别的东西-他们做到了。 我会说-这个库有点硬核,对用户的友好程度也不高。 可加载组件文档无与伦比。 如果不使用该库,那么值得阅读文档,这是值得的-您应该知道很多细节...
React-imported-component-有点奇怪。 它是独立于捆绑器的,因此它永不中断(没有中断),可以与Webpack 5和55一起使用,但这需要付出一定的代价。 虽然在SSR期间以前的库会将所有使用的脚本添加到页面正文中,但是您将能够并行加载所有脚本-导入的文件名不知道,并且将调用原始的“导入”(这就是为什么捆绑独立的)加载已使用的块,但只能从主捆绑包内部进行调用-因此,所有其他脚本只有在下载并执行主脚本后才能加载。 不支持像React.lazy这样的完全动态导入,因此不支持输入。 还支持暂挂。 在SSR上使用同步对象 。 对于CSS,它也有完全不同的方法,并提供完善的流呈现支持。
列出的库之间在质量或受欢迎程度上没有区别,我们都是好朋友-因此,请放心选择。
灰色区域3-混合渲染
SSR是一件好事,但是,很难。 小型项目可能希望拥有SSR-有很多理由拥有它-但他们可能不想设置和维护它。
SSR可能真的非常困难。 如果想快速获胜,请尝试razzle或使用Next.js。
因此,我最简单的SSR解决方案(尤其是简单SPA的解决方案)是预渲染。 就像在浏览器中打开SPA并点击“保存”按钮。 像:
没有“服务器”的预渲染是“ SSR”。 它是使用客户端的SSR。 魔术! 开箱即用……但不是为了代码随地吐痰。
因此,您只是在浏览器中呈现了页面,保存了HTML,并要求加载相同的内容。 但是没有使用服务器端特定代码(收集所有使用的块),因为没有服务器 !

在上一部分中,我已经指出了与Webpack绑定的库,这些库在收集有关已用块的信息方面完全无法处理混合渲染。
react-snap部分支持可加载组件的版本2(与当前版本5不兼容)。 支持已经消失了。
只要没有绑定到bundler /端,react-imported-component就可以处理这种情况,因此对于SSR或Hybrid,只要支持“状态水合作用”,就没有区别,仅对于react-snap,而rendertron则没有。
在撰写本文期间发现了react-imported-component的这种功能,以前未知,请参见示例 。 这很容易。
在这里,您必须使用另一种解决方案,该解决方案垂直于所有其他库。
React组件
该库是为部分水合而创建的,可以对应用程序进行部分水合,其余部分仍保持脱水状态。 它适用于SSR和Hybrid渲染器,没有任何区别。
这个想法很简单:
- SSR期间-渲染组件,并用<div />包裹
- 在客户端上-找到该div,并使用innerHTML,直到Component准备好替换无效的HTML。
- 您不必加载,并等待一个带有拆分组件的块,然后
hydrate
以不呈现白洞而不是呈现它 -只需使用预渲染的HTML,该HTML绝对等于一个真实组件可以渲染的HTML,并且已经存在-它带有服务器(或液压)响应。
这就是为什么我们必须等待所有块加载后才能水化- 匹配服务器渲染的HTML。 这就是为什么我们可以使用服务器渲染的HTML片段,直到客户端未准备好-它等于我们将要生产的片段。
import {PrerenderedComponent} from 'react-prerendered-component'; const importer = memoizeOne(() => import('./Component'));
您可以阅读有关该技术的另一篇文章 。 但主要是这里-它以另一种方式解决了“卸载内容的闪烁”,这不是代码拆分库的常见方式。 公开寻求新的解决方案。
TLDR?
- 不要使用react-loadable,它不会增加任何有价值的价值
- React.lazy很好,但是太简单了。
- SSR很难,您应该知道
- 混合木偶驱动的渲染是一回事。 有时甚至更难的事情。