最近花了一些时间在优化Mu站点上。已经很努力很努力的去改进了,背后做了很多工作,但是最后依然没有达到自己想要的结果。有些失望,但是还是记录下自己的执着。

Mu站点是一个SPA应用。针对这类前端应用,谷歌有一个工具lighthouse,可以对其进行评分。一共包含5个方面的评估:性能,访问,最佳实践,SEO和PWA。每个方面包含一系列选项,如果哪些项目评分比较低,它会给出建议,怎么优化这块内容。对Mu的优化,主要是依赖这个工具。优化的最终目标是达到全部选项100分,也就是下图的状态

图片

我优化到极致,最后的结果始终差1分,郁郁不欢。一方面我用的是一个香港的服务器,到内地网络延迟就有40多毫秒。此外,加上SPA本身的限制。所以,只能达到这样了,虽然有点不甘心。

图片

因为站点比较简单,所以才会这么执着追求满分。如果是一个比较复杂的应用的话,应该是无论如何都达不到满分的状态的。至于为什么,可以慢慢往下看,再做判断。

可访问性

可访问性是针对有缺陷人士而言,网站的可访问程度。w3c关于可访问性有一些标准。举个例子,如果一个色弱的人,打开一个花里胡哨的网站。那他肯定会很崩溃;还有,如果一个失明的人,使用读屏APP访问页面内容。如果页面不规范,读屏软件识别很差的话,访问也会很吃力。这些细节的考量,体验了一个开发者的人文关怀。如果网站内容比较复杂的话,这块比较难达到满分。但是,能优化多少就优化多少吧。

因为Mu本身比较简约,在这个方面评分自然很高。有一个不达标的是,标签的背景色和文字颜色的对比度不达标。于是,马上更换了颜色。如果一直有访问这个网站,可能会知道原先的按钮色是青色,现在是灰黑色,就是这个原因。

最佳实践

最佳实践是针对站点整体而言的,有服务器,也有js要求。比较关键的几个点就是,网站一定要是https的,且支持http2协议。另外,就是html标签一定要按照html5的规范来,该有的属性都得有。这个对照着改就好了,属于比较容易优化的地方。

因为站点本身就是https+http2协议,所以这块评分很高。没有怎么花功夫优化。

SEO

SEO指搜索引擎友好度。主要是页面要按照html5规范的标签,有标题,有关键词信息等等,让搜索引擎爬虫能方便的爬站点。

这里有个说明,lighthouse只针对当前页面进行评分,它并不知道整个站点的情况。也就是说,可能这个页面的SEO比较好,但是站点整体的SEO并不好。尤其是对于SPA应用,SEO其实一个比较头疼的问题。解决方法是使用服务器端渲染。

因为站点只有一个内容页,所以对我而言,SEO也不是大问题。这块按照提示进行修改,也很容易提高评分。

PWA

PWA渐进式应用,小程序的祖宗。运用现代web api技术,创建跨平台的应用。web应用有天然的跨平台优势,于是大佬们就想,要是web应用能够有原生的体验的话,岂不是无敌了。于是提出了一套pwa解决方案,赋予web应用一定的离线能力,还有web应用不具备的通知能力等。

具体怎么将一个web应用pwa化,可以简单的包一层壳完事,也可以处理各种复杂的离线的场景。建议感兴趣的话,还是去谷歌查资料,非常详细。

Vue Cli提供了一个插件,让web应用快速支持pwa。但是我没有用上。因为我这个项目是个多页面,包括前台和后台。我只想将前台部分pwa化。这个插件进行打包时,没办法做到区分。所以最后还是自己看文档手动实现了pwa相关逻辑。

尽管pwa的想法是好的,但是实际的推广并不太好。首先是苹果,苹果有一套app生态,自然对pwa这种东西不感冒。如果pwa火了,反而会威胁到它的生态。pwa在国内推广也不顺利,国内安卓系统各种魔改就不说了。目前pwa应用体验最好的是在chrome浏览器上。

性能

性能这部分是本文的重头戏,也是最难优化的地方。性能的优化对用户体验来说是最直观的。对开发者而言,就是怎么尽可能的提高响应速度,渲染速度。

