前言:專案載入的時候,不載入全部程式碼,只載入對應路由需要的元件,屬於前端優化範疇。
原理:利用打包工具將程式碼拆分成chunk,然後動態建立script標籤,並將src屬性指向對應的chunk的路徑即可。
因為要單獨打包程式碼塊,所以webpack統一配置chunkFileName和publicPath欄位,前者為打包後的chunk檔案命名,後者為所有靜態檔案引入新增路徑字首。
方式一:(react-loadable)
import React from 'react';import ReactDOM from 'react-dom';import { BrowserRouter, Route, Link } from 'react-router-dom';import Loadable from 'react-loadable';
function LoadableAnotherComponent({ error }) { if (error) { return <div>Error!</div>; } else { return <div>Loading...</div>; }}class MyComponent extends React.Component { // loading元件 render() { return <LoadableAnotherComponent/>; } }
const HomePage =() => <div>Home Page</div> // 業務元件const UsersPage = () => <div>Users Page</div>
const HomePage2 = Loadable({ loader: () => import(/* webpackChunkName: "home" */'./component/homePage'), // import()返回一個promise,then裡面的data對應返回的module。 loading: MyComponent})const UsersPage2 = Loadable({ loader: () => import(/* webpackChunkName: "user" */'./component/userPage'), loading: MyComponent})function Layout() { return ( <BrowserRouter> <div> <Link exact to="/">首頁</Link> <Link to="/users">使用者</Link> <Route path="/" exact component={HomePage2} /> <Route path="/users" component={UsersPage2} /> </div> </BrowserRouter> );}
ReactDOM.render(<Layout />, document.getElementById('box'));複製程式碼
方式二:bundle-loader + Bundle包裝元件
import React from 'react';import ReactDOM from 'react-dom';import { BrowserRouter, Route, Link } from 'react-router-dom';import HomePage from 'bundle-loader?lazy!./component/homePage'; // bundle-loader底層為require.ensure方法,返回一個方法lazy參數列示懶載入,否則引入時就會執行對應的module。import UserPage from 'bundle-loader?lazy!./component/userPage';
function LoadableAnotherComponent({ error }) { console.log(error) return (error ? <div>{error}</div> : <div>loading.............</div>);}class MyComponent extends React.Component { render() { return <LoadableAnotherComponent/>; }}class Bundle extends React.Component { // 包裝元件類似上面的react-loadable state = { // short for "module" but that's a keyword in js, so "mod" mod: null } componentWillMount() { // 載入初始狀態 this.load(this.props); } componentWillReceiveProps(nextProps) { if (nextProps.load !== this.props.load) { this.load(nextProps); } } load(props) { // 重置狀態 this.setState({ mod: null }); // 傳入元件的元件 console.log(props.load); props.load((mod) => { console.log(mod) this.setState({ // handle both es imports and cjs mod: mod.default ? mod.default : mod }); }); } render() { // if state mode not undefined,The container will render children return this.state.mod ? this.props.children(this.state.mod) : null; } } const HomePageC = (props) => { return ( <Bundle load={HomePage}> {(Container) => <Container {...props} />} </Bundle> );}const UserPageC = (props) => { return ( <Bundle load={UserPage}> {(Container) => <Container {...props} />} </Bundle> );}
function Layout() { return ( <BrowserRouter> <div> <Link to="/">首頁</Link> <Link to="/users">使用者</Link> <Route path="/" exact component={HomePageC} /> <Route path="/users" component={UserPageC} /> </div> </BrowserRouter> );}
ReactDOM.render(<Layout />, document.getElementById('box'));複製程式碼
方式三:require.ensure + (react-router3的getComponent)
const about = (location, cb) => {
require.ensure([], require => { // require.ensure是CommonJs的唯一的動態載入模組方法。
cb(null, require('../Component/about').default)
},'about')
}
//配置route
<Route path="about" getComponent={about} />複製程式碼