ทำความเข้าใจหลักการพื้นฐานของ JavaScript SEO

JavaScript เป็นส่วนสำคัญของแพลตฟอร์มบนเว็บ เนื่องจาก JavaScript มีฟีเจอร์มากมายที่เปลี่ยนเว็บให้เป็นแพลตฟอร์มแอปพลิเคชันที่มีประสิทธิภาพ การทำให้เว็บแอปพลิเคชันที่ทำงานด้วย JavaScript ค้นพบได้ผ่าน Google Search จะช่วยให้คุณพบกับผู้ใช้รายใหม่ และดึงดูดผู้ใช้ที่มีอยู่ให้กลับมาอีกครั้งในขณะที่ผู้ใช้ค้นหาเนื้อหาที่มีอยู่บนเว็บแอปของคุณ แม้ว่า Google Search จะเรียกใช้ JavaScript กับ Chromium เวอร์ชันที่อัปเดตอยู่เสมอ แต่ก็มีบางอย่างที่คุณเพิ่มประสิทธิภาพได้

คู่มือนี้อธิบายวิธีที่ Google Search ประมวลผล JavaScript และแนวทางปฏิบัติแนะนำในการปรับปรุงเว็บแอป JavaScript สำหรับใช้กับ Google Search

วิธีที่ Googlebot ประมวลผล JavaScript

Googlebot ประมวลผลเว็บแอป JavaScript ใน 3 ช่วงหลักๆ ได้แก่

  1. การรวบรวมข้อมูล
  2. การแสดงผล
  3. การจัดทำดัชนี

Googlebot รวบรวมข้อมูล แสดงผล และจัดทำดัชนีหน้าเว็บ

Googlebot รับ URL จากคิวการรวบรวมข้อมูล รวบรวมข้อมูล URL แล้วส่งไปยังขั้นตอนการประมวลผล ขั้นตอนการประมวลผลจะแยกลิงก์ที่กลับไปที่คิวการรวบรวมข้อมูลและจัดคิวหน้าเว็บสำหรับการแสดงผล หน้าเว็บเดินทางจากคิวการแสดงผลไปที่ตัวแสดงผล ซึ่งส่ง HTML ที่แสดงผลแล้วกลับไปที่การประมวลผล ซึ่งจะจัดทำดัชนีเนื้อหาและแยกลิงก์เพื่อจัดไว้ในคิวการรวบรวมข้อมูล

เมื่อ Googlebot ดึง URL จากคิวการรวบรวมข้อมูลด้วยการสร้างคำขอ HTTP ก็จะตรวจสอบก่อนว่าคุณอนุญาตให้รวบรวมข้อมูลไหม โดยการอ่านไฟล์ robots.txt หากไฟล์ทำเครื่องหมายว่าไม่อนุญาต URL ใด Googlebot จะข้ามการสร้างคำขอ HTTP ไปยัง URL นั้นและข้าม URL นั้นไป

จากนั้น Googlebot จะแยกวิเคราะห์การตอบกลับของ URL อื่นๆ ในแอตทริบิวต์ href ของลิงก์ HTML และเพิ่ม URL ในคิวการรวบรวมข้อมูล หากไม่ต้องการให้ค้นพบลิงก์ ให้ใช้กลไก nofollow

การรวบรวมข้อมูล URL และการแยกวิเคราะห์การตอบกลับ HTML ทำงานได้ดีกับเว็บไซต์แบบดั้งเดิมหรือหน้าเว็บที่แสดงผลฝั่งเซิร์ฟเวอร์ซึ่ง HTML ในการตอบกลับ HTTP มีเนื้อหาทั้งหมด เว็บไซต์ JavaScript บางเว็บอาจใช้รูปแบบ App Shell ซึ่ง HTML เริ่มต้นไม่มีเนื้อหาจริงและ Googlebot ต้องเรียกใช้ JavaScript ก่อนจึงจะดูเนื้อหาจริงของหน้าเว็บที่ JavaScript สร้างได้

Googlebot จัดคิวหน้าเว็บทั้งหมดสำหรับการแสดงผล เว้นแต่ว่าส่วนหัวหรือเมตาแท็ก robots จะบอกให้ Googlebot ไม่ต้องจัดทำดัชนีหน้าเว็บหนึ่งๆ หน้าเว็บดังกล่าวจะอยู่ในคิว 2-3 วินาทีหรืออาจนานกว่านั้น เมื่อ Googlebot มีทรัพยากรพร้อม Chromium แบบไม่มีส่วนหัวจะแสดงผลหน้าเว็บและเรียกใช้ JavaScript จากนั้นจึงแยกวิเคราะห์ HTML ที่แสดงผลสำหรับลิงก์อีกครั้งและจัดคิว URL ที่พบเพื่อรวบรวมข้อมูล นอกจากนี้ Googlebot ยังใช้ HTML ที่แสดงผลเพื่อจัดทำดัชนีหน้าเว็บด้วย

