1. 程式人生 > >漸進增強的 Web 體驗(Progressive Web AMP)

漸進增強的 Web 體驗(Progressive Web AMP)

如果你最近幾個月一直關注著 Web 開發社群,可能你對漸進增強的 Web 應用(Progressive Web App 簡稱 PWA)已有所瞭解。它是應用體驗能與原生應用媲美的 Web 應用的統稱:不依賴網路連線易安裝,支援視網膜螢幕,支援無邊距影象,支援登入和個性化,快速且流暢的應用體驗,支援推送通並且有一個好看的介面。

一些 Google 的漸進式 Web 應用示例。

雖然新的 Service Worker API 允許離線快取所有的網站資源以便在後續載入中瞬時載入,就像陌生人的第一印象很關鍵一樣。最新的 DoubleClick 研究 (譯者注:DoubleClick 是谷歌旗下一家公司)表明,如果首次載入超過 3 秒,超過 53% 的使用者將放棄訪問。

老實說,3 秒已是一個相當嚴峻的目標。移動端連線通常有平均 300ms 延遲,而且附帶有頻寬限制和時不時訊號弱等不利情況,你可能只剩下不到 1 秒時間留給應用初始化等事情。

使用者和內容之間的延遲。

當然,有一些方法能緩解首次載入緩慢的問題 — 在伺服器上預先渲染好一個基礎結構,再懶載入各個功能模組等等 — 但是使用此種策略達到的優化程度也有限,而且不得不僱傭一個前端優化專家,或者自己成長為一個專家。

那麼,我們有什麼方法來做一個從根本上和原生應用不同的首次瞬時載入呢?

AMP,為移動頁面加速

網站的最重要的優勢之一是跨平臺 — 無需安裝和即刻載入,使用者通常只需輕擊一下滑鼠即可。

要想輕鬆地從短瀏覽(ephemeral browsing)的機會中收益,所需的就是一個瞬時載入(crazy-fast-loading)的網站。讓網站瞬時載入,你需要做些什麼呢?你所需做的只是一個適當的節制:沒有兆位元組大小圖片,阻塞渲染的廣告,沒有十萬行 JavaScript,就只有這些要求。

AMPs,是加速移動網頁(Accelerated Mobile Pages)的簡稱,它擅長於此,實際上,這是它們存在的原因(raison d’être)。它就像一個駕駛輔助功能,通過實行一套合理的規則,優化你的網頁主體內容,讓它們處於快車道。並通過建立這種嚴格的,靜態的佈局環境,使譬如谷歌搜尋等平臺

僅預渲染首屏,得以進一步接近“瞬時”。

此 AMP 的首屏橫幅圖片(hero image)和標題將被提前渲染,以便訪問者瞬時看到首屏內容。

AMP 還是 PWA?

AMP 可靠快速的體驗,在實現時也伴隨著一些限制。當你需要高度動態的功能時,AMP 是不適用的,譬如推送通知、網路支付和依靠額外 JavaScript 的功能。此外,因為 AMP 頁面通常從 AMP 快取中提供,你的 Service Worker 不能執行,首次訪問享受不到漸進式 Web 應用的最重要的好處。另一方面,在首次訪問的速度上,漸進式 Web 應用永遠不及 AWP,因為平臺能順利且毫不費力地預渲染 AMP 頁面 — 內嵌更簡單(比如在內嵌瀏覽器中)。

一旦使用者點選內部連結,離開 AMP 快取,你就能通過安裝 service worker 來增強網站,讓網站支援離線和更多的功能。

那麼,是 AMP 還是漸進式 Web 應用?瞬時交付還是優化交付,或是最先進的平臺功能和靈活的應用程式碼?有沒有一種結合兩者的好處的方式呢?

完美的使用者旅程(User Journey)

終究,重要的是針對使用者旅程的理想體驗。它大概是這樣的:

  1. 使用者發現了一個指向你的內容的連結,並且點選了它。
  2. 內容快速載入是一種愉快的體驗。
  3. 使用者被通知並進階到有推送通知和支援離線的更流暢的體驗。
  4. 立即重定向到一個類原生的體驗,並且可將網站放在你的主螢幕上。使用者驚呼:“怎麼回事?好神奇!”。

訪問網站的第一步應該讓人感覺快速,其後的瀏覽體驗應該越來越引人入勝。

