瞭解 JavaScript 搜尋引擎最佳化 (SEO) 基礎知識

JavaScript 是構成網路平台的關鍵要素,因為這類指令碼語言提供了多種功能,可將網路轉變成功能強大的應用程式平台。只要讓他人能夠透過 Google 搜尋找到您的 JavaScript 網路應用程式,您就可以在人們搜尋該應用程式提供的內容時發掘新的使用者,並再次吸引現有使用者。雖然 Google 搜尋是透過持續更新的 Chromium 版本執行 JavaScript,您仍可藉由最佳化作業修正部分問題

本指南將說明 Google 搜尋如何處理 JavaScript,以及針對 Google 搜尋改善 JavaScript 網路應用程式的最佳做法。

Googlebot 如何處理 JavaScript

Googlebot 的 JavaScript 網頁應用程式處理作業分成三個主要階段:

  1. 檢索
  2. 轉譯
  3. 建立索引

Googlebot 會檢索及轉譯網頁,並建立網頁索引。

Googlebot 會從檢索佇列中擷取網址並加以檢索,然後將網址傳送至處理階段。處理階段會擷取重新回到檢索佇列的連結,並將網頁排入轉譯佇列。網頁會從轉譯佇列傳送至轉譯器,轉譯器會將經過轉譯的 HTML 傳回處理階段,而處理階段則會建立內容索引並擷取要排入檢索佇列的連結。

在發出 HTTP 要求來擷取檢索佇列中的網址前,Googlebot 會先確認您是否允許檢索,做法是讀取 robots.txt 檔案。如果該檔案將網址標為不允許檢索,Googlebot 就不會對這個網址發出 HTTP 要求,也不會檢索此網址。

接著,Googlebot 會剖析 HTML 連結 href 屬性中其他網址的回應,並將網址新增至檢索佇列。如要防止 Googlebot 找到特定連結,請採用 nofollow 機制

在傳統網站或伺服器端轉譯的網頁上,HTTP 回應中的 HTML 會包含所有內容,因此這類網站或網頁相當適合 Googlebot 檢索網址及剖析 HTML 回應。不過,部分 JavaScript 網站可能會採用應用程式命令介面模型,其中的初始 HTML 並未包含實際內容,這時 Googlebot 就必須執行 JavaScript 才能查看這類指令碼語言產生的確切網頁內容。

除非漫遊器中繼標記或標頭告知不要建立網頁索引,否則 Googlebot 會將所有網頁排入轉譯佇列。網頁可能會在這個佇列中停留數秒,但也可能需要更長的時間。在 Googlebot 資源允許的情況下,無頭 Chromium 會轉譯網頁並執行 JavaScript。Googlebot 會再次剖析連結中經過轉譯的 HTML,然後將藉此找到的網址排入檢索佇列。此外,Googlebot 也會利用經過轉譯的 HTML 來建立網頁索引。

請注意,我們依然建議您採取伺服器端轉譯或預先轉譯的做法,方便使用者和檢索器更快速地瀏覽網站,況且也不是所有漫遊器都能執行 JavaScript。

使用獨特的標題和摘要描述網頁

只要提供獨特的描述性標題和實用的中繼說明,即可協助使用者迅速找出最符合個人需求的搜尋結果。請參閱這篇指南,瞭解良好的標題和說明應具備哪些條件。

您可以透過 JavaScript 設定或變更中繼說明和標題。

編寫相容的程式碼

由於瀏覽器提供的 API 種類繁多,而 JavaScript 又是發展相當快速的語言,因此 Googlebot 對於 API 和 JavaScript 功能的支援會有些限制。為了確保您的程式碼能與 Googlebot 相容,請遵循 JavaScript 問題的疑難排解指南

使用有意義的 HTTP 狀態碼

Googlebot 會透過 HTTP 狀態碼確認網頁檢索過程中是否發生錯誤。

您應該利用有意義的狀態碼告知 Googlebot 是否要檢索網頁或建立網頁索引,例如透過 404 說明找不到網頁,或藉由 401 提醒 Googlebot 必須登入才能存取網頁。此外,您也可以使用 HTTP 狀態碼告知 Googlebot 網頁是否已移至新網址,以便視情況更新索引。

