一、为什么要 Code Splitting?
先给大家看看未进行 Code Splitting
之前的文件的加载大小:
这个是进行 Code Splitting
之后的文件加载大小:
在构建 React.js
单页应用程序时,Create React App
将生成一个大文件,包含我们的应用程序所需的所有 JavaScript
,随着项目的需求扩大和完善,该文件也会随之增大,初次加载时可能会有大量的不必要的组件和文件,增加我们加载的时间,这很明显影响了用户体验。为了就解决这个问题,我们这里通过 import()
来进行拆分我们的代码,将 JavaScript
代码分成多个块 (chunk)
,实现动态加载所需文件,称为 Code Splitting
。
Code Splitting主要有两种方式:
-
分离第三方库(vendor)
CommonsChunkPlugin
分离 vendor/library
代码,从 Webpack v4
开始,它 CommonsChunkPlugin
被删除了 optimization.splitChunks
,开箱即用 SplitChunksPlugin
应该适合大多数用户。
-
按需加载(利用 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';
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