聽起來是不是好的難以置信?好吧,儘管乍看,它們解決不同的問題且不相關,要是我們結合兩種技術會怎麼樣呢?

PWAMP 結合模式

要獲得瞬時載入,漸進增強的體驗,你所需做的是將 AMPs 和漸進式 Web 應用的豐富功能用下列之一(或多)的方式相結合:

  • AMP 作為 PWA
    當你可以接受 AMP 的限制時。

  • AMP 轉作 PWA
    當你想要在兩者之間平滑過渡時。

  • AMP 在 PWA 中
    當你重用 AMP 為 PWA 的資料來源時。

讓我們每個都過一遍吧。

AMP 作為 PWA

許多網站其實用不到超出 AMP(功能)範圍。Amp by Example 就是一個例子,它既是 AMP 也是一個漸進式 Web 應用。

  • 它有 service worker,因此允許包括離線訪問等在內的其他功能。
  • 它有清單(manifest),在橫幅(banner)上會提醒“新增到主螢幕“。

當用戶從谷歌搜尋訪問 Amp by Example,然後點選網站上鍊接,它們將從 AMP 快取頁面轉到源頁面上。當然,網站仍在使用 AMP 庫,但是現在由於它處於源頁面上,它能使用 service worker 或提示安裝等等。

你可以使用此項技術讓你的 AMP 網站支援離線訪問,一旦他們訪問源頁面就進行擴充套件,因為你可以通過 service worker 的 fetch 事件來修改響應(response),並返回你想要的響應 (response)。

function createCompleteResponse (header, body) {

  return Promise.all([
    header.text(),
    getTemplate(RANDOM STUFF AMP DOESN’T LIKE),
    body.text()
  ]).then(html => {
    return new Response(html[0] + html[1] + html[2], {
      headers: {
        'Content-Type': 'text/html'
      }
    });
  });

}

這一技術也允許你在 AMP 後續訪問中插入指令碼,提供超出 AMP 範圍外的更進階的功能。

AMP 轉作 PWA

當上述不能滿足,並且你想讓內容有一個完全不同的 PWA 體驗時,是時候用一種更高階一點的模式了:

  • 為了接近瞬時載入的體驗,所有內容“葉”頁(指有特定內容,不是概述的頁面)被髮布成 AMP。
  • 這些 AMP 使用 AMP 的特殊元素 <amp-install-serviceworker> 來預備快取,並且當用戶喜歡你的內容時用 PWA 的外殼。
  • 當用戶點選你網站上的另一個連結(比如,在底部的行為召喚(按鈕),使其更像原生)service worker 攔截請求並接管頁面,然後載入 PWA 外殼替代之。

假如你熟悉 service worker 的運作,你可以通過以上三個簡單步驟來實現這種體驗。(如果你不清楚的話,強烈推薦我的同事傑克在優達學城(Udacity)上的課程)。第一步,在你所有的 AMP 上放置 service worker。

<amp-install-serviceworker
      src="https://www.your-domain.com/serviceworker.js"
      layout="nodisplay">
</amp-install-serviceworker>

第二步,在 service worker 安裝過程中,快取 PWA 所需的所有資源。

var CACHE_NAME = 'my-site-cache-v1';
var urlsToCache = [
  '/',
  '/styles/main.css',
  '/script/main.js'
];

