透過 Rendertron 進行動態轉譯

2019 年 1 月 31 日,星期四

許多前端架構需依靠 JavaScript 來顯示內容,這表示 Google 可能要花點時間為您的內容建立索引,或是更新已建立索引的內容。

在今年的 Google I/O 大會中,我們討論出一個變通做法,那就是動態轉譯。您可以透過多種方式執行這項工作,這篇網誌文章會舉例說明如何透過 Rendertron 執行動態轉譯,所謂 Rendertron 就是根據無頭 Chromium 所開發的開放原始碼解決方案。

哪些網站建議採用動態轉譯?

並非所有造訪您網站的搜尋引擎或社交媒體漫遊器都會執行 JavaScript。舉例來說,Googlebot 雖可執行您的 JavaScript,但可能需要花點時間,而且會有一些限制

對於經常變更且需要 JavaScript 來顯示的內容而言,動態轉譯可說是相當實用。採用混合式轉譯 (例如 Angular Universal) 有助於改善您網站的使用者體驗,尤其是畫面首次有效顯示所需的時間。

動態轉譯如何運作?

動態轉譯的運作方式

動態轉譯是指針對特定使用者代理程式,在用戶端轉譯和預先轉譯內容間進行切換。

您需要轉譯器來執行 JavaScript 和產生靜態 HTML。Rendertron 是一款使用無頭 Chromium 進行轉譯的開放原始碼專案。單一頁面應用程式通常會在背景載入資料或延後工作以便轉譯內容。 Rendertron 的機制可判斷網頁何時完成轉譯,而且會等到所有網路要求都已完成,沒有任何未完成的工作時才執行動態轉譯。

這篇文章的內容包括:

  1. 網路應用程式範例說明
  2. 設定小型 express.js 伺服器來提供網頁應用程式
  3. 安裝及設定 Rendertron 做為動態轉譯的中介軟體

網頁應用程式範例

《Kitten Corner》網頁應用程式使用 JavaScript 從 API 載入各種貓咪圖片,並以格狀顯示這些圖片。

格狀顯示的可愛貓咪圖片加上可顯示更多內容的按鈕,這個網路應用程式足以讓所有貓奴心滿意足!

這個網路應用程式的 JavaScript 如下:

const apiUrl = 'https://api.thecatapi.com/v1/images/search?limit=50';
   const tpl = document.querySelector('template').content;
   const container = document.querySelector('ul');
   function init () {
     fetch(apiUrl)
     .then(response => response.json())
     .then(cats => {
       container.innerHTML = '';
       cats
         .map(cat => { const li = document.importNode(tpl, true); li.querySelector('img').src = cat.url; return li;
         }).forEach(li => container.appendChild(li));
     })
   }
   init();
   document.querySelector('button').addEventListener('click', init);

這個網頁應用程式使用的新版 JavaScript (ES6),目前 Googlebot 尚未支援。我們可以透過行動裝置相容性測試來確認 Googlebot 能否看到內容:

行動裝置相容性測試結果顯示該網頁可在行動裝置上瀏覽,但螢幕截圖中卻沒有任何貓咪圖片!也就是說,系統可以顯示標題和按鈕,但卻無法顯示任何貓咪圖片。

這個問題雖能輕鬆排解,不過也正好適合用來練習設定動態轉譯。 動態轉譯可以在不變更網頁應用程式程式碼的情況下,讓 Googlebot 看到貓咪圖片。

設定伺服器

為了提供網頁應用程式,我們使用 node.js 程式庫 express 建構網路伺服器。

伺服器程式碼看起來像這樣 (如需完整專案原始碼,請點擊這裡):

const express = require('express');
const app = express();
const DIST_FOLDER = process.cwd() + '/docs';
const PORT = process.env.PORT || 8080;
// Serve static assets (images, css, etc.)
app.get('*.*', express.static(DIST_FOLDER));
// Point all other URLs to index.html for our single page app
app.get('*', (req, res) => {
  res.sendFile(DIST_FOLDER + '/index.html');
});
// Start Express Server
app.listen(PORT, () => {
  console.log(`Node Express server listening on https://localhost:${PORT} from ${DIST_FOLDER}`);
});

您可以試試這個已上線的範例;如果您使用的是新版瀏覽器,應該會看到很多貓咪圖片。如要從電腦執行專案,您需要透過 node.js 來執行下列指令:

npm install --save express rendertron-middleware
node server.js

