作者:傅姝丽(沪江前端开发工程师)
本文原创翻译,有不当的地方欢迎指出。转载请指明出处。
如果你在过去几个月一直关注web开发社区,你很可能已经阅读了progressive web apps,下面简称PWAs (中文有译作渐进式web应用).它是一个术语,统称那些拥有离线支持,可安装,“Retina”,满屏显示,个性化支持,流畅的浏览效果,推送通知和强大的UI等可以和原生媲美的web应用。
https://www.smashingmagazine.com/2016/08/a-beginners-guide-to-progressive-web-apps/
这是一些谷歌Progressive Web APPs示范
虽然当你网站一加载,Service Work API就会帮你缓存所有网站资源,但就像你初次见一个人第一眼印象很重要,最新DoubleClick study的数据表明,如果首次加载花费的时间超过3秒,超过53%的用户会离开。
3秒,在现实中是一个非常残酷的目标。移动端连接,平均有300毫秒的延迟,还受制于带宽、弱信号,所以实际上你只有不到1秒的时间去下载你app所需要初始化所需要的资源。
以上显示了用户请求的延时
当然,我们有办法去减少首次加载的时间,比如服务端预渲染基本布局、按需懒加载等等,但是我们能做到的是有限的,还必须专门有个人去做性能优化。所以,既要迅速加载又要有原生的体验,我们该怎样做?
AMP, For Accelerated Mobile Pages
https://codelabs.developers.google.com/codelabs/your-first-pwapp/#4
网站一个巨大的优势在于无摩擦的入口——它不需要安装,用户总是只需点击一下即可立即加载。
为了享受这么轻松、瞬间的浏览体验,你所有要做的是让你的网站跑的飞快,但是如何让你的网站跑到飞快?我们可以适当的减少开销,没有兆级别容量的图片,没有阻塞渲染的广告,不超过10万行的js代码,所有的只是纯内容的展示。
Accelerated Mobile Pages, 简称AMPs, 就非常擅长做这些,事实这也是它们的宗旨。通过它精心设计的规则能保证优先显示页面的主要内容。通过创建要严格的静态布局,它能使平台像google Search通过首屏预加载达到瞬间加载的效果。
https://www.ampproject.org/learn/how-amp-works/
https://www.ampproject.org/learn/how-amp-works/#load-pages-in-an-instant
这个AMP 的hero image 和 headline会预加载, 以保证用户可以立马看到它
AMP 还是 PWA?
为了快速加载你引入了AMP, 但你引入AMP的同时你很多功能会受限。AMP并不适用一些高级的功能 比如通知推送,网页支付或者一切需要引入其它js的功能。以及因为AMP的页面是受AMP Cache控制的,你享受不到PWA的的优势,因为你自己的Service Worker不能运行。另一方面PWA并不能像AMP在第一次加载那么快,并且能安全且容易的嵌入。
所以AMP还是渐进式的app?是一次性加载还是选择性的加载,是最新的平台特性还是轻巧的应用代码?我们是不是有可能结合两者,综合两个的好处?
PWAMP 结合模式
你可以通过以下方式结合AMPs和progressive web apps
AMP AS PWA
当你能接受AMP的局限性
AMP TO PWA
当你希望在两者之间无缝过度
AMP IN PWA
当你希望AMP作为一个资源在你的PWA里面可复用, 现在让我们来单独的谈谈它们。
AMP AS PWA
很多网站在AMPs范围不需要别的功能。例如,Amp by Example既是一个AMP APP,也是PWA APP。
它有一个service worker,因此它允许离线访问等。
它有一个manifest,所以支持“添加到主屏幕”。
当用户在google search页面点击Amp by Example,然后点击该网站上的另一个链接时,他们将脱离AMP Cache去远程拉数据。网站仍然使用AMP库,当然,但是因为它依赖远程,所以它可以使用service worker,然后安装及激活等等。
你可以使用此技术让你的AMP网站支持离线访问,然后在线时及时更新你的网页,因为在线时您可以通过service workor的fetch事件修改响应,返回你想要返回的内容:
AMP TO PWA
如果上面的不能满足你,你需要非凡的PWA体验围绕你的内容,这是你可以考虑为高级的模式
所有的内容子页面(那些指定的内容,不是全局的页面)作为AMP发布,享受立即加载
这些AMP页面用AMP特定的元素在用户阅读你内容的时候为缓存和PWA脚本做准备
当用户点击你网站的另外一个链接(比如唤起类似原生app的操作),这时候service worker截取请求,接管页面控制权加载PWA脚本
你可以实施这三部,如果你熟悉Service Works的是怎样运行的(如果你不熟悉,我强烈推荐你阅读我同事Jake’s Udacity 的课程)。
https://www.udacity.com/course/offline-web-applications--ud899
首先在你所有AMP引入入Service Worker.
第二步, 在Service Worker安装事件中,缓存PWA需要的所有数据
最后, 还是在Service Worker里面, 用返回PWA取代原有的AMP导航请求
(下面的代码只是为了展示原理所以简化了,高级的例子在最后的Demo里)
现在,当用户在你从AMP Cache返回的页面里面点击一个链接,Service Worker会注册这个navigate 请求然后接管, 变成一个完全成型的已经缓存的PWA。
这个技术有意思的在于它是渐进增强的从AMP转变成PWA. 这也意味着,如果你的浏览器不支持Service Worker,它将不会被导航到PWA, 而是AMP跳AMP
AMP通过shell url rewriting实现这种渐进增强。通过在添加一个回调属性, 如果检测到不支持Service Worker,AMP会用shell Url重写所有匹配所有连接,所有的后续的点击不再会导航到PWA.
https://www.ampproject.org/docs/reference/components/amp-install-serviceworker#shell-url-rewrite
AMP IN PWA
在此模式中,用户已经在一个渐进式的app里面了,你正好用AJAX获取获取数据,但是你的真实需求是得到两种后端返回的数据,一种是AMP内容,另一种是你Progressive Web App所需要的JSON格式数据。
当然,一种简单方式是在iframes里面加载 AMP内容。但是iframe比较慢,而且你需要一次又一次重新编译和重新初始化AMP Library。今天cutting-edge 技术提供一个更好的办法: shadow-dom
AMP 可以安全的被嵌入其他网站, mp liabrary在整个PWA只会被编译和加载一次。
整个过程是这样
PWA劫持任何导航点击
然后它发一个XMLHttpRequest 去fetch AMP页面
拉到后它把内容放到一个新的shadow root
然后它通知 main AMP Library, “这里有个新的document,请检查”(运行的时候叫 attachShadowDoc)
用这个技术,AMP Library在PWA只编译和加载一次,它会响应每个你绑定的shadow document。并且因为你是通过XMLHttpRequests去fetch页面,你可以在插入到新的 shadow document之前更改AMP 资源。打个比方你可以用来:
过滤掉不需要的信息,比如headers 和footers
插入额外的内容, 比如广告和工具
用更动态的内容替换某些内容
现在你把你的渐进式Web APP变得稍微复杂点了,你可以减轻后端的复杂度。
准备好了,走你~
为了阐述 shadow dom的这个方法(PWA包含AMP),AMP团队已经制作了React-based demo called The Scenic, ---- 一个虚拟的旅游杂志.
这个Demo在GitHub
https://github.com/ampproject/amp-publisher-sample/tree/master/amp-pwa
来点干货
我们看看Mic’s new PWA(in beta)这个以及上线的例子: 如果你强刷任意一个页面(会暂时忽略Service Worker),然后你看你请求返回的结果,你会发现是AMP页面资源。现在你单价“hamburger menu”: 它会重新加载当前页面,然而因为已经加载在PWA app shell, 这个重新加载几乎是瞬间的,菜单在刷新后打开,看上去好像根本没有刷新过。
最后的想法
我对这种新的结合方式很兴奋,这种结合带来了它们各自的好处, 再强调下:
总是很快
内置大型分布(通过AMP平台套件)渐进式增强
一种后端返回规则
减少客户端的复杂程度
更少的整体投入
但是我们只是探索了不同方式的差异,打造2016年及未来的最好的Web体验还仍需努力,为开辟Web新篇章继续前行。
如果喜欢本文,可以订阅沪江技术学院公众号。