TOP ⬆

MLA 播放器静态资源的简单优化

这次主要记录一下我是如何对一个静态资源多的项目进行优化的。

背景是当前正在秋招补录,面试过程中要让面试官对你的项目提起兴趣的前提就是这个项目足够快。因此在面试后我找了一段时间对项目进行了整理和优化,主要修改动作如下:

  1. 尽可能压缩图片资源,这里我使用了 webp 格式
  2. 足够小的图片,在不动态加载的时候可以用 base64 编码的方式减少请求数量
  3. 小技巧:css3 的新属性来重复背景图
  4. 跳过步骤 2 可以选择 HTTP2
  5. 老生常谈懒加载

具体过程可以直接看仓库,github 仓库地址:My Little Airport

想法

修改前

之前项目图片是部署在后端的服务器上,后端还作 FTP 服务器的作用,展示流程如下: 初次流程图 (PS:图片上的客户端本质是浏览器上的 JS 主线程,而浏览器代表浏览器中的网络进程)

优点:使用这种方式部署 FTP 服务器可以根据数据库实现实时更新,并重新加载数据,甚至可以在不同的时机在同一页面组件下展示不同图片(强缓存可以使用 hash 去更新)

缺点:很明显我们的项目静态资源是不变的,没有必要使用 FTP 来做动态更新,我们完全可以把固定不变的静态资源放到前端来,这样使用 HTTP2 直接加载岂不美哉?

修改后

修改加载资源的方式如下: 优化资源后

优点:前端存放部分静态资源使用动态加载,也可以使用静态加载,静态加载的时候利用 webpack 可以转换成 base64 进一步减少资源请求,当然也选择使用 HTTP2

缺点:资源和后端数据绑定的情况下,这样做其实是不太合适的,因为多了一步隐形的约定,后期修改也比较麻烦(注意资源务必放在 public 中避免更换资源还要重新部署)

项目使用

当前项目使用的方式集合了上面两种。

首先图片类的资源会放在前端里,因为专辑、歌曲图片这些资源和每首歌都是对应的,不存在需要经常修改的场合;而后端服务器存放歌曲资源,这样新增歌曲的时候可以直接往数据库塞,前端也提供了默认的专辑封面,当然有新专辑的时候还是使用 FTP 服务器来修改比较妥当。

实施方案

  1. 图像大小压缩

    使用 webp 的缘由是因为没有尝试过,毕竟这种格式是谷歌推荐的,还贴心地提供了有损无损压缩算法。具体怎么把图片格式转换成 webp 我就不提啦,github 上有很多方案可以批量进行。这里重点给大家分享一个由谷歌推出的超级好用的图片压缩工具 squoosh ,并用它来批量压缩 webp 文件

    squoosh

    页面配置一看就懂,我就不进行介绍了,注意上面标红和标绿的两个 tips 是很关键的。

    红色按钮会把当前页面配置的压缩方式 copy 成 npx 命令,我们使用 squoosh-cli 就可以在本地进行批量压缩啦!详细的教程地址可见squoosh-cli

    绿色指明的意思就是 resize 配置需要谨慎使用,如果改变大小最好是使用百分比的形式执行批处理,一定要保证压缩过程中长宽比不会被拉伸!

    ⚠️ 注意压缩文件前要做好备份喔~ 可以看到在不改变长宽和页面效果的情况下,60%有损压缩的成果是巨大的!和未使用 webp 格式前的图片资源对比下缩小了 2.5 倍左右(666kB -> 261kB)

    squoosh压缩成果

  2. webpack 配置使用 base64 ,项目中开启了 http2,所以无视了这一条配置,不过这里还是了解一下!

    这里关键要用到的 loader 就是 url-loader ,在安装 loader 后在 webpack 中开启如下配置即可

    {
        test: /\.(png|jpe?g|gif|svg|webp)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10, // 10b
        }
      },

    Vue-cli 4 开启这项配置可以看这个官方文档:从相对路径导入

  3. css3 重复背景图,在本次项目中的背景图是特制的,其特点就是可重复的即是一个图案完全对称的矩形,这样,我们只需要引入一个小图块,在利用 css3 中背景图片相关的新属性就可以生成一副精美的图画,大大节省了资源空间

    html {
    	background-image: url(./background_image.webp);
    	background-repeat: repeat; //	实际上可以我们还可以选择其是按x/y轴来进行重复
    }

    展示效果如下一个 5kB 大小的图块就可以生成一副高质量的背景图:

    backgroud-image

  4. 选择 HTTP2,因为项目原先就部署了 HTTPS 协议,配置 SSL/TLS 的过程就不讲了。

    前端使用 nginx 来部署项目,而 nginx 开启 HTTP2 就只需要一个配置:vim /etc/nginx/nginx-conf -> listen 443 http2 这里添加一个http2关键字即可开启

    后端是用 springboot2 框架的,要开启 http2 需要先修改一下项目的部署服务器,tomcat -> undertow,具体 build.gradle 和 application.yaml 的配置修改从网上找配置资料即可

  5. 懒加载,项目中使用的是 vant 组件的懒加载方式,不过我们可以深入研究一下各种懒加载的方式。(具体过程后续会有补充,先挖坑)

    1. 监听全局滑动事件,利用 offset 来控制
    2. js 原生的 API Intersection Observer 实现懒加载

思考

除了上述中提到的方法,我们还如何在性能优化方便做得更多?

  1. 缓存协议,前端要配置强缓存或者协商缓存,这里需要在 nginx 中配置,由于我们在 public 中存放我们的图片并采用绝对地址的方式来获取,因此最好使用协商缓存来优化。如果使用强缓存的话要使用动态加载的方式来引入,这样可以通过 webpack 来在文件名上加 hash 值,这样强缓存的过期时间就不会影响用户体验了。
  2. gzip 压缩,主要针对 css 和 js 资源,对图片再进行压缩意义已经不大了,使用 gzip 压缩需要 webpack 和 nginx 来配合,比如 nginx 如果检测到.gz 结尾的文件就会自动发送文件,从而减轻负担,项目成果为(521kB->164kB)缩短了整整 3 倍,与节省下来的时间相比花在解压上根本不值一提。具体配置过程看下篇文章
  3. cdn 贫穷使我留下泪水,没有实践过,没办法细讲 QAQ
  4. ssr, 这个项目其实挺适合 ssr 的!毕设做完再优化

总结

lighthouse 跑一下首页的分

lighthouse

从解析结果上看,我们项目中的无障碍阅读,语义化标签,SEO 这些方面存在着巨大的欠缺,因此要进一步加大这方面的优化才行!