self.addEventListener('install', function(event) {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

最後,又回到 service worker,攔截 AMP 的導航請求,用 PWA 替代響應。(下面的程式碼是功能簡化版本,後面還有一個更進階的示例。)

self.addEventListener('fetch', event => {
    if (event.request.mode === 'navigate') {
      event.respondWith(fetch('/pwa'));

      // Immediately start downloading the actual resource.
      fetch(event.request.url);
    }
});

現在,每當使用者點選從 AMP 快取頁面上的連結,service worker 註冊 navigate 請求模式(request mode)並接管,然後用已快取的成熟(full-brown)的 PWA 代替。

你可以通過在網站上安裝一些 service worker 來實現漸進增強。對於不支援 service worker 的瀏覽器,它們僅會轉移到 AMP 快取頁面。

此項技術很有意思之處在於從 AMP 漸進增強到 PWA。然而,這也意味著,暫時不支援 service worker 的瀏覽器將從 AMP 跳到 AMP 並且不會導航到 PWA。

AMP 通過 Shell URL 重寫 來跳轉。通過在 <amp-install-serviceworker> 標籤中新增一個備用 URL 模式(URL pattern),如果檢測到不支援 service worker,就指示 AMP 重寫特定頁面上所有匹配的連結,用另一個傳統的 shell URL 替代(外殼(Shell)是應用的使用者介面所需的最基本的 HTML、CSS 和 JavaScript,也是一個用來確保應用有好多效能的元件。它的首次載入將會非常快,載入後立刻被快取下來。這意味著應用的外殼不需要每次使用時都被下載,而是隻載入需要的資料。 ):

<amp-install-serviceworker
      src="https://www.your-domain.com/serviceworker.js"
      layout="nodisplay"
      data-no-service-worker-fallback-url-match=".*"
      data-no-service-worker-fallback-shell-url="https://www.your-domain.com/pwa">
</amp-install-serviceworker>

在有 service worker 的情況下具有了這些屬性,AMP 上所有後續點選都將轉到 PWA。挺巧妙的,是吧?

AMP 在 PWA 中

那麼,現在使用者處於漸進式 Web 應用中,你可能會使用一些 AJAX 驅動(AJAX-driven)的導航,通過 JSON 來獲取內容。你當然可以這麼做,但是現在有兩個完全不同的內容後端和基礎架構需求 — 一個生成 AMP 頁面,另外一個為你的漸進式 Web 應用提供基於 JSON 格式的介面。

但請想一想 AMP 的本質是什麼。它不只是一個網站,它被設計成一個超輕便的內容單元。AMP 是獨立的且可以順利地嵌入到其他網站。我們是否可以拋棄 JSON 介面,使用 AMP 作為我們漸進式 Web 應用的資料格式,從而大大降低後端複雜性呢?


AMP 頁面能順利地嵌入其他網站中 — PWA 的 AMP 庫只會編譯並載入一次。

當然,一個簡單的方法是在 frames 中載入 AMP 頁面。但是使用 iframes 比較慢,並且需要你一遍又一遍地重新編譯和初始化 AMP 庫。現在前沿的 Web 技術提供了一種更好的方式:Shadow DOM。

處理過程看起來是這樣的:

  1. PWA 操縱所有的導航點選事件。
  2. 然後,用 XMLHttpRequest 獲取請求的 AMP 頁面。
  3. 將內容放入一個新的 shadow root 中。
  4. 然後返回給主 AMP 庫,“嘿,我有一個新文件給你。請查收!”(在執行時呼叫 attachShadowDoc)。

使用此種技術,整個 PWA 只會編譯和載入一次 AMP 庫,並且然後,因為你是通過 XMLHttpRequest 獲取的頁面,你能在 AMP 源插入新的 shadow document 之前進行一些修改,你可以像這樣做:

  • 去掉不必要的內容,比如頁首(header)和頁尾(footer);
  • 插入額外的內容,比如令人反感的廣告或資訊提示;
  • 用更動態的內容替換特定內容。

現在,你使你的漸進式 Web 應用更簡單了,而且大大簡化了後端結構。

準備,配置,實行!

AMP 團隊做了一個名為 The Scenic 的 React 示例 來演示 shadom DOM 方法(也就是:PWA 中的 AMP),它是一本假的旅行雜誌:

看點真東西

一個真實產品的例子是 Mic 新式 PWA(beta 階段),研究一下 :如果你按住 shift 重新重新整理(shift-reload)任意文章(這樣暫時忽略 service worker)檢視原始碼, 你會注意到這是一個 AMP 頁面。現在嘗試點選一下選單:它會重新載入當前頁面, 但由於 <amp-install-serviceworker> 已存在於 PWA 應用外殼中,過載幾乎是瞬間完成的,並且選單在重新整理後開啟,使其看起來不像是重新載入過一樣。但現在你處於擁有其他豐富功能的(內嵌 AMP 頁面)PWA 中。狡猾,但很了不起。

結語

無需多說,我非常激動地憧憬著新結合的潛力。這個結合集兩者之所長。

優點概括:

  • 不論什麼情況,都很快;
  • 良好的內建支援(通過 AMP 的平臺夥伴);
  • 漸進增強;
  • 只需一種後端介面;
  • 降低客戶端複雜性;
  • 成本低;

但是我們才開始發掘這種模式的變型,也是全新的一種。除提供構建 2016 最好的 Web 體驗之外,繼續向前到達 Web 的新篇章。