โปรดทราบว่าคุณยังควรใช้การแสดงผลล่วงหน้าหรือฝั่งเซิร์ฟเวอร์อยู่ เนื่องจากจะทำให้เว็บไซต์เร็วขึ้นสำหรับผู้ใช้และโปรแกรมรวบรวมข้อมูล และบ็อตบางตัวเรียกใช้ JavaScript ไม่ได้

อธิบายหน้าเว็บโดยใช้ชื่อและตัวอย่างข้อมูลที่ไม่ซ้ำกัน

ชื่อที่สื่อความหมายและไม่ซ้ำกันรวมถึงคำอธิบายเมตาที่เป็นประโยชน์ช่วยให้ผู้ใช้ทราบผลการค้นหาที่ตรงกับเป้าหมายที่สุดได้อย่างรวดเร็ว เราอธิบายลักษณะของชื่อและคำอธิบายที่ดีไว้ในหลักเกณฑ์เหล่านี้

คุณใช้ JavaScript เพื่อตั้งค่าหรือเปลี่ยนคำอธิบายเมตาและชื่อได้

เขียนโค้ดที่เข้ากันได้

เบราว์เซอร์มี API และ JavaScript จำนวนมากที่เป็นภาษาที่พัฒนาขึ้นใหม่อยู่ตลอด Googlebot มีข้อจำกัดบางอย่างเกี่ยวกับฟีเจอร์ของ API และ JavaScript ที่รองรับ โปรดทำตามหลักเกณฑ์การแก้ปัญหา JavaScript เพื่อให้โค้ดของคุณใช้ร่วมกับ Googlebot ได้

ใช้รหัสสถานะ HTTP ที่มีความหมาย

Googlebot ใช้รหัสสถานะ HTTP เพื่อให้ทราบว่าเกิดข้อผิดพลาดเมื่อรวบรวมข้อมูลหน้าเว็บหรือไม่

คุณควรใช้รหัสสถานะที่มีความหมายเพื่อบอก Googlebot หากไม่ต้องการให้รวบรวมข้อมูลหน้าเว็บหรือจัดทำดัชนี ตัวอย่างเช่น ใช้รหัส 404 กับหน้าเว็บที่ค้นหาไม่ได้ หรือรหัส 401 กับหน้าเว็บที่อยู่หลังการเข้าสู่ระบบ คุณใช้รหัสสถานะ HTTP เพื่อแจ้ง Googlebot ในกรณีที่หน้าเว็บย้ายไปยัง URL ใหม่ได้ เพื่อให้มีการอัปเดตดัชนีตามนั้น

รายการรหัสสถานะ HTTP และกรณีที่ควรใช้มีดังนี้

สถานะ HTTP กรณีที่ควรใช้
301 / 302 หน้าเว็บนี้ย้ายไปยัง URL ใหม่แล้ว
401 / 403 หน้าเว็บไม่พร้อมใช้งานเนื่องจากมีปัญหาเกี่ยวกับสิทธิ์
404 / 410 หน้าเว็บใช้ไม่ได้แล้ว
5xx เกิดข้อผิดพลาดที่ฝั่งเซิร์ฟเวอร์

หลีกเลี่ยงข้อผิดพลาด Soft 404 ในแอปหน้าเว็บเดียว

ในแอปหน้าเว็บเดียวที่แสดงผลฝั่งไคลเอ็นต์ การกำหนดเส้นทางมักใช้เป็นการกำหนดเส้นทางฝั่งไคลเอ็นต์ ในกรณีนี้ การใช้รหัสสถานะ HTTP ที่มีความหมายอาจไม่เหมาะหรือเป็นไปไม่ได้ เพื่อหลีกเลี่ยงข้อผิดพลาด Soft 404 เมื่อใช้การแสดงผลและการกำหนดเส้นทางฝั่งไคลเอ็นต์ ให้ใช้กลยุทธ์ข้อใดข้อหนึ่งต่อไปนี้

  • ใช้การเปลี่ยนเส้นทาง JavaScript ไปยัง URL ที่เซิร์ฟเวอร์ตอบสนองด้วยรหัสสถานะ HTTP 404 (ตัวอย่างเช่น /not-found)
  • เพิ่ม <meta name="robots" content="noindex"> ลงในหน้าข้อผิดพลาดโดยใช้ JavaScript

โค้ดตัวอย่างสำหรับการเปลี่ยนเส้นทางมีดังนี้

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 แทน Fragment

เมื่อมองหาลิงก์ในหน้าของคุณ Googlebot จะพิจารณาเฉพาะ URL ในแอตทริบิวต์ href ของลิงก์ HTML

