On-demand load optimization of front-end performance (React-router+webpack)

Source: Internet
Author: User
One, what is load on demand


As with the asynchronous load script (asynchronously loading the script method), on-demand load/code cutting can also solve the first screen loading speed.


    • When you need to load on demand


If it is a large file, it is appropriate to use on-demand loading. For example, a nearly 1M of national cities and counties of the JSON file, when I load the first screen does not need to be introduced, but when the user click on the option to load. If you do not click, it will not load. You can shorten the number of first-screen HTTP requests and the time.



If it's a small file, you don't have to be too concerned about loading on demand. Excessive HTTP requests can cause performance problems.


Second, the method of implementing on-demand loading
    1. Webpack Packaging Module Tool implementation
    2. Requirejs implementation


Here are theReact-router+Webpackfeatures that implement on-demand loading, with the following effects:


Third, the realization process (react-router4.0)

Attention! I am using the latest version of react-router-dom^4.3.1. If it is under 4.0, React-route can look directly at four


4.0 is more complex than the previous implementation. The Bundle-loader module needs to be introduced. and create your own bundle model implementations.


1. Create a wrapper component model 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 method, used to update the mod state
    load (props) {
        // initialize
        this.setState ({
            mod: null
        });
        / *
            Call the incoming load method and pass in a callback function
            This callback function receives the component obtained asynchronously inside the load method and updates it to mod
        * /
        props.load (mod => {
            this.setState ({
            mod: mod.default? mod.default: mod
            });
        });
    }

    render () {
        / *
            Pass the mod component in the existing state as a parameter to the 'child' of the currently wrapped component
        * /
        return this.state.mod? this.props.children (this.state.mod): null;
    }
}

export default Bundle;
2. Method (function) for creating packaging components
// Lazy loading method
import React from 'react';
import Bundle from './Bundle';

console.log (Bundle);
// Load the component by default, you can directly return null
const Loading = () => <div> Loading ... </ div>;

/ *
   Wrapping method, a component (functional component) will be returned after the first call
   Since you want to use it as a component under the route, you need to pass in props
* /

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

console.log (lazyLoad);
export default lazyLoad; // In fact, lazyLoad is a function, the component can call
The relationship between the above two files:
From the name, lazyLoad.js is called lazy loading. It is actually a middleware. Finally, lazyLoad will expose a function for the component to call. The content exported by lazyLoad:

function lazyLoad (loadComponent) {
    return function (props) {
        return (
            <Bundle load = {loadComponent}>
                {Comp => (Comp? <Comp {... props} />: <Loading />)}
            </ Bundle>
        )
    }
}
Obviously, loadComponent is the component to be loaded, which is called in the route, for example: asynchronously calling page1

<Route path = "/ page1" component = {lazyLoad (Page1)} />
As the core of on-demand loading, Bundle.js has been introduced in lazyLoad middleware, and a custom method load is passed in, which is the component content. And the dynamic sub-content children:

{Comp => (Comp? <Comp {... props} />: <Loading />)}
Finally, return the component information, with the corresponding props. If there is no relevant component, then Loading
3. Route used together
import React from 'react';
import {NavLink, Route, Switch, BrowserRouter as Router} from 'react-router-dom'
import './style/style.css'
import 'bundle-loader'
// The bundle model is used to load components asynchronously
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;
A few points to note:
When importing components asynchronously, the name changes to 'bundle-loader? lazy & name = page1! ../ components / page1 / index'
Where bundle-loader means loader: 'bunle-loader' (need to load the bundle-loader module)
lazy means lazy: true; lazy loading
name: indicates the name of the file generated asynchronously

It is also feasible to remove the outer route and render without rendering
<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'), // packing place
            filename: 'bundle.js', // Package name
            publicPath: '/', // Automatically generate the path of HTML into JS
            // Load on demand
            chunkFilename: '[name] _ [chunkhash: 8] .js'
        },
        ...
    }
...
Pay attention to the publicPath parameter here.
If the publicPath parameter is not set, the default when the packaged html is introduced into the bundle is:

<script type = "text / javascript" src = "bundle.js"> </ script>
If you set publicPath to publicPath: '/ dist', the js format of the HTML file after packaging is:

<script type = "text / javascript" src = "/ dist / bundle.js"> </ script>
Reference article: React-router-v4-Webpack implements on-demand loading (code-splitting)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.