一、為什么要動態加載模塊
webpack在打包react應用時會將整個應用打包成一個js文件,當用戶首次訪問時,會加載整個js文件,當應用規模越來越大時,這個js文件所包含的數據量也越來越大,網站首屏渲染的速度也就會變慢。
二、優化方法
常見的優化方法有一下3種:
1、多入口:利用webpack的entry配置多入口,將應用打包分割成多個js文件。適用於多頁面應用。
2、去重:利用splitChunks去重,將公用的部分分離出來。
3、路由動態加載:利用import()方法細顆粒度的分割代碼,將每一個路由到的組件從主bundle.js文件分離出來。
這里主要介紹路由動態加載的方法,社區已有較為成熟的第三方庫react-loadable。本文討論不借助第三方庫來實現。webpack支持ECMA提案的import()方法,它返回的是一個promise對象,在webpack打包的時候會先遍歷所有的import()方法,然后將每個import()的組件打包成獨立的chunk,與主bundle.js文件分離。這樣應用首屏渲染時加載的數據量就減少了,提高了首屏的速度。當路由跳轉時,會異步加載相應的chunk。然后配合ssr技術有優化首屏加載的問題。
路由動態加載組件實現如下:
import * as React from 'react'; export default (loadComponent, loading = '加載中') => { return class AsyncComponent extends React.Component { state = { Child: null } async componentDidMount() { const { Child } = await loadComponent(); this.setState({ Child }) } render() { const { Child } = this.state; return Child ? <Child {...this.props} /> : loading } } }
使用時routes.js
import AsyncComponent from './component/AsyncComponent'; export default [ { name: '首頁', path: '/', component: AsyncComponent(()=> import('./pages/home')) }, { name: '詳情', path: '/detail', component: AsyncComponent(()=> import('./pages/detail')) }, ]
因為import()返回的是一個promise對象,所以可以再componentDidMount里使用await來等待異步加載組件,整個實現就是利用高階組件和import()方法。