前端性能优化,首先需要了解http协议和整个页面的生命周期。当用户输入页面地址,浏览器向服务器发送一个http请求,服务器响应。如果收到一个html资源,则会进行解析,甄别引用的外部资源。然后再发送请求,获取这些资源。如果引用了一个js资源,则会在加载完后执行。

针对SPA应用,js占主要角色。浏览器加载完html,还需要js渲染完才能看到最终的内容。

具体的优化策略如下。

降低请求资源大小

浏览器和服务器通信有网络时延,如果资源越大,则传输时间越长。所以,尽可能的降低请求资源大小。

解决方案有:使用工具压缩js和css资源;开启gzip压缩请求,效果显著。压缩图片资源,采用webp图片格式,webp不需要再经过gzip压缩。

降低css大小

前面提到了压缩css资源。但是仅仅做到这一步还不够。lighthouse会报一个提示remove unused css ...。意思是移除不用的css样式。

这个其实是比较艰难的。目前的前端页面开发,哪个不用上一两个前端ui框架。即使是像bulma这种很精简的css框架,开发者也不会用到其中所有的css元素。事实上呢,一般一个项目,能用到框架中80%的ui样式就很不错了。我在优化前,只用到了bulma框架5%左右的样式。

一方面,其他几个项目都是100分了,我的目标是全100分。所以最后咬咬牙,对照着bulma中的样式,自己重新写了一遍样式。写的不优雅,但是完成了任务。最后,也确实将css资源从40kb左右,压缩到了5kb的样子。

http2

现在是2020年了,http2应该不算是个新玩意了。做web开发应该都有耳闻http2的优势。连接复用,首部压缩,流并行传输等等。所以,升级到http2也是一个比较常规的优化,效果也是很显著的。直接在nginx中启用http2即可。

http2还有一个重要的能力,就是服务器推送。它可以在浏览器请求html资源时,主动推送可能会用到的css和js资源。这样做,可以减少后续请求连接等开销。但是这样有一个问题,服务器推送,对于每次请求都会执行,这样和客户端缓存冲突,浪费了带宽。理论上只需要首次访问推送。nginx官方有文档,介绍如何启用服务器推送,以及如何处理重复推送的问题。

我尝试了http2服务器推送,结果是并没有很高的回报。于是,没有启用这个特性。

SPA首屏渲染

SPA有一个常见问题,就是首屏渲染。从前面提到的渲染过程来看,如果页面是浏览器渲染,则必须得等到js等资源开始执行后才会渲染用户真正看到的页面。如果js资源太大,网络传输比较长,这个渲染就会延后。给用户的第一印象就是很慢。所以,尽可能的提高首屏渲染速度,也是一个优化点。

一般用户打开首页,并不会立马就访问到登录页面。如果不进行优化,会导致首页加载的js中包含很多其他页面的元素,拖累首页的速度。采用异步组件,可以将不立即使用的组件打包到独立的文件,放到后面按需加载,减少首页包体积。

但是无论怎么优化包的大小,用户还是要等到js等就绪后才能看到页面。于是,一个思路就是将需要浏览器渲染的这部分逻辑放到服务器端来做。刚好js也有服务器开发环境,所以,就实现了服务器端渲染SPA。

但是这个改造成本有点高,并且和后端技术不一致,就没有用上。

FID

我的性能评分是99分。主要是差在了FID这一个选项上面。

图片

什么是FID?首次输入延迟。按照谷歌的意思,页面渲染并不是体验的结束。用户和网站能够进行交互的时间,这点也非常关键。FID就是度量这个指标的。为什么会发生输入延迟呢?因为渲染出页面后,浏览器主线程忙于其他的工作,没办法响应用户的输入事件。

典型的网页加载时间图

图片

可以看到,灰色是网络请求资源,黄色是主线程执行资源。浏览器在黄色块接收到用户输入事件时,就会产生延时,和最后响应的时间差,就是FID

优化的方式只能尽量减少js执行时间。减少请求数,最快的让js执行,然后最快的让js执行完毕。目前看,瓶颈并不在我的代码逻辑里面。可能是SPA天然的劣势吧。使用webpack分析打包的体积,也是Vue全家桶占用的体积最大。看来没办法了。

最后

据说vue 3.0针对2.x版本会有一些优化。到时候生态稳定了,可能会再折腾一波。这评分太难受了。

参考资料