react项目优化之webpack

同步自个人博客css

开门见山,因为咱们项目的前端代码只有一个bundle,全部代码都在一个js文件里,随着功能不断的堆叠,体积已经到没法忍受的地步了(gzip后即将突破300k),致使首屏的时间不停的涨啊涨,最近一周富裕了一点人力赶忙作一次优化,暂时缓住了势头。前端

react+webapck的优化文章如今一搜一大把,此次只说说个人技术方案,以及我是如何分析和优化的。node

技术方案

首先,我先说下,gzipcdn等等前端优化手段咱们都是有的,此次主要是为了解决bundle过大的问题。react

咱们项目的整体架构很简单易懂,react全家桶:react+redux,哈哈。共有三个系统,每一个系统有本身单独的工程。因为是Hybrid应用,为了尽量贴合APP内的切页效果,每一个工程又都是采用的是单页+多页的形式。webpack

因为系统多+单页多页混合,致使咱们的路由比较混乱,原本打算上react-router进行一次大的改版,可是时间不够充裕,综合时间,开发成本角度来看,我定了一个简单并能够快速实施的方案:git

  1. 抽取出三个工程的公共代码打包出一个bundle。好比reactreduxredux-thunk以及一些polyfill,由于这些都是长时间不会变更的代码,因此能够最大程度的命中缓存,而且每次发布不须要从新下载这部分代码,在项目中就用externals的方案去引用这些代码。github

  2. code split,每一个工程按照多页的路由作代码切割,每一个多页路由都有本身的bundleweb

  3. 异步加载,每一个多页路由都会对应各自的辅助页面和组件代码,都使用异步加载的方式。npm

如何优化bundle体积

code split+异步加载

这个很简单,使用webpackrequre.ensure就能够了json

addPage(cb){
    require.ensure([], function () {
            cb({
                Page1: require('../../pages/Page1'),
                Page2: require('../../pages/Page2')            
                })
       });
}

这里Page1Page2的代码都是异步加载的,具体的部分涉及到路由的设计,咱们目前的方案很是的简单和随便,就不细说了。我也看了react-router的解决方案,以为写起来复杂了一些,后续可能会在寻找更好的方案或者本身撸一个。

这里须要注意,虽然咱们的js代码作了拆分,css文件仍是但愿打包成一个,因此须要给ExtractTextPlugin增长allChunks的配置。

new options.ExtractTextPlugin('[name]@[contenthash].css', {allChunks: true})

externals

我将reactredux等等公用的代码打包成一个lib.js,而后暴露在全局变量上。每一个工程里都会先去引用这个lib.js,在webpack的配置里就只须要配置上externals就能够了

其余插件

咱们还用了一些其余插件来尽量的优化体积

  • UglifyJsPlugin 很少说了,代码混淆压缩

  • DedupePlugin 消除重复引用的模块,好像webpack2已内置,使用webpack2的能够忽略

  • OccurrenceOrderPlugin 让依赖次数多的模块靠前分到更小的id来达到输出更多的代码

  • CommonsChunkPlugin这个咱们没有用,可是你们能够去看看,对于多页应用它能够帮助你将一些公共代码打包

如何分析bundle过大的问题

在作代码拆分的时候我曾遇到过一个问题,如何确认个人代码已是最优的了,如何确认我没法继续优化了?这就须要咱们去查看,这个bundle究竟打包了哪些代码,是否这些都是咱们须要的。

首先我推荐一个网址,这里介绍了不少webpack优化的工具。

我本身推荐两个bundle体积的可视化分析工具

  1. webpack-visualizer

  2. webpack-bundle-analyzer

具体如何使用我就不介绍了,它们的文档写的很清楚你们能够去文档上看,他们均可以很清楚的看到每一个bundle分别打包了哪些代码,哪些占据了最大的体积,也能够观察哪些代码实际上是无用的能够优化掉的。

这里我还遇到过一个问题,好比我在detail.chunk.js里发现引入了一个loading组件,可是我映象里详情页并无引入loading组件呀,这时候就须要去寻找loading是被谁依赖了。以前我都是用webstorm的find usages一点点的去看引用关系,其实能够用webpack提供的一个官方工具来作这件事。

首先,你须要这么启动webpack

webpack --profile --json > stats.json

此时会生成一个stats.json文件,以后在官方分析工具里上传文件便可对你的bundle进行分析。

这里我用官方的例子简单说下

  1. 上传你的json文件,长传后会看到这么一个界面,会简单描述你的webpack的版本,有多少modules,多少chunks等等
    1

  2. 点击chunks,能够看到全部chunks的描述,左边是chunks的id,而后有namse,有多少modules,大小,引用它的chunks是谁、即parents,假如咱们须要分析id为1的chunk,只须要点击左边的id
    2

  3. 这里你能够看到更详细的信息,这里最重要的是两个,reasons是引用这个chunks的模块,modules是这个chunks所引用的modules
    3

  4. 这里你发现有一个模块不是你想要的modules,你只须要点击这个模块的id,再去查看reasons就能够看到这个模块是被谁引入的

如何优化本地开发体验和打包速度

webpack吐槽的常态 —— 打包慢,这里说一下咱们这边作过的优化。

缩小文件搜索范围

resolve.modules配置为node_modules,像使用 impot _ from "lodash"这种时webpack遍历向上递归查到node_modules,但一般只有一个node_modules,为了减小能够直接写明node_modules的地址

loader也能够设置须要生效的目录地址
好比babelloader能够只对src目录里的代码进行编译,忽略庞大的node_modules

{
    test:/\.js$/,
    loader:'babel-oader',
    include:path.resolve(__dirname,'src')
}

使用alias

发布到npm的库大多包含两个目录,一个是放cmd模块化的lib目录,一个是全部文件合并成的dist目录,多数入口文件是指向lib的。默认状况下webpack会去读lib目录下的入口文件再去递归加载其余以来的文件,这个过程很是耗时,alias可让webpack直接使用dist目录的总体文件减小递归

使用noParse

有些库是自成一体,不须要依赖别的库的,webpack无需解析他们的依赖,能够配置这些文件脱离Webpack解析。

happyPack

happyPack的文档也写的很好,就不复制粘贴了,你们能够自行去阅读文档,简单地说,它主要是利用多进程+缓存使得build更快,这大幅减小了咱们在编译机上编译的时间。

后评估

先说说优化完后的结果,因为react的体积过大,lib就有60k+,基本已经不能继续优化了,加上咱们的路由设计的很很差,首屏的bundle依然有70k+,总的来讲,首屏从280k下降到140k左右。

可是,根据监控的效果来看,页面js下载的整体时间和白屏时间都只下降了30%左右,这并不符合个人心理预期,想了想除了http请求变多之外并无别的反作用,后续会继续深刻的分析一下为何优化的效果没达到预期。

相关文章
相关标签/搜索