การแสดงผลแบบไดนามิกด้วย Rendertron

วันพฤหัสบดีที่ 31 มกราคม 2019

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

วิธีแก้ปัญหาเบื้องต้นที่เราพูดคุยกันที่งาน Google I/O ในปีนี้คือการแสดงผลแบบไดนามิก ซึ่งสามารถทำได้หลายวิธี บล็อกโพสต์นี้แสดงตัวอย่างวิธีแสดงผลแบบไดนามิกโดยใช้ Rendertron ซึ่งเป็นโซลูชันโอเพนซอร์สที่ใช้ Chromium แบบ Headless เป็นหลัก

เว็บไซต์แบบใดบ้างที่ควรพิจารณาใช้การแสดงผลแบบไดนามิก

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

การแสดงผลแบบไดนามิกมีประโยชน์สำหรับเนื้อหาที่เปลี่ยนแปลงบ่อยและต้องใช้ JavaScript ในการแสดง การพิจารณาใช้การแสดงผลแบบผสมผสาน (เช่น Angular Universal) อาจช่วยให้ประสบการณ์การใช้งานเว็บไซต์ดีขึ้น (โดยเฉพาะอย่างยิ่ง เวลาที่ใช้ใน First Meaningful Paint)

การแสดงผลแบบไดนามิกทำงานอย่างไร

วิธีการทํางานของการแสดงผลแบบไดนามิก

การแสดงผลแบบไดนามิกหมายถึงการสลับไปมาระหว่างเนื้อหาที่แสดงผลฝั่งไคลเอ็นต์และเนื้อหาที่แสดงผลล่วงหน้าสำหรับ User Agent ที่เจาะจง

คุณจะต้องใช้ตัวแสดงผล (Renderer) เพื่อเรียกใช้ JavaScript และสร้าง HTML แบบคงที่ Rendertron เป็นโปรเจ็กต์โอเพนซอร์สที่ใช้ Chromium แบบ Headless เพื่อแสดงผล แอปต่างๆ ที่มีหน้าเดียวมักจะโหลดข้อมูลในเบื้องหลังหรือเลื่อนเวลาการแสดงผลเนื้อหา 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 เห็นภาพแมวได้โดยไม่ต้องเปลี่ยนโค้ดของเว็บแอป

ตั้งค่าเซิร์ฟเวอร์

ในการให้บริการเว็บแอปพลิเคชัน เราจะใช้ express ซึ่งเป็นไลบรารี node.js ในการสร้างเว็บเซิร์ฟเวอร์

โค้ดของเซิร์ฟเวอร์จะมีลักษณะดังนี้ (ดูซอร์สโค้ดของโปรเจ็กต์ทั้งหมดได้ที่นี่)

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 เริ่มการทำงานของเซิร์ฟเวอร์ที่นำ URL หนึ่งมา แล้วส่ง HTML แบบคงที่ของ URL นั้นกลับไปโดยใช้ Chromium แบบ Headless เราจะทําตามคําแนะนําจากโปรเจ็กต์ Rendertron และใช้ Google Cloud Platform

ฟอร์มสำหรับสร้างโครงการ Google Cloud Platform ใหม่

โปรดทราบว่าคุณสามารถเริ่มต้นใช้งานด้วย Usage Tier ได้โดยไม่มีค่าใช้จ่าย การใช้การตั้งค่านี้ในเวอร์ชันที่ใช้งานจริงอาจมีค่าใช้จ่ายตามราคาที่กำหนดไว้ของ Google Cloud Platform

  1. สร้างโปรเจ็กต์ใหม่ในคอนโซล Google Cloud จด "รหัสโปรเจ็กต์" ด้านล่างช่องป้อนข้อมูลเอาไว้
  2. ติดตั้ง Google Cloud SDK ตามที่อธิบายไว้ในเอกสารประกอบและลงชื่อเข้าสู่ระบบ
  3. โคลนที่เก็บ Rendertron จาก GitHub ดัวยคำสั่งนี้
    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 แทนที่ YOUR_PROJECT_ID ด้วยรหัสโปรเจ็กต์ที่จดไว้จากขั้นตอนที่ 1
    gcloud app deploy app.yaml --project YOUR_PROJECT_ID
  7. เลือกภูมิภาคที่ต้องการและยืนยันการทำให้ใช้งานได้ รอจนกระทั่งเสร็จสิ้น
  8. ป้อน YOUR_PROJECT_ID.appspot.com ของ URL คุณควรจะเห็นอินเทอร์เฟซของ Rendertron ซึ่งมีช่องป้อนข้อมูล 1 ช่อง และปุ่มอีก 2-3 ปุ่ม
