计划把微信的文章也搬一份上来。css
这篇主要介绍一下我在玩Webpack过程当中的心得。经过实例介绍WebPack的安装,插件使用及加载策略。感觉构建工具给前端优化工做带来的便利。前端
曾几什么时候,咱们是如上图的方式引入JS资源的,相信如今不多碰见了。近年来Web前端开发领域朝着规范开发的方向演进。体如今如下两点:react
MVC研发构架。多多益处(逻辑清晰,程序注重数据与表现分离,可读性强,利于规避和排查问题...)jquery
构建工具层出不穷。多多益处(提高团队协做,以及工程运维,避免人工处理琐碎而重复的工做)webpack
因此,前端这么好玩,若是还有项目没有先后端分离的话,真的是守旧过头了。git
主流构建工具github
市面上有许多构建工具,包括Grunt、Gulp、browserify等,这些和WebPack都是打包工具。但WebPack同时也具有如下特色:web
相比Grunt,WebPack除了具有丰富的插件外,同时带有一套加载(Loader)系统。使它支持多种规范的加载方式,包括ES六、CommonJS、AMD等方式,这是Grunt、Gulp所不具有的。npm
从代码混淆的角度来看,WebPack更加的极致编程
代码分片为处理单元(而不是文件),使得文件的分片更为灵活。
P.S.此处只作简单的比较,不论孰优孰劣。其实工具都能知足需求,关键是看怎么用,工具的使用背后是对前端性能优化的理解程度。
WebPack安装与使用
WebPack运行在 NodeJS之下,而且它及其插件都是使用NPM(NodeJS的包管理工具)管理。
安装Node及NPM。到NodeJS官网安装包,安装便可
全局安装WebPack。联网状况下,执行命令行 $npm install webpack -g 便可。
此至便可使用WebPack了,到WebPack官网去按着Get start(http://webpack.github.io/docs/tutorials/getting-started/)的步骤来,感觉一个最简单的构建过程。
然而要把WebPack用好,只是跑起来是远远不够的。
WebPack插件
花较大篇幅介绍插件的使用,如下经过在一个DemoApp的构建过程当中思考的一些问题(这些问题基本会在每一个项目中遇到),让这些插件逐一登场。
1、文件过大
DemoApp最初的构建结果以下:
这里生成了一个topic.xxx.js,这个文件原本很小,估计只有10Kb左右,但构建的结果竟然快1Mb了。在3G网络(750Kb/s)下的加载瀑布流以下图:
这张图(体现前端文件加载过程)曝露了几个问题:
上面箭头所指的很蓝色柱子,说明了大部分时间消耗在加载topic.xxxx.js上。
全部JS文件相关的柱子是一根结束了另外一根才开始,说明不合理的文件合并策略,致使文件串行加载。
结果就是如底部的箭头所看到的,页面的加载时间太长了(3G网络,10+秒)。
观察构建的文件,发现原来构建工具把React、jQuery等代码库合并到了topic.xxxx.js,形成此文件过大。若是再加一个activity模块呢?很明显,activity.xxx.js获得相似的结果,都太大了,而且React、jQuery等代码库重复被合并到activity和topic里,以下图。若是再加模块也会获得一样的结果,模块越多重复加载的状况越严重。
可见,提取公共代码,状况能够获得改善,另外,压缩代码无疑是可使文件变小的。
1. 提取React、jQuery等库文件。它们不多变化,而且处处被复用,应该被提取出来,而且获得长时间的缓存。
此处使用插件:WebPack.optimize.CommonsChunkPlugin(WebPack内建插件)
2. 代码压缩。React由700+ Kb压缩成100+ Kb
此处使用插件:WebPack.optimize.UglifyJsPlugin (WebPack内建插件)
处理后topic.xxx.js和activity.xxx.js都很小了,而且多了jquery.xxx.js和react.xxx.js
再看看文件加载的瀑布流,柱子所占比例短了,同时资源并行加载。
到此为止,这个问题算比较好地解决了,但还不够,随着项目愈来愈大,还有一个重要因素会致使文件很大。这部份内容放到本文的最后介绍。
2、如何缓存
缓存控制要作到两件事情,提到缓存命中率
对于没有修改的文件,从缓存中获取文件
对于已经修改的文件,不要从缓存中获取
围绕这两点,演绎出了不少方案,此处列两种:
不处理,等待用户浏览器缓存过时,自动更新。这是最偷懒的,命中率低一些,同时可能会出现部分文件没有更新,致使报错的状况。
Http头对文件设置很大的max-age,例如1年。同时,给每一个文件命名上带上该文件的版本号,例如把文件的hash值作为版本号,topic. ef8bed6c.js。便是让文件很长时间不过时。
当文件没有更新时,使用缓存的文件天然不会出错;
当文件已经有更新时,其hash值必然改变,此时文件名变了,天然不存在此文件的缓存,因而浏览器会去加载最新的文件。
从上面的截图能够看出来,经过WebPack是能够很轻松作到第二点的——只须要给文件名配置上[chunkhash:8]便可,其中8是指hash长度为8,默认是16。
P.S.这样的处理效果已经很好了,但一样有劣处,即浏览器给这种缓存方式的缓存容量太少了,只有12Mb,且不分Host。因此更极致的作法是以文件名为Key,文件内容为value,缓存在localStorage里,命中则从缓存中取,不命中则去服务器取,虽然缓存容量也只有5Mb,可是每一个Host是独享这5Mb的。
3、自动生成页面
文件名带上版本号后,每一次文件变化,都须要Html文件里手动修改引用的文件名,这种重复工做很琐碎且容易出错。
使用 HtmlWebpackPlugin 和 ExtractTextPlugin 插件能够解决此问题。
生成带JS的页面
new ExtractTextPlugin("comm.[contenthash:9].css")
插件介绍到此为止,然而,还有一个关于同步加载和异步加载的问题,不然入口文件仍是会很臃肿。
关于同步加载和异步加载
使用WebPack打包,最爽的事情莫过于能够像服务器编程那样直接require文件,看起来是同步地从服务器上取得文件直接就使用了。以下面的代码同样,没有任何异步逻辑,代码很干净。
然而,这种爽是有代价的,对于直接require模块,WebPack的作法是把依赖的文件都打包在一块儿,形成文件很臃肿。
因此在写代码的时候要注意适度同步加载,同步的代码会被合成而且打包在一块儿;异步加载的代码会被分片成一个个chunk,在须要该模块时再加载,即按需加载,这个度是要开发者本身把握的,同步加载过多代码会形成文件过大影响加载速度,异步过多则文件太碎,形成过多的Http请求,一样影响加载速度。
同步加载的写法,如:
var TopicItem = require('../topic/topicitem');
异步加载的写法,如:
一个原则是:首屏须要的同步加载,首屏事后才须要的则按需加载(异步)
结语
以上是WebPack构建工具比较好的实践,可见,要用好仍是很考验前端性能优化的功力的,比较何时同步,何时异步,若是作缓存等等。
若是以为文章有用,顺手点击下方的推荐