React Loadable

歡迎訪問我的最佳實踐網(wǎng)站

React Loadable

一個動態(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/>;
  }
}

用戶反饋:

用戶

_ 如果你的公司或者項目也在使用 React Loadable歼疮,請加入這個列表(按照字母順序)

Also See:

  • react-loadable-visibilityreact-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(代碼分割)到我們的項目中了!

A single giant bundle vs multiple smaller bundles

Code-splitting(代碼分割)是把項目中一個大的入口文件分割成多個小的韩脏、單獨的文件的進程缩麸。

這看起來很難,但是一些類似于Webpack的工具已經(jīng)做到這些了赡矢,并且React Loadable是為了讓這件事兒變得更加簡單杭朱。

Route-based splitting(基于路由的代碼風格) vs. Component-based splitting(基于組件的代碼分割)

一般我們建議通過不同路由切斷你的程序,并且異步加載它們吹散,這對于大多數(shù)應用來講很不錯-在瀏覽器里一個用戶點擊一個鏈接并且等待頁面加載完成是一個在正常不過的行為弧械。

但是我們可以做的更好。

在React的大多數(shù)路由工具中空民,一個路由就是一個簡單的組件,這真沒有什么特殊的(Sorry Ryan和Michael-你們是特殊的)刃唐。所以我們?nèi)绻ㄟ^組件而不是路由優(yōu)化分割代碼,我們會得到什么呢?

Route vs. component centric code splitting

事實證明:相當多画饥。不僅僅是通過路由衔瓮,還有更多的地方你可以將你的應用程序拆分出來,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組件會接收一個errortrue的prop(否則為false).

function Loading(props) {
  if (props.error) {
    return <div>Error!</div>;
  } else {
    return <div>Loading...</div>;
  }
}

避免 Loading 組件閃爍的問題

有時候你的組件加載速度非常快(<200ms),Loading組件的loading效果在屏幕上一閃而過.
許多用戶反饋膝捞,這樣的效果會導致用戶認為等待的時間要比實際時間還要長坦刀,但是如果你什么都不顯示,用戶反而認為加載很快蔬咬。

所以你的loading compoent將會得到一個布爾類型為truepastDelay 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ù)LoadableLoadable.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
});

查看關于更多delay.

opts.timeout

props.timedOut超時的毫秒數(shù)后顯示loading組件蹂楣,默認是關閉的。

Loadable({
  timeout: 10000
});

更多關于 timeouts.

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

LoadableLoadable.Map返回的組件.

const LoadableComponent = Loadable({
  // ...
});

當組件加載的時候調(diào)用opts.render方法旭等,它會直接接收props參數(shù)酌呆。

LoadableComponent.preload()

LoadableComponent調(diào)用的一個靜態(tài)方法,可以讓組件預加載搔耕。

const LoadableComponent = Loadable({...});

LoadableComponent.preload();

返回一個代理隙袁,但是盡量避免此代理阻塞你的UI更新,否則會帶來非常不好的用戶體驗弃榨。

關于更多 preloading.

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,
});

關于更多 loading components

props.error

LoadingComponent的一個布爾類型的參數(shù)扮念,當loader模塊加載失敗的時候苗踪,為true.

function LoadingComponent(props) {
  if (props.error) {
    return <div>Error!</div>;
  } else {
    return <div>Loading...</div>;
  }
}

更多關于 errors.

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>;
  }
}

更多關于 timeouts.

props.pastDelay

LoadingComponent設置delay參數(shù)后关划,props.pastDelay將接受一個布爾類型的返回值.

function LoadingComponent(props) {
  if (props.pastDelay) {
    return <div>Loading...</div>;
  } else {
    return null;
  }
}

更多關于delays.

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)用matchingLoadableComponent.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.webpackopts.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')],
});

更多關于declaring modules.

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>
`);
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末胖缤,一起剝皮案震驚了整個濱河市尚镰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哪廓,老刑警劉巖狗唉,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異涡真,居然都是意外死亡分俯,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門哆料,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缸剪,“玉大人,你說我怎么就攤上這事剧劝¢系牵” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵讥此,是天一觀的道長拢锹。 經(jīng)常有香客問我,道長萄喳,這世上最難降的妖魔是什么卒稳? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮他巨,結果婚禮上充坑,老公的妹妹穿的比我還像新娘。我一直安慰自己染突,他們只是感情好捻爷,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著份企,像睡著了一般也榄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天甜紫,我揣著相機與錄音降宅,去河邊找鬼。 笑死囚霸,一個胖子當著我的面吹牛腰根,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拓型,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼额嘿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了吨述?” 一聲冷哼從身側響起岩睁,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎揣云,沒想到半個月后捕儒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡邓夕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年刘莹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片焚刚。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡点弯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出矿咕,到底是詐尸還是另有隱情抢肛,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布碳柱,位于F島的核電站捡絮,受9級特大地震影響,放射性物質發(fā)生泄漏莲镣。R本人自食惡果不足惜福稳,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瑞侮。 院中可真熱鬧的圆,春花似錦、人聲如沸半火。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钮糖。三九已至梅掠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓤檐。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留娱节,地道東北人挠蛉。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像肄满,于是被迫代替她去往敵國和親谴古。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Ba la la la ~ 讀者朋友們稠歉,你們好啊掰担,又到了冷鋒時間,話不多說怒炸,發(fā)車带饱! React 組件代碼...
    王飽飽閱讀 2,431評論 1 1
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,116評論 25 707
  • 無意中看到zhangwnag大佬分享的webpack教程感覺受益匪淺,特此分享以備自己日后查看阅羹,也希望更多的人看到...
    小小字符閱讀 8,164評論 7 35
  • 首先感恩本元跟本然兩位大愛的老師勺疼,也感恩我們班主任丁丁老師,也感恩我的父母以及詹靜老師捏鱼,貝貝老師和所有關心我支持我...
    當下綻放閱讀 830評論 0 0
  • //數(shù)據(jù)挖掘(六):預測 - kingzone的專欄 - 博客頻道 - CSDN.NEThttp://blog.c...
    葡萄喃喃囈語閱讀 346評論 0 0