UI ของ Rendertron หลังจากทำให้ใช้งานได้ใน Google Cloud Platform

ถ้าเห็นอินเทอร์เฟซบนเว็บของ Rendertron แสดงว่าคุณทำให้อินสแตนซ์ Rendertron ใช้งานได้สำเร็จ จด URL ของโปรเจ็กต์ (YOUR_PROJECT_ID.appspot.com) ไว้เพราะคุณจะต้องใช้ในส่วนถัดไปของกระบวนการ

เพิ่ม Rendertron ไปยังเซิร์ฟเวอร์

เว็บเซิร์ฟเวอร์ใช้ express.js และ Rendertron มีมิดเดิลแวร์ express.js เรียกใช้คําสั่งต่อไปนี้ในไดเรกทอรีของไฟล์ server.js

npm install --save rendertron-middleware

คำสั่งนี้ติดตั้ง rendertron-middleware จาก NPM เราจึงเพิ่มรายการดังกล่าวไปยังเซิร์ฟเวอร์ได้โดยทำดังนี้

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

กำหนดค่ารายการบ็อต

Rendertron ใช้ส่วนหัว HTTP ของ user-agent เพื่อระบุว่าคําขอมาจากบ็อตหรือจากเบราว์เซอร์ของผู้ใช้ ส่วนหัวนี้มีรายการ User Agent ของบ็อตที่มีการดูแลรักษาเป็นอย่างดีเพื่อใช้เปรียบเทียบ โดยค่าเริ่มต้น รายการนี้ไม่รวม Googlebot เนื่องจาก Googlebot เรียกใช้ JavaScript ได้ หากต้องการให้ Rendertron แสดงผลคำขอของ Googlebot ด้วย ให้เพิ่ม Googlebot ลงในรายการ User Agent ดังนี้

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

Rendertron จะเปรียบเทียบส่วนหัวของ user-agent กับนิพจน์ทั่วไปนี้ในภายหลัง

เพิ่มมิดเดิลแวร์

ในการส่งคำขอของบ็อตไปยังอินสแตนซ์ Rendertron เราจำเป็นต้องเพิ่มมิดเดิลแวร์ไปยังเซิร์ฟเวอร์ express.js มิดเดิลแวร์จะตรวจสอบ User Agent ที่ส่งคำขอและส่งต่อคำขอจากบ็อตที่รู้จักไปยังอินสแตนซ์ Rendertron ให้เพิ่มโค้ดต่อไปนี้ลงใน Server.js และอย่าลืมแทนที่ YOUR_PROJECT_ID ด้วยรหัสโครงการ Google Cloud Platform ดังนี้

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

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

การทดสอบการตั้งค่าของเรา

หากต้องการทดสอบว่าการตั้งค่า Rendertron ถูกต้องดีหรือไม่ ให้เรียกใช้การทดสอบความเหมาะกับอุปกรณ์เคลื่อนที่อีกครั้ง

การทดสอบแสดงให้เห็นว่าหน้าดังกล่าวเหมาะกับอุปกรณ์เคลื่อนที่ และแมวทั้งหมดที่หายไปก็แสดงขึ้นบนภาพหน้าจอแล้ว

คราวนี้ภาพแมวจะแสดงขึ้นมา ซึ่งต่างกับการทดสอบครั้งแรก ในแท็บ HTML เราจะเห็น HTML ทั้งหมดที่โค้ด JavaScript สร้างขึ้น และด้วยการตั้งค่า Rendertron จึงไม่ต้องใช้ JavaScript แสดงเนื้อหาอีกต่อไป

บทสรุป

คุณสร้างการตั้งค่าการแสดงผลแบบไดนามิกได้โดยไม่ต้องทำการเปลี่ยนแปลงใดๆ กับเว็บแอป การเปลี่ยนแปลงเหล่านี้จะช่วยให้คุณให้บริการเว็บแอปในเวอร์ชัน HTML แบบคงที่แก่ Crawler ได้