React v16.6 版本引入了React.lazy,Suspense的功能,这个功能主要是利用了webpack对es6的import动态载入组件,能够自动实现Code Splittingcss
Code Splitting就是把代码分红不少个小块(chunk),须要某部分代码的时候再去加载,减少了页面首屏进来加载很大一个js文件的压力,另外拆分红小块还能更好的利用浏览器缓存,下次再用到的话直接从浏览器缓存中读取。node
Beforereact
import OtherComponent from './OtherComponent';
function MyComponent() {
return (
<div>
<OtherComponent />
</div>
);
}
复制代码
Afterwebpack
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<OtherComponent />
</div>
);
}
复制代码
React.lazy接收一个函数做为参数,该函数必须经过调用import来返回一个Promise来加载组件,返回的Promise对象的resolve方法接收组件默认导出的模块es6
若是只是这么使用运行会出现错误,根据提示须要引入Suspense组件 web
Suspense相似于一个错误捕获器,容许定义一个fallback指示符,fallback用来定义咱们在等待加载时显示的一些内容。能够将Suspense组件放在动态加载组件上方的任何位置,若是动态组件未加载,则从该组件开始向上寻找,直到找到Suspense组件。可使用单个Suspense组件包裹多个动态加载组件浏览器
完整示例缓存
const OtherComponent = React.lazy(() => import(/* webpackChunkName:"OtherComponent" */'./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<Loading/>}>
<p>下面是一个动态加载的组件</p>
<OtherComponent />
</Suspense>
</div>
);
}
复制代码
由于个人项目是个多页面应用,我接下来会以desktop.js这个入口来演示,其中vendor.dll.js是一个第三方库分离的文件。bash
能够看到,当前这个js文件大小Gzip压缩以后为603.2kb,没有其余任何异步加载的chunkbabel
不要忘记修改webpack配置
output: {
chunkFilename: "static/js/[name].[chunkhash:8].chunk.js"
},
复制代码
若是使用了babel转译,则须要安装babel-plugin-syntax-dynamic-import
插件来解析动态import语法,修改babel配置
{
"plugins": ["syntax-dynamic-import"]
}
复制代码
看一下打包后的文件大小
能够看到,desktop.js文件已经缩小到了459.69kb,比以前缩小了150kb(由于我只作了部分组件的异步加载,因此文件大小变化不是太大)。下图的Subtile.chunk是我点击按钮以后进行加载的组件
为了对比清晰,我这张图只包含了MultiLayoutDialog.chunk(66.84kb)和MultiLayoutPollingDialog.chunk(47.55kb)两个模块
状况不太乐观,两个组件的node_modules中都分别包含antd/lib,rc-tree,rc-animate,这是由于每一个chunk都是一个独立的可运行的模块,所以会加载本身的依赖,可是显然这是不合理的,应该将这些公共的依赖抽离出来,这个时候你须要用到CommonsChunkPlugin,配置async,用于从异步chunk中抽离公共的资源为一个单独的文件,当首个异步chunk被加载时会同步加载该公共资源文件
从新配置webpack
new webpack.optimize.CommonsChunkPlugin({
async: "common-in-lazy",
minChunks: ({ resource }) =>
resource && resource.indexOf("node_modules") >= 0 && resource.match(/\.js$/),
children: true,
})
// 在全部的async chunk中查找被其中至少2个chunk所共享的node_modules资源,将它们挪到common-in-lazy文件中,没有则新建。
复制代码
再来看提取了公共资源以后的打包文件大小
MultiLayoutDialog.chunk(19.85kb)和MultiLayoutPollingDialog.chunk(26.21kb)两个chunk分别减小了46kb和20kb,(另外还有一些其余的chunk体积也减小了,在此没有截图),公共资源抽离为了common-in-lazy-desktop.chunk,该chunk中包含了以前重复加载的antd/lib,rc-tree,rc-animate等资源,改文件大小为50.09kb
不要觉得到此异步加载就大功告成了,若是你敢build以后部署,你会收到qa小姐姐亲切问候的,由于有些异步加载的组件样式丢失啦,致使页面显示出现问题。正在喝茶的你吓得立马坐正一波谷歌以后,决定将异步chunk的css样式与入口的css合并到一个css文件,只作js的异步chunk加载,修改webpack配置
new ExtractTextPlugin({
filename: cssFilename,
allChunks: true // 默认为false,仅从初始chunk中提取
}),
复制代码
至此,整个异步加载已经所有完成,继续喝茶,总结一下:
1. react的lazy方法须要配合Suspense组件来使用,能够定义异步chunk加载未完成以前的UI显示
2.webpack配置的出口要添加chunkFilename: "static/js/[name].[chunkhash:8].chunk.js"
3.若是使用了babel,为避免babel将异步import转译,则须要安装额外的插件来识别动态import
4.打包的异步chunk会各自包含本身的依赖,这些依赖会存在重复加载,可使用commonsChunksPlugin将异步chunk中的公共资源提取为一个独立的异步chunk
5.若是异步chunk的部分样式有丢失,将extractTextPlugin中chunks配置为all,则将全部chunk中的css样式抽离为一个文件,(可是这样作的话,css不会实现异步加载了,感受不太好,若是你们有好的建议欢迎提出)
复制代码
以上就是我要分享的内容,若是存在错误的理解或者更好的理解方法,欢迎提出指正。