สำหรับแอปพลิเคชันหน้าเว็บเดียวที่มีการกำหนดเส้นทางฝั่งไคลเอ็นต์ ให้ใช้ History API เพื่อใช้การกำหนดเส้นทางระหว่างมุมมองต่างๆ ของเว็บแอป และให้หลีกเลี่ยงการใช้ Fragment ในการโหลดเนื้อหาต่างๆ ในหน้าเพื่อให้ 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>

แต่คุณดูแลให้ Googlebot เข้าถึง URL ของลิงก์ได้โดยใช้ History API

<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>

ใช้เมตาแท็ก robots อย่างระมัดระวัง

คุณป้องกันไม่ให้ Googlebot จัดทำดัชนีหน้าเว็บหรือติดตามลิงก์โดยใช้เมตาแท็ก robots ได้ ตัวอย่างเช่น การเพิ่มเมตาแท็กต่อไปนี้ไว้ที่ด้านบนของหน้าจะบล็อก Googlebot ไม่ให้จัดทำดัชนีหน้า

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

คุณใช้ JavaScript เพื่อเพิ่มเมตาแท็ก robots ไปยังหน้าหรือเปลี่ยนเนื้อหาของหน้าได้ โค้ดตัวอย่างต่อไปนี้แสดงวิธีเปลี่ยนเมตาแท็ก robots ด้วย 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 พบ noindex ในเมตาแท็ก robots ก่อนเรียกใช้ JavaScript จะไม่มีการแสดงผลหรือจัดทำดัชนีหน้าเว็บ

ใช้การแคชเป็นระยะเวลานาน

Googlebot จะแคชทุกอย่างเพื่อลดคำขอของเครือข่ายและการใช้ทรัพยากร WRS อาจไม่สนใจส่วนหัวของแคช จึงอาจทำให้ใช้ทรัพยากร JavaScript หรือ CSS ที่ล้าสมัย การทำลายนิ้วมือของเนื้อหาจะหลีกเลี่ยงปัญหานี้โดยสร้างลายนิ้วมือจากส่วนเนื้อหาของชื่อไฟล์ เช่น main.2bb85551.js เนื่องจากลายนิ้วมือขึ้นอยู่กับเนื้อหาของไฟล์ การอัปเดตแต่ละครั้งจึงสร้างชื่อไฟล์ที่แตกต่างกัน ดูข้อมูลเพิ่มเติมได้ที่คำแนะนำจาก web.dev เกี่ยวกับกลยุทธ์การแคชเป็นระยะเวลานาน

ใช้ข้อมูลที่มีโครงสร้าง

เมื่อใช้ข้อมูลที่มีโครงสร้างในหน้า คุณจะใช้ JavaScript เพื่อสร้าง JSON-LD ที่จำเป็นและแทรกลงในหน้านั้นได้ อย่าลืมทดสอบการใช้งานเพื่อหลีกเลี่ยงปัญหา

ทำตามแนวทางปฏิบัติแนะนำสำหรับคอมโพเนนต์เว็บ

Googlebot รองรับคอมโพเนนต์เว็บ เมื่อแสดงผลหน้าเว็บ Googlebot จะรวมเนื้อหา Shadow DOM และ Light DOM เข้าด้วยกัน ซึ่งหมายความว่า Googlebot จะมองเห็นเฉพาะเนื้อหาที่แสดงใน HTML ที่แสดงผล เพื่อให้แน่ใจว่า Googlebot จะยังคงมองเห็นเนื้อหาของคุณหลังจากที่แสดงผลแล้ว ให้ใช้การทดสอบความเหมาะกับอุปกรณ์เคลื่อนที่หรือเครื่องมือตรวจสอบ URL และดู HTML ที่แสดงผล

หากเนื้อหาไม่แสดงใน HTML ที่แสดงผล Googlebot จะจัดทำดัชนีเนื้อหาไม่ได้

ตัวอย่างต่อไปนี้สร้างคอมโพเนนต์เว็บที่แสดงเนื้อหา Light DOM ภายใน Shadow DOM วิธีหนึ่งที่จะทำให้ทั้งเนื้อหา Light DOM และ Shadow DOM แสดงใน HTML ที่แสดงผลคือการใช้เอลิเมนต์สล็อต

<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>
    

แก้ไขรูปภาพและเนื้อหาที่โหลดแบบ Lazy Loading

รูปภาพอาจทำให้ต้องเสียค่าใช้จ่ายค่อนข้างสูงจากการใช้แบนด์วิดท์และการเพิ่มประสิทธิภาพ กลยุทธ์ที่ดีคือใช้การโหลดแบบ Lazy Loading เพื่อโหลดรูปภาพเฉพาะเมื่อผู้ใช้กำลังจะได้เห็น โปรดทำตามหลักเกณฑ์ในการโหลดแบบ Lazy Loading เพื่อให้แน่ใจว่าคุณใช้การโหลดแบบนี้โดยไม่ส่งผลต่อการค้นหา