以下清單列出 HTTP 狀態碼和相關使用時機:

HTTP 狀態 使用時機
301/302 網頁已移至新網址。
401/403 因權限問題而無法存取網頁。
404/410 現已無法存取網頁。
5xx 伺服器端發生錯誤。

避免單頁應用程式發生轉址式 404 錯誤

在由用戶端轉譯的單頁應用程式中,轉送通常會以用戶端轉送的形式執行。 在這種情況下,您可能無法使用有意義的 HTTP 狀態碼,或者即使用了也無法運作。 如要避免在使用用戶端轉譯及轉送時發生轉址式 404 錯誤,請採取下列其中一項策略:

  • 使用 JavaScript 重新導向至伺服器傳回 404 狀態碼 (例如 /not-found) 的網址。
  • 使用 JavaScript 將 <meta name="robots" content="noindex"> 新增至發生錯誤的網頁。

以下是重新導向方法的程式碼範例:

fetch(`/api/products/${productId}`)
.then(response => response.json())
.then(product => {
  if(product.exists) {
    showProductDetails(product); // shows the product information on the page
  } else {
    // this product does not exist, so this is an error page.
    window.location.href = '/not-found'; // redirect to 404 page on the server.
  }
})

以下是 noindex 方法的程式碼範例:

fetch(`/api/products/${productId}`)
.then(response => response.json())
.then(product => {
  if(product.exists) {
    showProductDetails(product); // shows the product information on the page
  } else {
    // this product does not exist, so this is an error page.
    // Note: This example assumes there is no other meta robots tag present in the HTML.
    const metaRobots = document.createElement('meta');
    metaRobots.name = 'robots';
    metaRobots.content = 'noindex';
    document.head.appendChild(metaRobots);
  }
})

使用 History API 而非片段

當 Googlebot 在網頁中尋找連結時,只會追蹤 HTML 連結 href 屬性中的網址

對於採行用戶端轉送的單頁應用程式,請使用 History API 在網頁應用程式的不同檢視之間進行轉送。為了確保 Googlebot 能夠找到連結,請避免使用片段功能載入不同的網頁內容。 以下為不當做法示例,因為 Googlebot 將不會檢索這些連結:

<nav>
  <ul>
    <li><a href="#/products">Our products</a></li>
    <li><a href="#/services">Our services</a></li>
  </ul>
</nav>

<h1>Welcome to example.com!</h1>
<div id="placeholder">
  <p>Learn more about <a href="#/products">our products</a> and <a href="#/services">our services</p>
</div>
<script>
window.addEventListener('hashchange', function goToPage() {
  // this function loads different content based on the current URL fragment
  const pageToLoad = window.location.hash.slice(1); // URL fragment
  document.getElementById('placeholder').innerHTML = load(pageToLoad);
});
</script>

您可以改為執行 History API,確保 Googlebot 能夠存取連結網址:

<nav>
  <ul>
    <li><a href="/products">Our products</a></li>
    <li><a href="/services">Our services</a></li>
  </ul>
</nav>

<h1>Welcome to example.com!</h1>
<div id="placeholder">
  <p>Learn more about <a href="/products">our products</a> and <a href="/services">our services</p>
</div>
<script>
function goToPage(event) {
  event.preventDefault(); // stop the browser from navigating to the destination URL.
  const hrefUrl = event.target.getAttribute('href');
  const pageToLoad = hrefUrl.slice(1); // remove the leading slash
  document.getElementById('placeholder').innerHTML = load(pageToLoad);
  window.history.pushState({}, window.title, hrefUrl) // Update URL as well as browser history.
}

// Enable client-side routing for all links on the page
document.querySelectorAll('a').forEach(link => link.addEventListener('click', goToPage));

</script>

謹慎使用中繼漫遊器標記

透過中繼漫遊器標記,您可以禁止 Googlebot 建立網頁索引或追蹤連結。 舉例來說,如果您在網頁頂端新增下列中繼標記,即可禁止 Googlebot 建立網頁索引:

