前端效能最佳化之按需載入(React-router+webpack)

來源:互聯網
上載者:User
一、什麼是按需載入

和非同步載入script的目的一樣(非同步載入script的方法),按需載入/代碼切割也可以解決首屏載入的速度。

  • 什麼時候需要按需載入

如果是大檔案,使用按需載入就十分合適。比如一個近1M的全國城市省市縣的json檔案,在我首屏載入的時候並不需要引入,而是當使用者點擊選項的時候才載入。如果不點擊,則不會載入。就可以縮短首屏http請求的數量以及時間。

如果是小檔案,可以不必太在意按需載入。過多的http請求會導致效能問題。

二、實現按需載入的方法
  1. Webpack打包模組工具實現
  2. RequireJs實現

這裡介紹React-router+Webpack實現按需載入的功能,效果如下:

三、實現過程(React-router4.0)

注意!我這裡使用的是最新版本的React-router-dom^4.3.1.如果是4.0以下的react-route可直接看四

4.0相比以前實現方式要複雜。需要引入bundle-loader模組。並且自己建立bundle模型實現。

1.建立封裝組件模型bundle.js
import React from 'react';class Bundle extends React.Component {    constructor(arg){        super(arg)        this.state = {            mod: null,        }    }        componentWillMount() {        this.load(this.props);    }    componentWillReceiveProps(nextProps) {        if (nextProps.load !== this.props.load) {            this.load(nextProps);        }    }    // load 方法,用於更新 mod 狀態    load(props) {        // 初始化        this.setState({            mod: null        });        /*            調用傳入的 load 方法,並傳入一個回呼函數            這個回呼函數接收 在 load 方法內部非同步擷取到的組件,並將其更新為 mod         */         props.load(mod => {            this.setState({            mod: mod.default ? mod.default : mod            });        });    }    render() {        /*            將存在狀態中的 mod 組件作為參數傳遞給當前封裝組件的'子'        */         return this.state.mod ? this.props.children(this.state.mod) : null;    }}export default Bundle ;
2.建立封裝組件的方法(函數)
// 懶載入方法import React from 'react';import Bundle from './Bundle';console.log(Bundle);// 預設載入組件,可以直接返回 nullconst Loading = () => <div>Loading...</div>;/*   封裝方法,第一次調用後會返回一個組件(函數式組件)   由於要將其作為路由下的組件,所以需要將 props 傳入*/const lazyLoad = loadComponent => props => (   <Bundle load={loadComponent}>      {Comp => (Comp ? <Comp {...props} /> : <Loading />)}   </Bundle>);console.log(lazyLoad);export default lazyLoad;    //實際上lazyLoad就是一個函數,組件調用即可

上面兩個檔案的關係:
lazyLoad.js從名字上看,叫懶載入.實際上是一個中介軟體的作用。最後lazyLoad會暴露一個函數出來供組件調用。lazyLoad匯出的內容:

function lazyLoad(loadComponent) {    return function(props) {        return (            <Bundle load={loadComponent}>                {Comp => (Comp ? <Comp {...props} /> : <Loading />)}            </Bundle>        )    }}

顯而易見,loadComponent就是要載入的組件,在路由中調用,例如:非同步呼叫page1組件

<Route path="/page1" component={lazyLoad(Page1)}/> 

Bundle.js作為按需載入的核心,在lazyLoad中介軟體就已經引入,並傳入一個自訂的方法load,值為組件內容。以及動態子內容children:

{Comp => (Comp ? <Comp {...props} /> : <Loading />)}

最終返回組件資訊,並附帶相應的props.如果不存在相關組件,則Loading

3. Route搭配使用
import React from 'react';import { NavLink,Route,Switch,BrowserRouter as Router } from 'react-router-dom'import './style/style.css'import 'bundle-loader'// bundle模型用來非同步載入組件import Bundle from '../routes/Bundle.js';import lazyLoad from '../routes/lazyLoad';import Page1 from 'bundle-loader?lazy&name=page1!../components/page1/index';import Page2 from 'bundle-loader?lazy&name=page2!../components/page2/index';import Page3 from 'bundle-loader?lazy&name=page3!../components/page3/index';class AppPage extends React.Component{    constructor(arg){        super(arg)        this.state={}    }    render(){        return(            <Router  basename="/" >                <div className="appWried">                    <div className="appBtn">                        <NavLink to="/page1" className="button" activeClassName="active">                            PAGE1                        </NavLink>                        <NavLink to="/page2" className="button" activeClassName="active">                            PAGE2                        </NavLink>                        <NavLink to="/page3" className="button" activeClassName="active">                            PAGE3                        </NavLink>                    </div>                    <Route                        path="/"                        render={props => (                            <Switch>                                <Route path="/page1" component={lazyLoad(Page1)}/>                                 <Route path="/page2" component={lazyLoad(Page2)}/>                                 <Route path="/page3" component={lazyLoad(Page3)}/>                             </Switch>                        )}                    />                </div>            </Router>        )    }}export default AppPage;
  • 幾個注意的點:
    1. import非同步載入組件的時候,名字變更為'bundle-loader?lazy&name=page1!../components/page1/index'

    其中bundle-loader表示loader:'bunle-loader'(需載入bundle-loader模組)
    lazy表示lazy:true;懶載入
    name:表示非同步產生的檔案名稱字

    1. 去掉外層route,不用render渲染也是可行的
    <Switch>    <Route path="/page1" component={lazyLoad(Page1)}/>     <Route path="/page2" component={lazyLoad(Page2)}/>     <Route path="/page3" component={lazyLoad(Page3)}/> </Switch>
//webpack.config.js...    module.exports = {        ...        output:{            path:path.join(__dirname + '/dist'),    //打包地方            filename:'bundle.js',    //打包名字            publicPath: '/',    //自動產生html引入js的路徑            //按需載入            chunkFilename:'[name]_[chunkhash:8].js'        },        ...    }...

這裡要注意一下publicPath這個參數.
如果未設定publicPath參數,則預設打包產生的html引入bundle的時候為:

<script type="text/javascript" src="bundle.js"></script>

如果設定publicPath為publicPath: '/dist',則打包後html檔案引入js格式為:

<script type="text/javascript" src="/dist/bundle.js"></script>

參考文章:React-router-v4 - Webpack 實現按需載入(code-splitting)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.