一個動態(tài)導入加載組件的高階組件.
示例
import Loadable from 'react-loadable';
import Loading from './my-loading-component';
const LoadableComponent = Loadable({
loader: () => import('./my-component'),
loading: Loading,
});
export default class App extends React.Component {
render() {
return <LoadableComponent/>;
}
}
用戶反饋:
- "我現(xiàn)在非常癡迷于: create-react-app、React Router v4 和 react-loadable的使用. 自由的代碼分割, 太簡單了."
- "Webpack 2 upgrade & react-loadable; 花兩個小時就可以將初始化加載文件從1.1mb降到529kb."
- "Oh hey - 使用 loadable 組件 讓我初始化加載文件降到13kB. yeah!輕松搞定"
- "太令人驚嘆了. 讓我主打包文件減少了50kb."
- "我使用了 server-side rendering(服務端渲染) + code splitting(代碼分割) + PWA ServiceWorker 來緩存數(shù)據(jù)和資源 ?? (感謝 react-loadable). 現(xiàn)在我的前端程序快到飛起."
用戶
_ 如果你的公司或者項目也在使用 React Loadable歼疮,請加入這個列表(按照字母順序)
Also See:
-
react-loadable-visibility
和react-loadable
使用相同的API構建, 這個組件能讓你動態(tài)加載只顯示在屏幕上的組件.
<h2>
<img src="http://thejameskyle.com/img/react-loadable-guide.png" alt="GUIDE">
<small>Guide</small>
</h2>
所以你現(xiàn)在有了一個React App, 并且你用Webpack去打包你的應用, 所有的事情看起來是那么的順暢. 但是有一天你突然發(fā)現(xiàn)你的文件變得越來越大杂抽,打包變得越來越慢。
這時候我們是時候該引入 code-splitting(代碼分割)到我們的項目中了!
Code-splitting(代碼分割)是把項目中一個大的入口文件分割成多個小的韩脏、單獨的文件的進程缩麸。
這看起來很難,但是一些類似于Webpack的工具已經(jīng)做到這些了赡矢,并且React Loadable是為了讓這件事兒變得更加簡單杭朱。
Route-based splitting(基于路由的代碼風格) vs. Component-based splitting(基于組件的代碼分割)
一般我們建議通過不同路由切斷你的程序,并且異步加載它們吹散,這對于大多數(shù)應用來講很不錯-在瀏覽器里一個用戶點擊一個鏈接并且等待頁面加載完成是一個在正常不過的行為弧械。
但是我們可以做的更好。
在React的大多數(shù)路由工具中空民,一個路由就是一個簡單的組件,這真沒有什么特殊的(Sorry Ryan和Michael-你們是特殊的)刃唐。所以我們?nèi)绻ㄟ^組件而不是路由優(yōu)化分割代碼,我們會得到什么呢?
事實證明:相當多画饥。不僅僅是通過路由衔瓮,還有更多的地方你可以將你的應用程序拆分出來,Modals抖甘、tabs還有許多隱藏的UI組件热鞍,當用戶執(zhí)行某些操作的時候,你再去加載他們单山。
Example: 假設你的主應用程序是在一個選項卡里,用戶可能永遠也不會進入這個選項卡下的應用程序碍现,所以父路由組件為何要加載這個選項卡所對應的組件呢?
還有一個地方米奸,你可以優(yōu)先加載優(yōu)先級高的組件昼接。那些頁面底部的組件為何要和頁面頂部的組件同時加載呢?
由于路由即組件悴晰,所以我們?nèi)匀豢梢院茌p松的在組件層面做code-split(代碼分割)
在一個新項目中使用code-spliting
非常簡單慢睡,以至于你都不用想兩遍,你只需要改動少量代碼就可以完成自動的代碼分割铡溪。
React Loadable 簡介
React Loadable 是一個輕量級的代碼分割組件漂辐,它簡單到令人難以置信。
Loadable
是一個告誡組件 (一個創(chuàng)建并返回組件的函數(shù))棕硫,它能讓你的應用程序在渲染之前動態(tài)的加載任何模塊
想象有兩個組件髓涯,一個組件是import
的組件,另一個是渲染組件
import Bar from './components/Bar';
class Foo extends React.Component {
render() {
return <Bar/>;
}
}
現(xiàn)在我們通過import
引入Bar
這個組件哈扮,這是一個同步的引入纬纪,但是我們在渲染之前是并不需要這個組件的,所以我們?yōu)楹尾煌七t引入這個組件呢滑肉?
使用 dynamic import(動態(tài)引入) (a tc39 proposal currently at Stage 3)
我們可以修改組件Bar
使之成為一個異步的包各。
class MyComponent extends React.Component {
state = {
Bar: null
};
componentWillMount() {
import('./components/Bar').then(Bar => {
this.setState({ Bar });
});
}
render() {
let {Bar} = this.state;
if (!Bar) {
return <div>Loading...</div>;
} else {
return <Bar/>;
};
}
}
但是這是一整個工作流程,并不是單純的代碼分割這一件事兒這么簡單靶庙,比如當import()
失敗我們該怎么辦问畅?怎么作server-side rendering(服務端渲染)?這時候你可以抽象出Loadable
來解決這些問題六荒。
import Loadable from 'react-loadable';
const LoadableBar = Loadable({
loader: () => import('./components/Bar'),
loading() {
return <div>Loading...</div>
}
});
class MyComponent extends React.Component {
render() {
return <LoadableBar/>;
}
}
通過 import()
自動 code-splitting(代碼分割)
在webpack2+中护姆,當你使用import()
的時候,它會為你自動代碼分割掏击,而不用做外的設置签则。
這意味著通過使用React Loadable和import()
可以很快的實驗出新的代碼分割點來,這是程序中的最佳實踐.
創(chuàng)建一個更好的"Loading..." 組件
渲染一個靜態(tài)的"Loading..."已經(jīng)不能傳達出足夠的信息給用戶了铐料。有時有我們還要想要表現(xiàn)出更多的狀態(tài)來渐裂,比如錯誤和超時等,這是一個非常好的經(jīng)歷豺旬。
function Loading() {
return <div>Loading...</div>;
}
Loadable({
loader: () => import('./WillFailToLoad'), // oh no!
loading: Loading,
});
這樣做非常好,你的loading component會接收多個不同的props柒凉。
Loading 的錯誤狀態(tài)
當loader
加載失敗族阅,loading component組件會接收一個error
為true
的prop(否則為false
).
function Loading(props) {
if (props.error) {
return <div>Error!</div>;
} else {
return <div>Loading...</div>;
}
}
避免 Loading 組件閃爍的問題
有時候你的組件加載速度非常快(<200ms),Loading組件的loading效果在屏幕上一閃而過.
許多用戶反饋膝捞,這樣的效果會導致用戶認為等待的時間要比實際時間還要長坦刀,但是如果你什么都不顯示,用戶反而認為加載很快蔬咬。
所以你的loading compoent
將會得到一個布爾類型為true
pastDelay
prop的返回值鲤遥,當組件的加載時間比設置的delay時間長的時候。
function Loading(props) {
if (props.error) {
return <div>Error!</div>;
} else if (props.pastDelay) {
return <div>Loading...</div>;
} else {
return null;
}
}
默認的delay
參數(shù)為200ms
林艘,但是你可以根據(jù)需要自定義delay這個參數(shù)值
Loadable({
loader: () => import('./components/Bar'),
loading: Loading,
delay: 300, // 0.3 seconds
});
loader
超時
有時候網(wǎng)絡連接斷開或者失敗盖奈,或者永久性掛起,這時候網(wǎng)頁無反應狐援,用戶不知道是繼續(xù)等待還是重新刷新頁面钢坦。這時候當loader
超時后loading component 將會接收一個timedOut
prop 并且這個只值為true
function Loading(props) {
if (props.error) {
return <div>Error!</div>;
} else if (props.timedOut) {
return <div>Taking a long time...</div>;
} else if (props.pastDelay) {
return <div>Loading...</div>;
} else {
return null;
}
}
然而這個特性默認是被禁止的,如果想打開特性啥酱,你可以通過timeout
option參數(shù)傳遞給 Loadable
.
Loadable({
loader: () => import('./components/Bar'),
loading: Loading,
timeout: 10000, // 10 seconds
});
自定義渲染
Loadable
會渲染default
導出的組件爹凹,如果你想渲染自定義導出的組件,請使用render
option參數(shù)
Loadable({
loader: () => import('./my-component'),
render(loaded, props) {
let Component = loaded.namedExport;
return <Component {...props}/>;
}
});
加載多個資源
從技術上講镶殷,你可以用loader()
加載任何只要是一個promise的資源you're able to render something禾酱,但是這樣用起來確實有點讓人惱火。
你可以使用Loadable.Map
讓加載多個資源變得更加容易一些绘趋。
Loadable.Map({
loader: {
Bar: () => import('./Bar'),
i18n: () => fetch('./i18n/bar.json').then(res => res.json()),
},
render(loaded, props) {
let Bar = loaded.Bar.default;
let i18n = loaded.i18n;
return <Bar {...props} i18n={i18n}/>;
},
});
當使用Loadable.Map
的時候宇植,render()
method是一個必要參數(shù),他會傳遞一個匹配后的對象參數(shù)到loader
中去埋心。
預加載
還有一個優(yōu)化項,你可以決定哪些組件在渲染之前進行預先加載忙上。
比如:當按鈕點擊之前你需要加載一個新的組件拷呆,這個組件是被Loadable
中的static preload
method創(chuàng)建的。
const LoadableBar = Loadable({
loader: () => import('./Bar'),
loading: Loading,
});
class MyComponent extends React.Component {
state = { showBar: false };
onClick = () => {
this.setState({ showBar: true });
};
onMouseOver = () => {
LoadableBar.preload();
};
render() {
return (
<div>
<button
onClick={this.onClick}
onMouseOver={this.onMouseOver}>
Show Bar
</button>
{this.state.showBar && <LoadableBar/>}
</div>
)
}
}
<h2>
<img src="http://thejameskyle.com/img/react-loadable-ssr.png" alt="SERVER SIDE RENDERING">
<small>Server-Side Rendering(服務端渲染)</small>
</h2>
當你渲染所有所有已經(jīng)動態(tài)加載完成的組件的時候疫粥,你將會得到一堆loading的效果茬斧,這看起來確實很糟糕,但是好消息是React Loadable在設計之初就支持服務端渲染的梗逮,這樣就不會出現(xiàn)首屏加載效果了项秉。
我們通過Express開啟一個服務。
import express from 'express';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './components/App';
const app = express();
app.get('/', (req, res) => {
res.send(`
<!doctype html>
<html lang="en">
<head>...</head>
<body>
<div id="app">${ReactDOMServer.renderToString(<App/>)}</div>
<script src="/dist/main.js"></script>
</body>
</html>
`);
});
app.listen(3000, () => {
console.log('Running on http://localhost:3000/');
});
服務端預加載所有的組件
第一件事兒就是在渲染正確的內(nèi)容之前慷彤,確保你的服務端已經(jīng)加載了所有的組件了娄蔼。
我們可以使用 Loadable.preloadAll
這個方法.他會返回一個所有組件加載完成的一個代理怖喻。
Loadable.preloadAll().then(() => {
app.listen(3000, () => {
console.log('Running on http://localhost:3000/');
});
});
服務端拾起客戶端的狀態(tài)
這可能稍微有一些復雜,這可能會話費我們多一些的精力岁诉。
為了能讓客戶端接管服務端的狀態(tài)锚沸,我們需要在服務端使用相同的代碼,
為了實現(xiàn)這一點涕癣,我們首先就要通過loadable組件告訴我們到底哪個組件正在渲染哗蜈。
聲明哪個模塊被加載
這里有兩個參數(shù)Loadable
和Loadable.Map
能告訴我們哪個組件正在加載: opts.modules
和
opts.webpack
Loadable({
loader: () => import('./Bar'),
modules: ['./Bar'],
webpack: () => [require.resolveWeak('./Bar')],
});
但是我們不必太擔心這些參數(shù),React Loadable有一個Babel plugin插件可以完成這些設置坠韩。
將 react-loadable/babel
加入到你的Babel config
中:
{
"plugins": [
"react-loadable/babel"
]
}
現(xiàn)在這些參數(shù)將會被自動被創(chuàng)建距潘。
找出哪些動態(tài)模塊正在被加載
下一步我們將找到當請求進來的時候,哪些模塊是真正需要被加載的只搁。
為此音比,我們有一個Loadable.Capture
組件可以使用,它能收集所有的被加載的模塊须蜗。
import Loadable from 'react-loadable';
app.get('/', (req, res) => {
let modules = [];
let html = ReactDOMServer.renderToString(
<Loadable.Capture report={moduleName => modules.push(moduleName)}>
<App/>
</Loadable.Capture>
);
console.log(modules);
res.send(`...${html}...`);
});
將加載的模塊映射到打文件上
為了確惫枞罚客戶端加載了所有服務端渲染的模塊,我們需要將服務端的模塊和webpack打包出來的打包文件做一個映射明肮。
這包含兩部分,第一部分我們需要讓Webpack告訴我們每個模塊需要哪個打包文件菱农,為此我們可以使用React Loadable Webpack plugin插件,在webpack config中從react-loadable/webpack
引入ReactLoadablePlugin
插件柿估,傳遞一個filename
參數(shù)循未,webpack會將打包文件作為一個JSON數(shù)據(jù)輸出到這個文件中去。
// webpack.config.js
import { ReactLoadablePlugin } from 'react-loadable/webpack';
export default {
plugins: [
new ReactLoadablePlugin({
filename: './dist/react-loadable.json',
}),
],
};
然后我們回到我們的服務端秫舌,用剛才文件中的數(shù)據(jù)將模塊轉換成打包文件的數(shù)據(jù)
將模塊轉換成打包文件的妖,需要從react-loadable/webpack
引入getBundles
方法。
import Loadable from 'react-loadable';
import { getBundles } from 'react-loadable/webpack'
import stats from './dist/react-loadable.json';
app.get('/', (req, res) => {
let modules = [];
let html = ReactDOMServer.renderToString(
<Loadable.Capture report={moduleName => modules.push(moduleName)}>
<App/>
</Loadable.Capture>
);
let bundles = getBundles(stats, modules);
// ...
});
這時候我們可以通過<script>
標簽渲染這些打包后的文件輸出到HTML中足陨。
let bundles = getBundles(stats, modules);
res.send(`
<!doctype html>
<html lang="en">
<head>...</head>
<body>
<div id="app">${html}</div>
<script src="/dist/main.js"></script>
${bundles.map(bundle => {
return `<script src="/dist/${bundle.file}"></script>`
}).join('\n')}
</body>
</html>
`);
客戶端會等待所有的打包文件加載完成
因為Webpack的工作方式是嫂粟,我們的主打包文件會比其他的scripts預先加載,所以我們需要等待所有的文件加載完成后才開始渲染墨缘。
為此我們需要一個全局的函數(shù)供我們調(diào)用當所有的打包文件被加載后星虹,我們將在客戶端使用Loadable.preloadReady()
這個方法,就像在服務器使用Loadable.preloadAll()
這個方法一樣镊讼。
// src/entry.js
import React from 'react';
import ReactDOM from 'react-dom';
import Loadable from 'react-loadable';
import App from './components/App';
window.main = () => {
Loadable.preloadReady().then(() => {
ReactDOM.hydrate(<App/>, document.getElementById('app'));
});
};
這時候在我們服務端返回的HTML的末尾處的 <script>
標簽中調(diào)用那個全局函數(shù)宽涌。
let bundles = getBundles(stats, modules);
res.send(`
...
<script src="/dist/main.js"></script>
${bundles.map(...).join('\n')}
<script>window.main();</script>
</body>
</html>
`);
<h4 align="center">
Now server-side rendering should work perfectly!
</h4>
<h2>
<img src="http://thejameskyle.com/img/react-loadable-api-docs.png" alt="API DOCS">
<small>API 文檔</small>
</h2>
Loadable
rendering前動態(tài)loading模塊的一個高階組件,當模塊無法被加載的時候蝶棋,loading 組件會被渲染.
const LoadableComponent = Loadable({
loader: () => import('./Bar'),
loading: Loading,
delay: 200,
timeout: 10000,
});
它返回一個 LoadableComponent組件.
Loadable.Map
一個允許你并行加載多個資源點的高階組件卸亮。
Loadable.Map's opts.loader
接收一個對象,并且需要opts.render
方法
Loadable.Map({
loader: {
Bar: () => import('./Bar'),
i18n: () => fetch('./i18n/bar.json').then(res => res.json()),
},
render(loaded, props) {
let Bar = loaded.Bar.default;
let i18n = loaded.i18n;
return <Bar {...props} i18n={i18n}/>;
}
});
當調(diào)用Loadable.Map
中的render()
方法玩裙, 這個方法中的loaded
參數(shù)將會和loader
方法起到一樣的作用兼贸。
Loadable
and Loadable.Map
Options
opts.loader
一個加載模塊的promose函數(shù)
Loadable({
loader: () => import('./Bar'),
});
當調(diào)用Loadable.Map
的時候段直,它接收對象行函數(shù)。
Loadable.Map({
loader: {
Bar: () => import('./Bar'),
i18n: () => fetch('./i18n/bar.json').then(res => res.json()),
},
});
當調(diào)用Loadable.Map
的時候寝受,你也需要傳遞opts.render
函數(shù)
opts.loading
當模塊加載或者加載失敗的時候坷牛,這個組件會被渲染。
Loadable({
loading: LoadingComponent,
});
這個參數(shù)是必選參數(shù)很澄,如果你不想渲染任何京闰,讓它返回null
就好了。
Loadable({
loading: () => null,
});
opts.delay
延時毫秒數(shù)props.pastDelay
后加載渲染loading
組件甩苛,默認值是200
Loadable({
delay: 200
});
opts.timeout
props.timedOut
超時的毫秒數(shù)后顯示loading
組件蹂楣,默認是關閉的。
Loadable({
timeout: 10000
});
opts.render
自定義渲染加載模塊的函數(shù)
它接收 opts.loader
代理返回的loaded
參數(shù)和LoadableComponent
傳遞的props
兩個參數(shù)讯蒲。
Loadable({
render(loaded, props) {
let Component = loaded.default;
return <Component {...props}/>;
}
});
opts.webpack
可選參數(shù)痊土,可通過require.resolveWeak
獲取返回的一個Webpack模塊id的集合。
Loadable({
loader: () => import('./Foo'),
webpack: () => [require.resolveWeak('./Foo')],
});
這個參數(shù)可通過Babel Plugin自動生成.
opts.modules
可選參數(shù)墨林,imports模塊路徑的數(shù)組集合
Loadable({
loader: () => import('./my-component'),
modules: ['./my-component'],
});
可選參數(shù)赁酝,可通過Babel Plugin插件自動生成。
LoadableComponent
Loadable
和 Loadable.Map
返回的組件.
const LoadableComponent = Loadable({
// ...
});
當組件加載的時候調(diào)用opts.render
方法旭等,它會直接接收props參數(shù)酌呆。
LoadableComponent.preload()
LoadableComponent
調(diào)用的一個靜態(tài)方法,可以讓組件預加載搔耕。
const LoadableComponent = Loadable({...});
LoadableComponent.preload();
返回一個代理隙袁,但是盡量避免此代理阻塞你的UI更新,否則會帶來非常不好的用戶體驗弃榨。
LoadingComponent
傳給opts.loading
方法的一個組件.
function LoadingComponent(props) {
if (props.error) {
// When the loader has errored
return <div>Error!</div>;
} else if (props.timedOut) {
// When the loader has taken longer than the timeout
return <div>Taking a long time...</div>;
} else if (props.pastDelay) {
// When the loader has taken longer than the delay
return <div>Loading...</div>;
} else {
// When the loader has just started
return null;
}
}
Loading({
loading: LoadingComponent,
});
props.error
LoadingComponent
的一個布爾類型的參數(shù)扮念,當loader
模塊加載失敗的時候苗踪,為true
.
function LoadingComponent(props) {
if (props.error) {
return <div>Error!</div>;
} else {
return <div>Loading...</div>;
}
}
props.timedOut
LoadingComponent
組件設置timeout
參數(shù)后,props.timedOut
將接受一個布爾類型的返回值盛嘿。
function LoadingComponent(props) {
if (props.timedOut) {
return <div>Taking a long time...</div>;
} else {
return <div>Loading...</div>;
}
}
props.pastDelay
LoadingComponent
設置delay
參數(shù)后关划,props.pastDelay
將接受一個布爾類型的返回值.
function LoadingComponent(props) {
if (props.pastDelay) {
return <div>Loading...</div>;
} else {
return null;
}
}
Loadable.preloadAll()
等待所有被預加載的組件LoadableComponent.preload
完成加載,允許你在各種環(huán)境里預加載你的組件官辈,比如在服務端箱舞。
Loadable.preloadAll().then(() => {
app.listen(3000, () => {
console.log('Running on http://localhost:3000/');
});
});
注意非常重要的一點,預先加載你所有聲明過的loadable
組件在啟動你的服務.
Good:
// During module initialization...
const LoadableComponent = Loadable({...});
class MyComponent extends React.Component {
componentDidMount() {
// ...
}
}
Bad:
// ...
class MyComponent extends React.Component {
componentDidMount() {
// During app render...
const LoadableComponent = Loadable({...});
}
}
注意:
Loadable.preloadAll()
如果你的項目里有多個Loadable.preloadAll()
,react-loadable
將會失效钧萍。
更多關于 preloading on the server.
Loadable.preloadReady()
檢查瀏覽器里已經(jīng)加載所有模塊并且調(diào)用matching
LoadableComponent.preload
方法
window.main = () => {
Loadable.preloadReady().then(() => {
ReactDOM.hydrate(<App/>, document.getElementById('app'));
});
};
更多關于 preloading on the client.
Loadable.Capture
記錄哪個模塊被渲染的一個組件.
每個被React Loadable組件在被渲染的時候,接收一個被每個moduleName
調(diào)用的report
prop政鼠。
let modules = [];
let html = ReactDOMServer.renderToString(
<Loadable.Capture report={moduleName => modules.push(moduleName)}>
<App/>
</Loadable.Capture>
);
console.log(modules);
更多關于 capturing rendered modules.
Babel Plugin
為每個loadable 組件適配opts.webpack
和opts.modules
參數(shù)是一件很耗費體力的一件事兒风瘦,并且你還要始終記著去做。
你可以用Babel plugin寫到你的配置文件里去讓Webpack自動完成這件事兒公般,從而代替手動去做万搔。
{
"plugins": ["react-loadable/babel"]
}
Input
import Loadable from 'react-loadable';
const LoadableMyComponent = Loadable({
loader: () => import('./MyComponent'),
});
const LoadableComponents = Loadable.Map({
loader: {
One: () => import('./One'),
Two: () => import('./Two'),
},
});
Output
import Loadable from 'react-loadable';
import path from 'path';
const LoadableMyComponent = Loadable({
loader: () => import('./MyComponent'),
webpack: () => [require.resolveWeak('./MyComponent')],
modules: [path.join(__dirname, './MyComponent')],
});
const LoadableComponents = Loadable.Map({
loader: {
One: () => import('./One'),
Two: () => import('./Two'),
},
webpack: () => [require.resolveWeak('./One'), require.resolveWeak('./Two')],
modules: [path.join(__dirname, './One'), path.join(__dirname, './Two')],
});
Webpack Plugin
當服務端渲染的時候胡桨,為了send the right bundles down,你需要React Loadable Webpack plugin
插件生成一個模塊和打包文件有對應關系的JSON文件.
// webpack.config.js
import { ReactLoadablePlugin } from 'react-loadable/webpack';
export default {
plugins: [
new ReactLoadablePlugin({
filename: './dist/react-loadable.json',
}),
],
};
它將產(chǎn)生一個JSON文件(opts.filename
)瞬雹,你可以引入這個模塊和打包文件相對應的JSON文件
更多關于 mapping modules to bundles.
getBundles
通過react-loadable/webpack
方法可以導出一個模塊和打包文件的映射關系.
import { getBundles } from 'react-loadable/webpack';
let bundles = getBundles(stats, modules);
更多關于 mapping modules to bundles.
<h2>
<img src="http://thejameskyle.com/img/react-loadable-faq.png" alt="FAQ">
<small>FAQ</small>
</h2>
如果避免重復調(diào)用?
假定你的Loadable()
會重復設置loading
組件和delay
參數(shù),你可以用高階組件 (HOC)去封裝一層Loadable
,并為它設置一些默認參數(shù).
import Loadable from 'react-loadable';
import Loading from './my-loading-component';
export default function MyLoadable(opts) {
return Loadable(Object.assign({
loading: Loading,
delay: 200,
timeout: 10,
}, opts));
};
這時候你只需要設置loader
就可以使用它昧谊。
import MyLoadable from './MyLoadable';
const LoadableMyComponent = MyLoadable({
loader: () => import('./MyComponent'),
});
export default class App extends React.Component {
render() {
return <LoadableMyComponent/>;
}
}
不幸的是,如果你用HOC對Loadable封裝一層會使react-loadable/babel失效酗捌,所以這時候你需要手動的添加必要參數(shù)(modules
, webpack
).
import MyLoadable from './MyLoadable';
const LoadableMyComponent = MyLoadable({
loader: () => import('./MyComponent'),
modules: ['./MyComponent'],
webpack: () => [require.resolveWeak('./MyComponent')],
});
export default class App extends React.Component {
render() {
return <LoadableMyComponent/>;
}
}
如果在服務端渲染中使用其他的比如.css
或者.map
資源
當你調(diào)用getBundles
方法的時候呢诬,它會返回Javascript依賴的文件類型在你的Webpack配置中.
為得到這些,你需要手動的過濾一下文件類型,像這樣:
let bundles = getBundles(stats, modules);
let styles = bundles.filter(bundle => bundle.file.endsWith('.css'));
let scripts = bundles.filter(bundle => bundle.file.endsWith('.js'));
res.send(`
<!doctype html>
<html lang="en">
<head>
...
${styles.map(style => {
return `<link href="/dist/${style.file}" rel="stylesheet"/>`
}).join('\n')}
</head>
<body>
<div id="app">${html}</div>
<script src="/dist/main.js"></script>
${scripts.map(script => {
return `<script src="/dist/${script.file}"></script>`
}).join('\n')}
</body>
</html>
`);