Webpack是答案吗

青青子衿
青青子衿
青青子衿
109
文章
7
评论
2017年7月19日00:20:39 评论

webpack刚出现时gulp如日中天,现在webpack更新到2.x版本,gulp逐渐淡出我们的视线,聊webpack的人越来越多,直到最近发现Vue官方文档里到处都是基于webpack的讲解,仿佛webpack已经成为了打包器的事实标准,作为一个仍然不准备使用webpack的前端,我必须认真打量一下自己的处境了。

背景知识

模块化开发

一切还要从模块化说起,在距今仅仅几年之前的前端页面里,还会在底部发现一个jQuery+一个js文件的链接,随着这几年规范的进步、硬件、网络的发展、人们对体验的重视,各种因素导致前端脚本越写越多,代码越来越复杂,仿佛一夜之间那个玩具般的代码组织方式无法满足前端开发需求了,于是js模块化横空出世,以横扫之势迅速被前端社区接受,依托加载器实现的js模块化开发和加载,大大提升了前端开发体验,seajs便是在那个背景下杀出来的优秀加载器之一。

模块打包

模块化开发固然好,但在加载上有点问题,因为前端性能优化向来很看重减少请求数量,模块化加载无疑是背道而驰,要解决这个问题,大家想到了将模块打包,开发时是分开的,发布前用打包器合到一起,这样页面的js请求数可以降到1,很好,从此打包器开始流行,webpack就是一个打包器,在webpack之前大家用的最多的是gulp,gulp是一个比打包器更底层的任务管理器,可以压缩代码,预编译代码,处理图片,当然也可以完成打包。

webpack的反杀

既然gulp被webpack反杀了,一定是有不如人的地方,以gulp为代表的传统打包最大的问题是解决不了按需打包,就更别说按需加载了,因为传统的打包思路是遍历源文件 => 匹配规则 => 打包/处理,也就是说只要被规则命中了,即便是程序用不到的模块也会被无脑打包,根本原因是按需这个事无法被规则描述,只能被程序逻辑描述。其实在webpack之前不是没有解决方案,百度fis最得意的地方就是解决了这个问题,并且是理论上堪称完美的解决方案,我感觉其最大的缺点是需要后端配合,然而你懂的,后端通常不鸟这种需求,百度fis也就不了了之了。

那webpack是怎么解决按需问题的呢?前面说了,按需只能被程序逻辑描述,webpack的打包思路就是从程序逻辑入手:入口文件 => 分析代码 => 找出依赖 => 打包,这样代码里不出现的模块就不可能被打进包里,甚至还可以实现按需加载,这就是webpack最有价值的地方。

打包过程中还有一个仅次于按需的需求,那就是分包,之所以说webpack或者说所有的打包器都特别适合SPA应用,是因为SPA只有一个入口,基本不需要分包或者分包需求很简单,但在网站类应用上,我们讨论的不是要不要分包,而是怎样最不浪费的分包,将加载总量降到最低。这个通常来说不是大问题,只要配合好文件目录结构的划分,多数分包需求都可以用规则描述,但在这方面webpack更进了一步,可以在业务代码中依托特定的语法标记出需要分包的模块,这就使分包的实现能在一定程度上自动化了,没毛病。

webpack的其他功能我觉得没必要再说了,都不是刚需,有则锦上添花,没有也无所谓。

需求分析

业务场景

不谈场景的选型都是耍流氓。

假设有这样一个网站项目,兼容IE8,基于jQuery开发,脚本模块化,模块分成业务模块、插件模块、类库模块,类库模块以jQuery为主,业务模块即每个页面的业务代码,也是脚本入口,插件模块主要实现各种前端展示效果,为了更好的代码复用,已经将很多插件封装好并沉淀为一个插件库,可以覆盖项目里几乎所有的展示需求,这个库以一个文件夹的形式存在。

那么问题来了,这么多模块,请求数居高不下,怎么办。

无脑回答,打包啊。

打包分析

那我们就来看这个项目该怎么打包,重点放在插件模块上,首先会遇到传统打包的老大难按需问题,因为插件都在一个文件夹里,规则只能全部匹配,结果就是打出来一个大而无当的包。你说手动把不用的插件移除不行么,行。但实际情况是,展示类页面经常更新,可能今天用到插件1,明天就改用插件2,或者增加了一个页面要用插件3,你让开发者自己去统计到底用了哪个没用哪个吗,那是历史的倒退,不行。

别人解决不了webpack可以,这是webpack首当其冲的优势,按需,不是问题。

再往下看,网站上的所有展示效果都通过插件实现,最终整个项目用到的插件总数比较可观,也就是说即便按需了,这个插件包也不会小,而插件虽说相对固化,但毕竟是展示类插件,更新是免不了的,任意一个插件发生了增删改,整个插件包都要重打,客户端重新加载,代价有点大,不划算,并且我们知道,这个需求对于展示型网站来说,绝对是个真需求

整体打包不行,那每个页面对应一个自己的插件包呢,各改各的,互不干扰,嗯,有点道理。

但是,实际情况要复杂的多,这也是展示型网站最烦人的地方,页面间还是有不少共用插件的,头部至少有个导航、下拉菜单、搜索框吧,底部来个选项卡不过分吧,幻灯片插件很多页面都有可以吗,这些公共插件每个页面打一份真的好吗。要是将公用插件单独拎出来呢,好啊,那不就又是人肉维护依赖关系了么,还是不好。

