前言:项目加载的时候,不加载全部代码,只加载对应路由需要的组件,属于前端优化范畴。
原理:利用打包工具将代码拆分成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} />