同步自个人博客css
开门见山,因为咱们项目的前端代码只有一个bundle
,全部代码都在一个js文件里,随着功能不断的堆叠,体积已经到没法忍受的地步了(gzip后即将突破300k),致使首屏的时间不停的涨啊涨,最近一周富裕了一点人力赶忙作一次优化,暂时缓住了势头。前端
react+webapck的优化文章如今一搜一大把,此次只说说个人技术方案,以及我是如何分析和优化的。node
首先,我先说下,gzip
,cdn
等等前端优化手段咱们都是有的,此次主要是为了解决bundle
过大的问题。react
咱们项目的整体架构很简单易懂,react
全家桶:react
+redux
,哈哈。共有三个系统,每一个系统有本身单独的工程。因为是Hybrid
应用,为了尽量贴合APP
内的切页效果,每一个工程又都是采用的是单页+多页的形式。webpack
因为系统多+单页多页混合,致使咱们的路由比较混乱,原本打算上react-router
进行一次大的改版,可是时间不够充裕,综合时间,开发成本角度来看,我定了一个简单并能够快速实施的方案:git
抽取出三个工程的公共代码打包出一个bundle
。好比react
,redux
,redux-thunk
以及一些polyfill
,由于这些都是长时间不会变更的代码,因此能够最大程度的命中缓存,而且每次发布不须要从新下载这部分代码,在项目中就用externals
的方案去引用这些代码。github
code split
,每一个工程按照多页的路由作代码切割,每一个多页路由都有本身的bundle
。web
异步加载,每一个多页路由都会对应各自的辅助页面和组件代码,都使用异步加载的方式。npm
这个很简单,使用webpack
的requre.ensure
就能够了json
addPage(cb){ require.ensure([], function () { cb({ Page1: require('../../pages/Page1'), Page2: require('../../pages/Page2') }) }); }
这里Page1
和Page2
的代码都是异步加载的,具体的部分涉及到路由的设计,咱们目前的方案很是的简单和随便,就不细说了。我也看了react-router
的解决方案,以为写起来复杂了一些,后续可能会在寻找更好的方案或者本身撸一个。
这里须要注意,虽然咱们的js
代码作了拆分,css
文件仍是但愿打包成一个,因此须要给ExtractTextPlugin
增长allChunks
的配置。
new options.ExtractTextPlugin('[name]@[contenthash].css', {allChunks: true})
我将react
,redux
等等公用的代码打包成一个lib.js
,而后暴露在全局变量上。每一个工程里都会先去引用这个lib.js
,在webpack
的配置里就只须要配置上externals
就能够了
咱们还用了一些其余插件来尽量的优化体积
UglifyJsPlugin
很少说了,代码混淆压缩
DedupePlugin
消除重复引用的模块,好像webpack2
已内置,使用webpack2
的能够忽略
OccurrenceOrderPlugin
让依赖次数多的模块靠前分到更小的id来达到输出更多的代码
CommonsChunkPlugin
这个咱们没有用,可是你们能够去看看,对于多页应用它能够帮助你将一些公共代码打包
在作代码拆分的时候我曾遇到过一个问题,如何确认个人代码已是最优的了,如何确认我没法继续优化了?这就须要咱们去查看,这个bundle
究竟打包了哪些代码,是否这些都是咱们须要的。
首先我推荐一个网址,这里介绍了不少webpack
优化的工具。
我本身推荐两个bundle
体积的可视化分析工具
具体如何使用我就不介绍了,它们的文档写的很清楚你们能够去文档上看,他们均可以很清楚的看到每一个bundle
分别打包了哪些代码,哪些占据了最大的体积,也能够观察哪些代码实际上是无用的能够优化掉的。
这里我还遇到过一个问题,好比我在detail.chunk.js
里发现引入了一个loading
组件,可是我映象里详情页并无引入loading
组件呀,这时候就须要去寻找loading
是被谁依赖了。以前我都是用webstorm的find usages
一点点的去看引用关系,其实能够用webpack
提供的一个官方工具来作这件事。
首先,你须要这么启动webpack
webpack --profile --json > stats.json
此时会生成一个stats.json
文件,以后在官方分析工具里上传文件便可对你的bundle进行分析。
这里我用官方的例子简单说下
上传你的json
文件,长传后会看到这么一个界面,会简单描述你的webpack
的版本,有多少modules
,多少chunks
等等
点击chunks
,能够看到全部chunks
的描述,左边是chunks
的id,而后有namse
,有多少modules
,大小,引用它的chunks
是谁、即parents
,假如咱们须要分析id
为1的chunk
,只须要点击左边的id
这里你能够看到更详细的信息,这里最重要的是两个,reasons
是引用这个chunks
的模块,modules
是这个chunks
所引用的modules
这里你发现有一个模块不是你想要的modules
,你只须要点击这个模块的id,再去查看reasons
就能够看到这个模块是被谁引入的
webpack吐槽的常态 —— 打包慢,这里说一下咱们这边作过的优化。
将resolve.modules
配置为node_modules
,像使用 impot _ from "lodash"
这种时webpack遍历向上递归查到node_modules
,但一般只有一个node_modules
,为了减小能够直接写明node_modules
的地址
loader
也能够设置须要生效的目录地址
好比babel
的loader
能够只对src目录里的代码进行编译,忽略庞大的node_modules
{ test:/\.js$/, loader:'babel-oader', include:path.resolve(__dirname,'src') }
发布到npm的库大多包含两个目录,一个是放cmd模块化的lib目录,一个是全部文件合并成的dist目录,多数入口文件是指向lib的。默认状况下webpack会去读lib目录下的入口文件再去递归加载其余以来的文件,这个过程很是耗时,alias
可让webpack直接使用dist目录的总体文件减小递归
有些库是自成一体,不须要依赖别的库的,webpack无需解析他们的依赖,能够配置这些文件脱离Webpack解析。
happyPack的文档也写的很好,就不复制粘贴了,你们能够自行去阅读文档,简单地说,它主要是利用多进程+缓存使得build
更快,这大幅减小了咱们在编译机上编译的时间。
先说说优化完后的结果,因为react
的体积过大,lib
就有60k+,基本已经不能继续优化了,加上咱们的路由设计的很很差,首屏的bundle依然有70k+,总的来讲,首屏从280k下降到140k左右。
可是,根据监控的效果来看,页面js下载的整体时间和白屏时间都只下降了30%左右,这并不符合个人心理预期,想了想除了http请求变多之外并无别的反作用,后续会继续深刻的分析一下为何优化的效果没达到预期。