<!-- Googlebot won't index this page or follow links on this page -->
<meta name="robots" content="noindex, nofollow">

您可以使用 JavaScript 在網頁上新增中繼漫遊器標記,或變更標記內容。請參考下列範例程式碼,瞭解如何透過 JavaScript 變更中繼漫遊器標記,進而在 API 呼叫無法傳回內容的情況下,禁止系統為目前的網頁建立索引。

fetch('/api/products/' + productId)
  .then(function (response) { return response.json(); })
  .then(function (apiResponse) {
    if (apiResponse.isError) {
      // get the robots meta tag
      var metaRobots = document.querySelector('meta[name="robots"]');
      // if there was no robots meta tag, add one
      if (!metaRobots) {
        metaRobots = document.createElement('meta');
        metaRobots.setAttribute('name', 'robots');
        document.head.appendChild(metaRobots);
      }
      // tell Googlebot to exclude this page from the index
      metaRobots.setAttribute('content', 'noindex');
      // display an error message to the user
      errorMsg.textContent = 'This product is no longer available';
      return;
    }
    // display product information
    // ...
  });
    

在 Googlebot 執行 JavaScript 之前,如果在漫遊器中繼標記內發現 noindex,就不會轉譯網頁或建立網頁索引。

採用長效快取

為了減少網路要求與資源使用,Googlebot 會主動進行快取。在此情況下,WRS 可能會因為忽略快取標頭而使用過時的 JavaScript 或 CSS 資源。如要避免這個問題,您可以建立內容指紋,使其成為檔案名稱的一部分 (例如 main.2bb85551.js)。 由於指紋會反映檔案內容,因此只要檔案內容有所更新,系統就會產生一個新檔名。如要瞭解詳情,請參閱 web.dev 長效快取策略指南

使用結構化資料

在網頁中使用結構化資料時,可以使用 JavaScript 產生所需的 JSON-LD 並將其插入網頁。請務必測試導入作業,以免發生問題。

遵循網頁元件最佳做法

Googlebot 支援網頁元件。Googlebot 在轉譯網頁時,會壓縮 light DOM 和 shadow DOM 的內容。這表示 Googlebot 只能看到轉譯後的 HTML 可顯示的內容。為確保 Googlebot 在轉譯內容後仍能看到您的內容,請使用行動裝置相容性測試網址檢查工具並查看轉譯後的 HTML。

如果內容無法在轉譯後的 HTML 中顯示,則 Googlebot 將無法對其進行索引。

以下範例會建立一個網路元件,並在元件的 shadow DOM 中顯示它的 light DOM 內容。 如要確保 light DOM 和 shadow DOM 內容都能在轉譯後的 HTML 中顯示,其中一種方法就是使用 Slot 元素。

<script>
  class MyComponent extends HTMLElement {
    constructor() {
      super();
      this.attachShadow({ mode: 'open' });
    }

    connectedCallback() {
      let p = document.createElement('p');
      p.innerHTML = 'Hello World, this is shadow DOM content. Here comes the light DOM: <slot></slot>';
      this.shadowRoot.appendChild(p);
    }
  }

  window.customElements.define('my-component', MyComponent);
</script>

<my-component>
  <p>This is light DOM content. It's projected into the shadow DOM.</p>
  <p>WRS renders this content as well as the shadow DOM content.</p>
</my-component>
            

轉譯完成後,Googlebot 會將這個內容編入索引:

<my-component>
  Hello World, this is shadow DOM content. Here comes the light DOM:
  <p>This is light DOM content. It's projected into the shadow DOM<p>
  <p>WRS renders this content as well as the shadow DOM content.</p>
</my-component>
    

修正圖片和延遲載入的內容

載入圖片可能需要占用大量的頻寬,並拖慢執行效能。建議您採用延遲載入的機制,等到使用者快要看到圖片時再載入檔案。為了確保您能以適合搜尋服務的方式導入延遲載入機制,請遵循延遲載入指南