用 AMP 优化桌面站点

467 阅读6分钟
原文链接: www.xcodebuild.com

Google AMP (Accelerated Mobile Pages) 是 Google 的一个开源项目,目的是提高移动页面的访问速度。其核心思想就是通过约束 HTML CSS 和 JS 的使用方式从而提高页面的访问性能。

AMP

AMP 由三个部分组成

  1. AMP HTML
  1. AMP Runtime
  1. AMP Components

AMP HTML

AMP HTML 可以认为是 HTML 的一个子集,相比于 HTML 来说,AMP 的要求更加严格:

  1. <!doctype html>开头
  1. 顶部有一个 <html ⚡> tag (或者 <html amp>).
  1. 必须要有 <head><body> 标签 (在 HTML 中是不必须的)
  1. 必须要一个 <link rel="canonical" href="$SOME_URL"> 标签标识 AMP 页面对应的原页面,如果只有 AMP 版本就指向自己
  1. <meta charset="utf-8"> 标签作为 head 里的第一个标签
  1. 在 head 里包含`
  1. 在 head 里包含<script async src="https://cdn.ampproject.org/v0.js"></script>
  1. 在 head 里包含 AMP 初始化代码

除了页面结构的一些要求外,也有一部分 HTML 标签例如 iframe embed 等标签是不能使用的。除此之外,img video 等必须替换成 amp-img amp-video 来完成懒加载等工作。

样式

在 AMP HTML 中 link 标签是不能够引用 CSS 的,只能通过

<style amp-custom>
</style>

来书写页面样式,同时也不允许使用 !important ,不允许使用 * 作为选择器等。

JS

AMP-HTML 中不允许内联 JS,也不允许引用 JS。是的,处于性能考虑 AMP 实际上杜绝掉了使用自定义 JS 的可能性,不过未来会有一个 amp-script 允许在 worker 中使用 JS,后面会介绍。

一些其他的

具体的限制和规范不在此逐条翻译,可以参照:AMP HTML

AMP Runtime

AMP Runtime 实际上就是上面提到的必须要引用的一段 JS:

<script async src="https://cdn.ampproject.org/v0.js"></script>

这个 JS 会完成一些基础的功能,例如 amp-img 的加载和更多 AMP Components 的管理等。

除此之外,也是由这个 JS 提供的开发时验证功能,你可以在地址栏上加上 #development=1 检验页面的合法性。

AMP Components

AMP 不允许用户使用自定义 JS,然而网站不可能回到刚开始没有交互的年代,我们仍然需要一些基础的功能。AMP Components 就是通过 JS 实现的功能组件,以 amp-lightbox 为例,我们在页面中通过 custom element 的方式使用:

<button on="tap:quote-lb">See Quote</button>
<amp-lightbox id="quote-lb" layout="nodisplay">
    <blockquote>"Don't talk to me about JavaScript fatigue" - Horse JS</blockquote>
    <button on="tap:quote-lb.close">Nice!</button>
</amp-lightbox>

而实际上这些组件是通过各自 async 的脚本执行完成功能的:

<script async custom-element="amp-lightbox" src="https://cdn.ampproject.org/v0/amp-lightbox-0.1.js"></script>

AMP 快在哪

其实看完上面三个组成部分后我们大致就能明白 AMP 快的原因,它通过约束开发者的写法,尽可能避免开发者使用让性能下降的写法(阻塞的 JS,*这样的 CSS 选择器等),同时尽可能减少关键渲染链路上的网络请求(不需要请求一个 JS 或者 CSS 就能渲染出首屏)。

其实除了上面的约束外,Google 给了一个非常大的助力,就是能够在 Google 搜索的移动页面上提前预加载 AMP 页面的内容,在用户点击时直接打开。

Google搜索界面的 AMP 页面

所以这和桌面站点有什么关系

虽然 AMP 是为移动页面而设计的,但其实用在 PC 站点上也并没有问题。现在有很多 hexo 博客用 hexo-generator-amp 生成对应的 AMP 页面给 Google 消费,但其实我们完全可以直接使用 AMP 构建博客站点从而提高性能。

本站点就用这种方案重构了页面,从 Google Analytics 上手动打的 ContentfulPaint 指标看,从 1.6s 下降到了 0.7s

做起来也没有什么复杂的地方,按照 AMP 的规范直接改造 hexo 的模板即可,文章模板的地方可能需要把 <img> 通过正则替换成 <amp-img>

Bluma.css in AMP

Bluma.css 是我的博客主题用到的一个 CSS 框架,其 minimal 版本大概有 200KB 左右,而 AMP 要求整个页面的 CSS 不超过 50KB。所以只能通过一些 unCSS 的方案根据 HTML 把真正生效的 CSS 按需从 CSS 中剥离出来,最后达到了 AMP 的要求。

有同样需求的可以直接用在线的:uncss-online.com

水土不服

细心的朋友可能注意到,本页面虽然用 AMP 的方案重构了页面,但其实并非一个真正的 AMP 页面。这是因为 AMP 仍然有一些水土不服的地方。

完全不让运行 JS

AMP 处于性能的考虑完全禁用了 JS,虽然说 AMP Components 提供了很多组件用来补齐功能,但其在国内的生态就不是很好。例如我博客中用到的 LiveRe 评论、卜算子等就没有对应的组件。

其实目前有一个 <amp-script> 有望能够实现写一些 JS 逻辑,但是这个组件目前仍然不能在生产环境中使用,其实等到该组件能够。

CDN

AMP 的一大优势就是可以把页面缓存在 Google 全球的 CDN 上,同时页面中所有的 AMP Component 都只能引用 cdn.ampproject.org 的资源。这点从本意上是为了提高缓存提高速度,但实际上在国内的访问速度差强人意。

而字体只能从 Google Font 上加载这是直接导致国内无法访问,所以从这角度说,AMP 在国内是水土不服的状态。

使用,不完全遵守

最后我采取的方案就是尽可能按照 AMP 的方案来,但在水土不服的地方不强求一致,毕竟我只是想优化性能并不强求 AMP 带来的 Google 流量。

把页面大致按照 AMP 的要求改造后,我把用到的 AMP script 发到了 Github 上通过 jsdelivr.com 托管:github.com/xcodebuild/…

这样我们在页面中就可以引入

<script async src="https://cdn.jsdelivr.net/gh/xcodebuild/ampcdn@0.0.3/v0.js"></script>

如果你需要补充其他用到的 script 可以联系我,目前我只用到了基础的 v0.jsamp-auto-lightbox.js ,这个 JS 经过了一些简单的修改,从而从这个仓库加载 JS 而不是从 cdn.ampproject.org

而对于 JS 的使用我没有强求完全不执行,而是把所有必要的 JS(例如评论框,朴算子)都移到了 onload 事件中

window.addEventListener('load', function(){
  // append js
})

优化本身其实并不依赖 AMP

其实本站点的优化并没有享受到 AMP 带来的 Google 预缓存的好处,甚至连 <html ⚡️> 的这个⚡️ 都没有加(因为这实际上不是个合法的 AMP 页面),只是单纯的把 AMP Runtime 当做一个检验器和用到了简单的图片 lazyload 等特性。

Google 官方称也在和国内的搜索引擎例如搜狗、360 等进行合作,相信等国内的 CDN 访问优化好,以及 <amp-script> 能够在生产环境使用后,可以让本站点直接支持全站 AMP。

而如果只是需要优化页面的话,其实完全可以不用 AMP 这套方案,遵循其思想减少不必要的请求和 JS,最小化关键渲染链路即可。

Last

Performance is about people