代码分离知多少

一、为什么要进行代码拆分

在以往的性能优化清单中,减少HTTP请求一直是其中的一项。事实上,也做到了。在目前的大多数应用开发中都会用到 webpack 进行应用的构建打包,从而将我们应用以及应用所需的模块打包成一个大 bundle。这样也确实是减少了HTTP的请求。但是这样做有几个明显的劣势:

  1. 首屏加载时间过长,导致白屏,移动端网络不稳定尤甚
  2. 当你修改了业务代码以后,整个大的 bundle 要重新下载。

二、怎样对代码进行拆分

先看一下webpack进行代码分离的几种方法:

  • 在入口处配置entry进行分离
  • 防止重复,使用CommonsChunkPlugin去重和分离chunk
  • 动态导入:使用模块的内联函数
1、在入口处配置进行分离
entry: {
        app: './src/entry.js',
        vendor: ['react', 'react-dom']
    },

对于一些不常变动的库,比如框架,第三方依赖等等,可以直接在入口就进行代码的分离,就好比这里的reactreact-dom

2、防止重复,使用CommonsChunkPlugin

这个插件可以将公共模块依赖提取到已有的chunk中,比如下面这样

new webpack.optimize.CommonsChunkPlugin({
    name: 'common',
}),

当然,这个插件在webpack4.0以上的版本被废弃掉了,具体的可以查看SplitChunksPlugin

3、使用import()来进行动态导入

import()的相关文档可以查看import()相关文档

当然,使用import()需要用到babel-plugin-syntax-dynamic-import插件

import()的使用如下:

import('lodash').then(_ => {
    // do something
})

但这样写的话,每次都很麻烦,这里有一个高阶组件来处理这个事情

import React from 'react';

export default function asyncComponent(importComponent) {
  class AsyncComponent extends React.Component {
    constructor(props){
      super(props);
      this.state = {
        Component: null,
      }
    }
    componentDidMount() {
       importComponent().then(module => {
        // const { default: component } = res;
         this.setState({ Component: module.default });
       });
    }
    render(){
      const { Component } = this.state;
      return Component ? <Component { ...this.props } /> : null;
    }
  }
  return AsyncComponent;
}

有了这个高阶组件,使用就方便了:

const Result = asyncComponent(() => import('./container/result/result'))

import规范不允许控制模块的名称或其他的属性,因为chunkswebpack的概念。如果像上面那样直接使用的话,输出的就像下面这样

图片描述

好在webpack可以注释接受一些特殊的参数,但还要在配置文件的output加上chunkFilename

// 第一处修改
 const Result = asyncComponent(() => import(/* webpackChunkName: "result" */ './container/result/result'))
// 第二处修改
output: {
        path: '/',
        publicPath: '/',
        chunkFilename: '[name].bundle.js',
        filename: '[name].[hash].js',
    },

这样,上面的模块就会被命名为result.bundle.js,而不是[id].bundle.js

其实做到这一步,就已经做到了代码拆分。但是有一个比较好的库更适合做这个事情,这个库就是react-loadable,使用如下:

const Home = Loadable({
    loader: () => import(/* webpackChunkName: "Home" */ './container/Home/home'),
    loading: () => {
        return <div>loading</div>
    },
})

有的组件加载实在过快(<200ms),那么这个我们可以给一Loading组件来设置延迟时间

function Loading(props) {
  if (props.error) {
    return <div>Error! <button onClick={ props.retry }>Retry</button></div>;
  } else if (props.pastDelay) {
    return <div>Loading...</div>;
  } else {
    return null;
  }
}

接着使用react-loadable

const Home = Loadable({
    loader: () => import(/* webpackChunkName: "Home" */ './container/Home/home'),
    loading: Loading,
    delay: 200, // 200ms内加载出来的话,不显示加载状态
})

想了解更多react-loadable,可以点击react-loadable

完整代码
import React from 'react';
import { Route, Router, BrowserRouter, HashRouter, Switch, Redirect } from 'react-router-dom';
import { ConnectedRouter } from 'react-router-redux';
import createHistory from 'history/createHashHistory';
import App from './container/app';
import Loadable from 'react-loadable';

const Home = Loadable({
    loader: () => import(/* webpackChunkName: "Home" */ './container/Home/home'),
    loading: () => {
        return <div>loading</div>
    }
})

const Result = Loadable({
    loader: () => import(/* webpackChunkName: "result" */ './container/result/result'),
    loading: () => {
        return <div>loading...</div>
    }
})

const history = createHistory();

class Routers extends React.Component {
    render() {
        return (
            <HashRouter>
                <App>
                    <Switch>
                        <Route exact path="/" render={() => (<Redirect to="/home" />)} />
                        <Route path="/home" component={Home} />
                        <Route path="/second" component={Result} />
                    </Switch>
                </App>
            </HashRouter>
        )
    }
}
export default Routers;
最后

代码拆分有两种思路,一种是基于路由拆分,一种是基于组件拆分

图片描述

左边这幅图是基于路由拆分的示意图,右边的是基于组件拆分的示意图,可以看到基于组件进行拆分的粒度更细一点。

考虑这样一个场景,你有多个tab,可能有一些tab你从进入应用到离开应用都不会去点击它,那么每个tab页面下的组件就很适合进行代码拆分。这完全根据你的应用场景来决定的。

如果你想对你的一些组件进行拆分,也是同样的使用react-loadable

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值