React实战项目升级日记——实现按需加载和代码拆分



  • 为什么要做代码拆分

    在react实战中,我们已经把第三方组件给单独拿出来了,但是这还是不够的,因为打包后的项目,在部署之后,往往要等好几分钟,于是,代码拆分的想法也就出来了。

    百度到的一个教程:React-router-v4 - Webpack 实现按需加载(code-splitting):

    react-routrt v4中的代码拆分

    百度发现,如果是react-router 3的话,可以使用getComponent这个API来进行代码拆分,因为它是异步的,在组件匹配到的时候,才会调用。但是在react-router4的话,这个API就没有了~

    中文文档:Code Splitting | 代码拆分

    在router4的中文文档中看到,需要使用 Webpack 和 bundle loader 。

    那么就照着中文文档来进行一次代码拆分的操作。

    安装 bundle-loader

    npm install bundle-loader --save-dev

    创建 Bundle 组件

    import React, { Component } from 'react'
    
    class Bundle extends Component {
      state = {
        // "module"的缩写但这是js中的关键字"mod"
        mod: null
      }
    
      componentWillMount() {
        this.load(this.props)
      }
    
      componentWillReceiveProps(nextProps) {
        if (nextProps.load !== this.props.load) {
          this.load(nextProps)
        }
      }
      /**
       * 这个组件有个从webpack得到的load,当组件渲染或者得到一个新的load prop的时候,它就会去调用load。
       *
       */
      load(props) {
        this.setState({
          mod: null
        })
        props.load((mod) => {
          this.setState({
            // 同时处理 es 导入 和 cjs
            mod: mod.default ? mod.default : mod
          })
        })
      }
    
      render() {
        return this.props.children(this.state.mod)
      }
    }
    
    export default Bundle
    

    使用 Bundle 组件进行按需加载

    <Bundle load={() => import('./something')}>
      {(mod) => ()}
    </Bundle>
    

    如果搭配路由的话

    //按需加载
    const Dashboard = (props) => (
        <Bundle load={() => import('../components/dashboard/Dashboard')}>
            {(Dashboard) => <Dashboard {...props}/>}
        </Bundle>
    );
    
    //引入路由
    <Route exact path={`${appurl}/dashboard/index`} component={Dashboard} />
    

    为什么用Bundle loader而不是import()呢?

    好像是说,import已经用了很多年了,他们准备换一个新的~

    然后,bundle loader的另一个好处就是,第二次同步调用的时候,屏幕不会闪烁。。。反正我没用成功import,因为用了之后会报错~

    Unexpected '!' in 'bundle-loader?lazy!./component/chat'. Do not use import syntax to configure webpack loaders import/no-webpack-loader-syntax
    Search for the keywords to learn more about each error.

    再加上一个高阶组件lazyLoad,让代码看起来更加舒服点~

    import React from 'react';
    import Bundle from './Bundle';
    
    // 默认加载组件,可以直接返回 null
    const Loading = () => <div>Loading...</div>;
    
    /*
       包装方法,第一次调用后会返回一个组件(函数式组件)
       由于要将其作为路由下的组件,所以需要将 props 传入
    */
    const lazyLoad = loadComponent => props => (
        <Bundle load={loadComponent}>
            {Comp => (Comp ? <Comp {...props} /> : <Loading />)}
        </Bundle>
    );
    
    export default lazyLoad;
    

    修改路由~

    可以直接用lazyLoad来进行操作了~

    类似于前面的那个Bundle load

    const Dashboard = lazyLoad(() => import('../components/dashboard/Dashboard'));
    

    剩下的就和正常使用一样了

    打包之后,就会是这样的,感觉还不错,起码打开的时候不用等太久了~

    File sizes after gzip:
    
      325.71 KB  build\static\js\vendor.0a45c13b.js
      228.54 KB  build\static\js\charts.97055a2f.js
      82.53 KB   build\static\js\main.3be6ef1e.js
      41.09 KB   build\static\js\0.a9626723.chunk.js
      39.88 KB   build\static\js\1.fc2307f1.chunk.js
      38.45 KB   build\static\js\2.4c15e74f.chunk.js
      37.15 KB   build\static\js\4.13198a09.chunk.js
      15.32 KB   build\static\js\3.6168b8e5.chunk.js
      3.8 KB     build\static\css\main.af514e41.css
    
    

Log in to reply
 

Looks like your connection to 新前端社区 was lost, please wait while we try to reconnect.