说一千道一万,关键在于打包需求不稳定,这种情况是打包中最难解决的,webpack也没有办法。但百度fis有!fis从一个更高的维度看问题,直接拿到了资源依赖表,千变万化的打包需求瞬间变得可控了,可惜,用户少,生态就小,生态小,就没戏了。

现在的局面,在不考虑fis的情况下,已经不是怎么打包的问题了,而是根本不适合打包

解决方案

模块本地存储

那么问题又变成,无法打包的情况下如何减少模块化应用请求数。

不打包就得用加载器,加载器自身不可避免的要占一个请求,但加载器也为模块请求优化提供了可能,现在至少有两种可行的方案,一是配合服务端的请求合并,二是模块本地存储。服务端请求合并方案这里略去不谈。

本地存储方案在纯前端就可以实现,通过扩展加载器将请求到的模块代码缓存到localStorage,这样用户初次访问会全量请求,但之后的访问将只加载模块加载器、缓存模块目录、和业务模块三个文件,模块目录文件用于记录将要缓存的模块及其版本号,实现缓存更新,实际开发中可以跟加载器合并成一个文件,从而将脚本请求数降到2

下面我们就要算一笔账了,虽然打包方案极难完美实现,但如果我们财大气粗,上CDN加速呢,虽然包经常更新,但有了CDN加载速度也能保证,理论上每个页面的脚本请求数可以降到1,但实际中总要提取第三方类库吧,请求数同样是2,好,那对比双方就是:

普通请求加载器 + 业务代码 VS CDN加持下的公共包 + 页面包

下面讨论的前提是,CDN再快也有极限,一个CDN大包在一个小文件面前,不会有很大优势。下面看看双方的代码体积,加载器用的seajs,页面的业务代码百行左右,这种情况下的2个请求,我认为上CDN的钱可以省。在非首次加载情况下,我认为本地存储方案处于无敌水平。

本地存储方案最大的问题是首次加载,大批的插件请求怎么办。无法根除,但可以缓解。比如在前端开发时多考虑模块懒加载,尽量提升首屏展示速度,这是前端的看家本领。实在不行咱也可以给插件上CDN嘛,反正只有首次加载走流量,就算上了CDN都比其他方案省好多钱。

因此最终选定的方案是,seajs + 本地存储。

webpack不是银弹

以上项目需求均来自真实经历,这些需求我相信在前端圈子里仍然占有很大的比例,总结起来就是,我们有一个丰富又多变的组件库,这时候webpack解决不了问题。

在兼容性方面,webpack一直是面向最新的标准,自身的很多特性需要依赖polyfill才能向下兼容,甚至有的特性最新的浏览器都还没有原生兼容,用起来难免有点折腾。

技术圈都是追新的,仿佛现在的前端都不好意思再聊jQuery技术栈了,即便说起来也都是jQuery已经过时了的论调,我只想说,浏览器市占率摆在那,展示类项目的需求摆在那,这些应用场景还确确实实的存在着,现实世界的任何一个2C产品可能都有一个高到让你不屑的兼容性要求。

最后webpack的侵入性较强,这是我个人最介意的一点,某些高级特性需要依赖独特的语法才能实现,也就是说需要在一定程度上面向webpack编程,一旦离开了webpack,你的源码无法运行。

后记

唯一不变的是变化。

模块加载在未来大概率会被浏览器原生支持,到那时会不会有新的优化方案?

打包这件事,怎么看都像一个补丁,未来的HTTP2会不会彻底使其成为伪需求?

IE8迟早淘汰,Vue/React的市场会无限增大吗,SEO怎么做,Nodejs服务端渲染是答案吗?

这真是个动荡的年代啊。

没错,文中提到的项目就是Flow-UI,感谢关注。

weinxin
我的微信
爱生活、爱学习的小伙伴可以通过扫一扫二维码添加我的个人微信一起交流!
未分类
青青子衿
  • 本文由 发表于 2017年7月19日00:20:39
  • 转载请务必保留本文链接:http://ishangsf.com/archives/619
国内离线安装 Chrome 扩展程序的方法总结

国内离线安装 Chrome 扩展程序的方法总结

前言 Chrome 作为最流行的网页浏览器之一,少不了其丰富强大的扩展们的加成,但国内无法访问 Chrome 扩展应用商店有点不方便。 好在 Chrome 支持离线安装扩展程序,我们只需要下载好离线安...
Verdaccio 搭建内网 npm 服务器

Verdaccio 搭建内网 npm 服务器

工作在一台不能连外网的电脑上,为了能够使用 npm install, 因此使用 verdaccio 搭建内网的npm 服务器 Verdaccio 官网: https://verdaccio.org/d...
gitbook常用的插件

gitbook常用的插件

1. 说明 本文主要讲解gitbook插件的使用。gitbook使用教程请参考我另一篇文章:https://segmentfault.com/a/11... Gitbook默认自带有5个插件: hig...
如何从官网下载 Google Chrome 离线安装包

如何从官网下载 Google Chrome 离线安装包

Google Chrome 已经是许多人的默认浏览器,但由于“你懂的”原因,在线安装基本没有成功过,他自己的自动更新也多数一直在加载中,所以我们会到一些下载站下载安装包,但我的多次经历告诉我,下载回来...
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: