问题描述
为了减少我的应用程序的初始负载,我尝试进行代码拆分.例如,我成功地拆分了 twilio-video,以便在用户按下呼叫"时加载和初始化
import('twilio-video').then(Video => {Video.connect(twilioInfo.data.token, options).then(room => {...});});
Webpack 正确拆分代码并在需要时加载.
现在我想对组件或路由做同样的事情(当我们站在登录页面时不加载用户配置文件).有没有等价的
const OtherComponent = React.lazy(() => import('./OtherComponent'));
或
const Home = lazy(() => import('./routes/Home'));
或者在遇到路由路径时加载组件的任何其他方式?
过去非常困难.如今,Webpack Module Federation 让它喘不过气来.
他们有大量示例来帮助您入门.>
例如,基本-主机远程示例 有一个适合您需要的简单场景.只需将整个 Github 存储库、cd
提取到此示例中,然后运行它(如每个示例的 README
中所述).
留意网络标签.组件在明确请求之前不会加载.
基本示例
basic-host-remotesample 有两个独立的包:app1
和 app2
.
app1
想使用app2
的组件
- 它将
app2
添加到
app2
提供了一个Button
组件
app2
exposes
Button
在 其 WMF 配置.
- app1/src/App.js 动态加载按钮.(它在初始渲染期间这样做,使得按需加载不那么明显.)
- 时机成熟时,
app1
使用动态import
请求组件. - 它使用 React.lazy 包装负载,如下所示:
const RemoteButton = React.lazy(() => import(app2/Button"));
- 例如,您可以在
useEffect
或Route.render
回调等中执行此操作.
- 例如,您可以在
app1
可以使用该Button
,一旦它被加载.加载时,它使用Suspense
显示加载消息:<React.Suspense fallback={<LoadingScreen/>}><远程按钮/></React.Suspense>
- 或者,您可以不使用
lazy
和Suspense
,而是使用import(...)
语句返回的承诺,然后以您喜欢的任何方式处理异步加载.当然,WMF
完全不限于react
,可以动态加载任何模块. - 请注意,
app1
和app2
具有相同的shared
设置,确保这些共享依赖项仅加载一次,并且未与远程加载的代码捆绑/复制:{//...共享:{反应:{单例:真},反应DOM":{单例:真}},}
另一方面,WMF
动态加载必须使用动态import
(即import(...)
),因为:>
- 非动态导入将始终在加载时解析(因此使其成为非动态依赖项),并且
- "动态
require
"不能被 webpack 捆绑,因为浏览器没有commonjs
的概念(除非你使用了一些 hacks,在这种情况下,你将失去相关的加载promise
").
WMF 示例
WMF 需要一些学习,但它的所有样本都具有以下共同元素:
- 每个示例都有多个独立的包.
- 每个包都有自己的
webpack.config.js
- 每个包通常充当主机(动态提供组件)或此类组件的使用者,或两者兼而有之.
- 在
development
模式下,您通常使用集成良好的webpack-dev-server
提供所有内容.- 注意:在
production
模式下,您需要对配置进行一些小的调整.当webpack-dev-server
不在画面中时,您的构建只会在构建输出中添加一些额外的remoteEntry.js
文件.
- 注意:在
- 您可以使用
shared
配置轻松配置如何处理公共依赖项.(通常您希望它们充当单例,这意味着每个人都应该共享公共依赖项,而不是打包自己的依赖项.) - 如果你想坚持把所有东西都放在一个包里,那可能也是可能的.只需
公开
它并将它自己的(独立的)组件添加到它自己的遥控器
.不确定它是否有效,但值得一试.
最后的话
同样,这需要一点学习曲线,但我发现这绝对值得.感觉就像我见过的最复杂的动态构建 + 加载系统之一.
最烦人的是,WMF 目前在 Webpack 页面上仍然没有适当的 API 文档,但我相信它很快就会出现.目前,只有一个不太完善的概念笔记集..>
WMF 作者本人 承诺提供很快就会有更好的文档™️.
幸运的是,对于学习,示例真的很好,很积极保持并仍在增强.
To reduce the initial load of my app, i try to do code splitting.For exemple, i successfully split twilio-video, to load and initialize when user press "call"
import('twilio-video').then(Video => {
Video.connect(twilioInfo.data.token, options).then(room => {
...
});
});
Webpack correctly split the code and load it when needed.
Now i would like to do the same with components, or routes (to not load user profil while we stand on login page).Is there any equivalent of
const OtherComponent = React.lazy(() => import('./OtherComponent'));
or
const Home = lazy(() => import('./routes/Home'));
or any other way to load component when a route path is hitted?
It used to be very difficult. These days, Webpack Module Federation makes it a breathe.
They have tons of samples to get you started.
For example, the basic-host-remote sample has a simple scenario that fits your need. Just fetch the entire Github repo, cd
into this sample, and run it (as explained in each sample's README
).
Keep an eye open for the Network tab. Components are not loaded until they are explicitely requested.
Basic Example
The basic-host-remote sample has two separate packages: app1
and app2
.
app1
wants to use components fromapp2
- It adds
app2
to itsremotes
in its WMF config
app2
provides aButton
component
app2
exposes
Button
in its WMF config.
- app1/src/App.js loads the button dynamically. (It does so during initial render, making the on-demand loading a lot less obvious.)
- When the time comes,
app1
requests a component using dynamicimport
. - It wraps the load using React.lazy, like so:
const RemoteButton = React.lazy(() => import("app2/Button"));
- E.g., you can do this in a
useEffect
, or aRoute.render
callback etc.
- E.g., you can do this in a
app1
can use thatButton
, once it's loaded. While loading, it shows a loading message, usingSuspense
:<React.Suspense fallback={<LoadingScreen />}> <RemoteButton /> </React.Suspense>
- Alternatively, instead of using
lazy
andSuspense
, you can just take the promise returned from theimport(...)
statement and handle the asynchronous loading any way you prefer. Of course,WMF
is not at all restricted toreact
and can load any module dynamically. - Note that both,
app1
andapp2
have the sameshared
setup, making sure that those shared dependencies are only loaded one time, and not bundled/duplicated with remotely loaded code:{ // ... shared: { react: { singleton: true }, "react-dom": { singleton: true } }, }
On the flip side, WMF
dynamic loading must use dynamic import
(i.e. import(...)
), because:
- non-dynamic imports will always resolve at load time (thus making it a non-dynamic dependency), and
- "dynamic
require
" cannot be bundled by webpack since browsers have no concept ofcommonjs
(unless you use some hacks, in which case, you will lose the relevant "loadingpromise
").
WMF Samples
WMF takes a bit of learning, but all its samples have the following common elements:
- Every sample has multiple independent packages.
- Each package has its own
webpack.config.js
- Each package usually acts as a host (which provides components dynamically) or a consumer of such components, or both.
- In
development
mode, you usually serve up everything using the nicely integratedwebpack-dev-server
.- NOTE: In
production
mode, you want to make some small adjustments to your config. Whenwebpack-dev-server
is out of the picture, your build just adds some additionalremoteEntry.js
files to your build output.
- NOTE: In
- You can easily configure what to do with common dependencies, using the
shared
configuration. (Usually you want them to act as singletons, meaning, everyone should share common dependencies, and not pack their own.) - If you want to insist on keeping everything in one package, that is probably also possible. Just
expose
it and add its own (independent) components to its ownremotes
. Not sure if it works, but its worth trying.
Final Words
Again, it will take a bit of a learning curve, but I find it's definitely worth it. Feels like one of the most sophisticated dynamic build + load systems I have seen.
Most annoyingly, WMF still does not currently have proper API documentation on the Webpack page, but I'm sure it'll come soon enough. Currently, there is only a not all too polished collection of conceptual notes.
The WMF author himself promises to provide better documentation soon™️.
Luckily, for learning, the samples are really good, actively maintained and still being enhanced.
这篇关于Hyperapp/Webpack - 如何编码拆分组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!