【React】Code Splitting(上)

asyncComponent

Posted by ARTROY on 2019-07-05

一、为什么要 Code Splitting?

先给大家看看未进行 Code Splitting 之前的文件的加载大小:
图1
这个是进行 Code Splitting 之后的文件加载大小:
图1
在构建 React.js 单页应用程序时,Create React App 将生成一个大文件,包含我们的应用程序所需的所有 JavaScript,随着项目的需求扩大和完善,该文件也会随之增大,初次加载时可能会有大量的不必要的组件和文件,增加我们加载的时间,这很明显影响了用户体验。为了就解决这个问题,我们这里通过 import() 来进行拆分我们的代码,将 JavaScript 代码分成多个块 (chunk),实现动态加载所需文件,称为 Code Splitting

Code Splitting主要有两种方式:

  1. 分离第三方库(vendor)
    CommonsChunkPlugin 分离 vendor/library 代码,从 Webpack v4 开始,它 CommonsChunkPlugin 被删除了 optimization.splitChunks,开箱即用 SplitChunksPlugin 应该适合大多数用户。

  2. 按需加载(利用 import() 语法)
    (1)@babel/plugin-syntax-dynamic-import
    (2)babel-plugin-dynamic-import-webpack
    (3)proposal-dynamic-import

二、Code Splitting + Router v4?

2.1 创建异步组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const asyncComponent = (importComponent) => {
return class AsyncComponent extends React.Component {
static Component = null;
state = { Component: AsyncComponent.Component };

componentWillMount() {
if (!this.state.Component) {
importComponent().then(({default: Component}) => {
AsyncComponent.Component = Component
this.setState({ Component })
})
}
}
render() {
const { Component: C } = this.state
return C ? <C {...this.props} /> : null;
}
}
}

2.2 使用异步组件

原来静态导入:

1
2
3
4
5
6
7
8
9
10
11
import Home from '../mobile/Home';
import Detail from '../mobile/Detail';

export default class Router extends Component {
render() {
<Switch>
<Route exact path={'/'} component={Home} />
<Route exact path={'/detail'} component={Detail} />
</Switch>
}
}

修改成动态加载:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const load = component => {
return import(`../mobile/${component}`);
}

const Home = asyncComponent(() => load('Home'));
const Detail = asyncComponent(() => load('Detail'));

export default class Router extends Component {
render() {
<Switch>
<Route exact path={'/'} component={Home} />
<Route exact path={'/detail'} component={Detail} />
</Switch>
}
}

2.3 优化异步组件

页面跳转是请求过长或者请求失败进行优化。
安装:
npm i -S react-loadable
router.js 文件下引入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import Loadable from 'react-loadable';

// import Home from '../mobile/Home';
// import Detail from '../mobile/Detail';
const load = component => {
return import(`../mobile/${component}`);
}

const LoadComponent = ({ isLoading, error }) => {
if (isLoading) { // 加载等待
return <div><Loader active size='large' content='Loading' /></div>;
} else if (error) { // 错误
return <div>error</div>;
} else {
return null;
}
};

const Home = Loadable({
loader: () => load('Home'),
loading: LoadComponent
});
const Detail = Loadable({
loader: () => load('Detail'),
loading: LoadComponent
});

// 引入改回初始的样子
export default class Router extends Component {
render() {
<Switch>
<Route exact path={'/'} component={Home} />
<Route exact path={'/detail'} component={Detail} />
</Switch>
}
}

参考资料:
Code Splitting in Create React App
Webpack 大法之 Code Splitting



支付宝打赏 微信打赏

欣赏此文,打赏一下



-->