然後將瀏覽器指向 https://localhost:8080。 完成後,即可開始設定動態轉譯。

部署 Rendertron 執行個體

Rendertron 執行的伺服器收到網址後,會透過無頭 Chromium 傳回該網址的靜態 HTML。我們會依照 Renderron 專案的建議操作,並使用 Google Cloud Platform

建立新 Google Cloud Platform 專案的表單。

請注意,您可以使用無須付費即可使用的用量級別進行操作,如果您在正式版使用這項設定,則須依 Google Cloud Platform 定價方案支付費用。

  1. Google Cloud 控制台中建立新專案。記下輸入欄位下方的「專案 ID」。
  2. 按照說明文件所述安裝 Google Cloud SDK,然後登入。
  3. 透過以下工具從 GitHub 複製 Rendertron 存放區:
    git clone https://github.com/GoogleChrome/rendertron.git
    cd rendertron
  4. 在電腦上執行以下指令,安裝依附元件並建立 Rendertron:
    npm install && npm run build
  5. 在含有以下內容的 rendertron 目錄中建立名為 config.json 的新檔案,藉此啟用 Rendertron 的快取:
    { "datastoreCache": true }
  6. 從 rendertron 目錄執行以下指令,並以步驟 1 中的專案 ID 取代 YOUR_PROJECT_ID
    gcloud app deploy app.yaml --project YOUR_PROJECT_ID
  7. 選擇您想要的地區,然後確認部署,並等待部署程序完成。
  8. 輸入網址 YOUR_PROJECT_ID.appspot.com。您應該會看到含有輸入欄位和幾個按鈕的 Rendertron 介面。
部署至 Google Cloud Platform 之後的 Rendertron UI

當您看到 Rendertron 網路介面,表示您已成功部署自己的 Rendertron 執行個體。請記下專案網址 (YOUR_PROJECT_ID.appspot.com),後續程序會用到。

將 Rendertron 新增至伺服器

網路伺服器會使用 express.js,而 Rendertron 擁有 express.js 中介軟體。請在 server.js 檔案目錄中執行以下指令:

npm install --save rendertron-middleware

這個指令會從 npm 安裝 rendertron-middleware,如此一來,您便可將 Rendertron 新增至伺服器:

const express = require('express');
const app = express();
const rendertron = require('rendertron-middleware');

設定漫遊器清單

Rendertron 會透過 user-agent HTTP 標頭來判斷要求是來自漫遊器或是使用者的瀏覽器,因為它擁有維護完善的使用者代理程式漫遊器清單可用來比對。由於 Googlebot 可以執行 JavaScript,因此在預設情況下,這份清單不會將 Googlebot 列入。如要讓 Rendertron 也轉譯 Googlebot 的要求,請將 Googlebot 新增至使用者代理程式清單:

const BOTS = rendertron.botUserAgents.concat('googlebot');
const BOT_UA_PATTERN = new RegExp(BOTS.join('|'), 'i');

之後,Rendertron 就會將 user-agent 標頭與這個規則運算式進行比對。

新增中介軟體

如要將漫遊器要求傳送至 Rendertron 執行個體,您需要將中介軟體新增至自己的 express.js 伺服器。中介軟體會檢查提出要求的使用者代理程式,並將來自已知漫遊器的要求轉接至 Rendertron 執行個體。請將以下程式碼新增至 server.js,別忘了以您的 Google Cloud Platform 專案 ID 取代 YOUR_PROJECT_ID

app.use(rendertron.makeMiddleware({
  proxyUrl: 'https://YOUR_PROJECT_ID.appspot.com/render',
  userAgentPattern: BOT_UA_PATTERN
}));

漫遊器向範例網站提出要求後,會收到 Rendertron 傳回的靜態 HTML,因此不需要執行 JavaScript 就能顯示內容。

測試設定

如要測試是否成功設定 Rendertron,請再次執行行動裝置相容性測試。

行動裝置相容性測試結果顯示該網頁可在行動裝置上瀏覽,而且先前消失的貓咪圖片現在全部出現在螢幕截圖中了!

不同於第一次測試的結果,這次可以看到貓咪圖片。您可以在 HTML 分頁中看到 JavaScript 程式碼產生的所有 HTML;採用 Rendertron 後,確實無需透過 JavaScript 就能顯示內容。

結論

您在保持網頁應用程式原封不動的情況下,建立了動態轉譯設定,進行這些變更後,您就能為檢索器提供網頁應用程式的靜態 HTML 版本。