一、为什么要进行代码拆分
在以往的性能优化清单中,减少HTTP
请求一直是其中的一项。事实上,也做到了。在目前的大多数应用开发中都会用到 webpack
进行应用的构建打包,从而将我们应用以及应用所需的模块打包成一个大 bundle
。这样也确实是减少了HTTP
的请求。但是这样做有几个明显的劣势:
- 首屏加载时间过长,导致白屏,移动端网络不稳定尤甚
- 当你修改了业务代码以后,整个大的
bundle
要重新下载。
二、怎样对代码进行拆分
先看一下 webpack
进行代码分离的几种方法:
- 在入口处配置
entry
进行分离 - 防止重复,使用
CommonsChunkPlugin
去重和分离chunk
- 动态导入:使用模块的内联函数
1、在入口处配置进行分离
1 | entry: { |
对于一些不常变动的库,比如框架,第三方依赖等等,可以直接在入口就进行代码的分离,就好比这里的react
、react-dom
2、防止重复,使用 CommonsChunkPlugin
这个插件可以将公共模块依赖提取到已有的chunk中,比如下面这样
1 | new webpack.optimize.CommonsChunkPlugin({ |
当然,这个插件在webpack
4.0以上的版本被废弃掉了,具体的可以查看SplitChunksPlugin
3、使用import()
来进行动态导入
import()
的相关文档可以查看import()相关文档
当然,使用import()
需要用到babel-plugin-syntax-dynamic-import
插件
import()
的使用如下:
1 | import('lodash').then(_ => { |
但这样写的话,每次都很麻烦,这里有一个高阶组件来处理这个事情
1 | import React from 'react'; |
有了这个高阶组件,使用就方便了:
1 | const Result = asyncComponent(() => import('./container/result/result')) |
import
规范不允许控制模块的名称或其他的属性,因为chunks
是webpack
的概念。如果像上面那样直接使用的话,输出的就像下面这样
好在webpack
可以注释接受一些特殊的参数,但还要在配置文件的output
加上chunkFilename
1 | // 第一处修改 |
这样,上面的模块就会被命名为result.bundle.js
,而不是[id].bundle.js
。
其实做到这一步,就已经做到了代码拆分。但是有一个比较好的库更适合做这个事情,这个库就是react-loadable
,使用如下:
1 | const Home = Loadable({ |
有的组件加载实在过快(<200ms),那么这个我们可以给一Loading
组件来设置延迟时间
1 | function Loading(props) { |
接着使用react-loadable
1 | const Home = Loadable({ |
想了解更多react-loadable
,可以点击react-loadable
完整代码
1 | import React from 'react'; |
最后
代码拆分有两种思路,一种是基于路由拆分,一种是基于组件拆分
左边这幅图是基于路由拆分的示意图,右边的是基于组件拆分的示意图,可以看到基于组件进行拆分的粒度更细一点。
考虑这样一个场景,你有多个tab,可能有一些tab你从进入应用到离开应用都不会去点击它,那么每个tab页面下的组件就很适合进行代码拆分。这完全根据你的应用场景来决定的。
如果你想对你的一些组件进行拆分,也是同样的使用react-loadable