ไทย

สำรวจ Next.js Parallel Static Generation (PSG) สำหรับสร้างเว็บไซต์ประสิทธิภาพสูงและขยายขนาดได้ เรียนรู้การสร้างหลาย Route อย่างมีประสิทธิภาพและเทคนิคการเพิ่มประสิทธิภาพขั้นสูง

Next.js Parallel Static Generation: การสร้างหลาย Route อย่างเชี่ยวชาญเพื่อเว็บไซต์ที่ขยายขนาดได้

ในโลกของการพัฒนาเว็บที่เปลี่ยนแปลงอย่างรวดเร็ว การส่งมอบเว็บไซต์ที่มีประสิทธิภาพสูงและขยายขนาดได้ถือเป็นสิ่งสำคัญยิ่ง Next.js ซึ่งเป็นเฟรมเวิร์ก React ที่ได้รับความนิยม มีฟีเจอร์ที่ทรงพลังเพื่อบรรลุเป้าหมายนี้ และหนึ่งในความสามารถที่โดดเด่นคือ Parallel Static Generation (PSG) บล็อกโพสต์นี้จะเจาะลึกเกี่ยวกับ PSG โดยเน้นที่ความสามารถในการสร้างหลาย Route พร้อมกันอย่างมีประสิทธิภาพ ซึ่งช่วยลดเวลาในการ build และเพิ่มประสิทธิภาพของเว็บไซต์ได้อย่างมาก เราจะสำรวจแนวคิดของการสร้างหลาย Route เปรียบเทียบกับการสร้างหน้าเว็บแบบสถิตแบบดั้งเดิม อภิปรายกลยุทธ์การนำไปใช้งานจริง และสรุปแนวทางปฏิบัติที่ดีที่สุดสำหรับการเพิ่มประสิทธิภาพแอปพลิเคชัน Next.js ของคุณเพื่อการขยายขนาดในระดับโลก

Static Generation (SSG) ใน Next.js คืออะไร?

ก่อนที่จะลงลึกในรายละเอียดของ PSG สิ่งสำคัญคือต้องเข้าใจพื้นฐานของ Static Site Generation (SSG) ใน Next.js เสียก่อน SSG เป็นเทคนิคการ pre-rendering ที่หน้าเว็บจะถูกสร้างขึ้น ณ เวลา build ส่งผลให้ได้ไฟล์ HTML แบบสถิตที่สามารถให้บริการแก่ผู้ใช้ได้โดยตรง แนวทางนี้มีประโยชน์หลักหลายประการ:

Next.js มีฟังก์ชันหลักสองอย่างสำหรับการสร้างหน้าเว็บแบบสถิต: getStaticProps และ getStaticPaths โดย getStaticProps จะดึงข้อมูลและส่งต่อไปเป็น props ไปยัง page component ของคุณในระหว่างกระบวนการ build ส่วน getStaticPaths จะกำหนด routes ที่ควรถูกสร้างเป็นแบบสถิต ตัวอย่างเช่น:

// pages/posts/[id].js

export async function getStaticPaths() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();

  const paths = posts.map((post) => ({
    params: { id: post.id.toString() },
  }));

  return {
    paths,
    fallback: false,
  };
}

export async function getStaticProps({ params }) {
  const res = await fetch(`https://api.example.com/posts/${params.id}`);
  const post = await res.json();

  return {
    props: {
      post,
    },
  };
}

function Post({ post }) {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}

export default Post;

ในตัวอย่างนี้ getStaticPaths จะดึงรายการโพสต์จาก API และสร้าง routes สำหรับแต่ละโพสต์ตาม ID จากนั้น getStaticProps จะดึงข้อมูลโพสต์แต่ละรายการสำหรับแต่ละ route

ความท้าทายของการสร้างหน้าเว็บแบบสถิตแบบดั้งเดิม

แม้ว่า SSG แบบดั้งเดิมจะมีข้อได้เปรียบที่สำคัญ แต่ก็อาจกลายเป็นคอขวดสำหรับเว็บไซต์ขนาดใหญ่ที่มี routes จำนวนมหาศาล กระบวนการ build อาจใช้เวลานานมาก โดยเฉพาะอย่างยิ่งหากมีการดึงข้อมูลเข้ามาเกี่ยวข้อง ซึ่งอาจเป็นปัญหาสำหรับ:

ลักษณะการทำงานแบบตามลำดับของการสร้างหน้าเว็บแบบสถิตแบบดั้งเดิม ซึ่ง routes จะถูกสร้างทีละรายการ เป็นสาเหตุหลักของความล่าช้านี้

ขอแนะนำ Parallel Static Generation (PSG)

Parallel Static Generation (PSG) แก้ไขข้อจำกัดของ SSG แบบดั้งเดิมโดยใช้ประโยชน์จากพลังของการทำงานพร้อมกัน (concurrency) แทนที่จะสร้าง routes ตามลำดับ PSG ช่วยให้ Next.js สามารถสร้างหลาย routes ได้พร้อมกัน ซึ่งช่วยลดเวลาในการ build โดยรวมได้อย่างมาก

แนวคิดหลักเบื้องหลัง PSG คือการกระจายภาระงานในการ build ไปยังหลายๆ process หรือ thread ซึ่งสามารถทำได้ผ่านเทคนิคต่างๆ เช่น:

ด้วยการทำให้กระบวนการ build เป็นแบบขนาน PSG สามารถปรับปรุงเวลาในการ build ได้อย่างมีนัยสำคัญ โดยเฉพาะสำหรับเว็บไซต์ที่มี routes จำนวนมาก ลองนึกภาพสถานการณ์ที่การ build เว็บไซต์ที่มี 1000 routes ใช้เวลา 1 ชั่วโมงด้วย SSG แบบดั้งเดิม ด้วย PSG หากคุณสามารถใช้ 10 processes พร้อมกันได้ เวลาในการ build อาจลดลงเหลือประมาณ 6 นาที (สมมติว่าสามารถขยายขนาดได้แบบเชิงเส้น)

วิธีนำ Parallel Static Generation ไปใช้ใน Next.js

แม้ว่า Next.js จะไม่ได้มีโซลูชันสำเร็จรูปสำหรับ PSG มาให้โดยตรง แต่ก็มีหลายแนวทางที่คุณสามารถนำไปใช้ได้:

1. การใช้ `p-map` สำหรับการดึงข้อมูลพร้อมกัน

หนึ่งในคอขวดที่พบบ่อยในการสร้างหน้าเว็บแบบสถิตคือการดึงข้อมูล การใช้ไลบรารีอย่าง `p-map` ช่วยให้คุณสามารถดึงข้อมูลพร้อมกันได้ ซึ่งช่วยเร่งกระบวนการของ getStaticProps

// pages/products/[id].js
import pMap from 'p-map';

export async function getStaticPaths() {
  const res = await fetch('https://api.example.com/products');
  const products = await res.json();

  const paths = products.map((product) => ({
    params: { id: product.id.toString() },
  }));

  return {
    paths,
    fallback: false,
  };
}

export async function getStaticProps({ params }) {
  // Simulate fetching product data
  const fetchProduct = async (id) => {
    const res = await fetch(`https://api.example.com/products/${id}`);
    return res.json();
  };

  const product = await fetchProduct(params.id);

  return {
    props: {
      product,
    },
  };
}

function Product({ product }) {
  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
    </div>
  );
}

export default Product;

แม้ว่าตัวอย่างนี้จะไม่ได้ทำให้การสร้าง route เป็นแบบขนานโดยตรง แต่ก็ทำให้การดึงข้อมูลภายใน getStaticProps เป็นแบบขนาน ซึ่งสามารถปรับปรุงเวลาในการ build ได้อย่างมากเมื่อการดึงข้อมูลเป็นคอขวดหลัก

2. การเขียนสคริปต์แบบกำหนดเองด้วย Node.js และ Child Processes

เพื่อการควบคุมที่ละเอียดมากขึ้น คุณสามารถสร้างสคริปต์ Node.js แบบกำหนดเองที่ใช้ประโยชน์จาก child processes เพื่อทำให้กระบวนการ build ทั้งหมดเป็นแบบขนาน แนวทางนี้เกี่ยวข้องกับการแบ่งรายการ routes ออกเป็นส่วนๆ (chunks) และมอบหมายแต่ละส่วนให้กับ child process แยกกัน

นี่คือโครงร่างแนวคิดของขั้นตอนที่เกี่ยวข้อง:

  1. สร้างรายการ Routes: ใช้ getStaticPaths หรือกลไกที่คล้ายกันเพื่อสร้างรายการ routes ทั้งหมดที่ต้องสร้างเป็นแบบสถิต
  2. แบ่ง Routes ออกเป็นส่วนๆ: แบ่งรายการ routes ออกเป็นส่วนเล็กๆ ซึ่งแต่ละส่วนมีจำนวน routes ที่สามารถจัดการได้ ขนาดของส่วนที่เหมาะสมจะขึ้นอยู่กับฮาร์ดแวร์และความซับซ้อนของหน้าเว็บของคุณ
  3. สร้าง Child Processes: ใช้โมดูล child_process ของ Node.js เพื่อสร้าง child processes หลายตัว
  4. มอบหมายส่วนต่างๆ ให้กับ Child Processes: มอบหมายแต่ละส่วนของ routes ให้กับ child process
  5. รันคำสั่ง Next.js Build ใน Child Processes: ภายในแต่ละ child process ให้รันคำสั่ง Next.js build (เช่น next build) ด้วยการกำหนดค่าเฉพาะที่จำกัดการ build ให้อยู่ในส่วนของ routes ที่ได้รับมอบหมาย ซึ่งอาจเกี่ยวข้องกับการตั้งค่า environment variables หรือใช้การกำหนดค่า Next.js แบบกำหนดเอง
  6. ติดตาม Child Processes: ติดตาม child processes เพื่อหาข้อผิดพลาดและการเสร็จสิ้น
  7. รวบรวมผลลัพธ์: เมื่อ child processes ทั้งหมดเสร็จสิ้นเรียบร้อยแล้ว ให้รวบรวมผลลัพธ์ (เช่น ไฟล์ HTML ที่สร้างขึ้น) และดำเนินการหลังการประมวลผลที่จำเป็น

แนวทางนี้ต้องใช้การเขียนสคริปต์ที่ซับซ้อนกว่า แต่ให้การควบคุมกระบวนการทำงานแบบขนานได้มากขึ้น

3. การใช้เครื่องมือ Build และ Task Runners

เครื่องมืออย่าง `npm-run-all` หรือ `concurrently` ก็สามารถใช้เพื่อรันคำสั่ง Next.js build หลายคำสั่งพร้อมกันได้เช่นกัน แม้ว่าแนวทางนี้อาจไม่มีประสิทธิภาพเท่ากับสคริปต์แบบกำหนดเองที่จัดการส่วนของ route โดยเฉพาะ

// package.json
{
  "scripts": {
    "build:part1": "next build",
    "build:part2": "next build",
    "build:parallel": "concurrently \"npm run build:part1\" \"npm run build:part2\""
  }
}

นี่เป็นแนวทางที่ง่ายกว่า แต่ต้องมีการจัดการ environment variables หรือกลไกอื่นๆ อย่างรอบคอบเพื่อให้แน่ใจว่าแต่ละ "ส่วน" ของการ build จะสร้างชุดของหน้าที่ถูกต้อง

การเพิ่มประสิทธิภาพ Parallel Static Generation

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

แนวทางปฏิบัติที่ดีที่สุดสำหรับ Parallel Static Generation

เพื่อให้แน่ใจว่าการนำ PSG ไปใช้ประสบความสำเร็จ ให้ปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดเหล่านี้:

ตัวอย่างการใช้งาน Parallel Static Generation ในโลกจริง

แม้ว่าการใช้งานจริงอาจแตกต่างกันไป นี่คือตัวอย่างสมมติบางส่วนที่แสดงให้เห็นถึงประโยชน์ของ PSG ในสถานการณ์ต่างๆ:

แนวทางทางเลือก: Incremental Static Regeneration (ISR)

ในขณะที่ PSG มุ่งเน้นไปที่การเร่งความเร็วในการ build ครั้งแรก Incremental Static Regeneration (ISR) เป็นเทคนิคที่เกี่ยวข้องซึ่งควรค่าแก่การพิจารณา ISR ช่วยให้คุณสามารถสร้างหน้าเว็บแบบสถิตได้ *หลังจาก* การ build ครั้งแรกของคุณเสร็จสิ้น ซึ่งมีประโยชน์อย่างยิ่งสำหรับเนื้อหาที่มีการเปลี่ยนแปลงบ่อยครั้ง เนื่องจากช่วยให้คุณสามารถอัปเดตไซต์ของคุณได้โดยไม่จำเป็นต้อง build ใหม่ทั้งหมด

ด้วย ISR คุณสามารถระบุเวลา revalidation (เป็นวินาที) ในฟังก์ชัน getStaticProps ของคุณ หลังจากเวลาที่กำหนดผ่านไป Next.js จะสร้างหน้าเว็บใหม่ในเบื้องหลังใน request ครั้งถัดไป สิ่งนี้ทำให้มั่นใจได้ว่าผู้ใช้ของคุณจะเห็นเนื้อหาเวอร์ชันล่าสุดเสมอ ในขณะที่ยังคงได้รับประโยชน์จากข้อได้เปรียบด้านประสิทธิภาพของการสร้างหน้าเว็บแบบสถิต

export async function getStaticProps() {
  // ... fetch data

  return {
    props: {
      data,
    },
    revalidate: 60, // Regenerate this page every 60 seconds
  };
}

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

ข้อผิดพลาดทั่วไปที่ควรหลีกเลี่ยง

การนำ PSG ไปใช้อาจเป็นเรื่องท้าทาย และสิ่งสำคัญคือต้องตระหนักถึงข้อผิดพลาดที่อาจเกิดขึ้น:

เครื่องมือและเทคโนโลยีสำหรับ Parallel Static Generation

มีเครื่องมือและเทคโนโลยีหลายอย่างที่สามารถช่วยในการนำ PSG ไปใช้:

อนาคตของ Static Generation

Static generation เป็นสาขาที่พัฒนาอย่างรวดเร็ว และเราคาดว่าจะได้เห็นความก้าวหน้าเพิ่มเติมในอีกไม่กี่ปีข้างหน้า แนวโน้มในอนาคตที่อาจเกิดขึ้น ได้แก่:

บทสรุป

Parallel Static Generation เป็นเทคนิคที่ทรงพลังสำหรับการสร้างเว็บไซต์ที่มีประสิทธิภาพสูงและขยายขนาดได้ด้วย Next.js ด้วยการสร้างหลาย routes พร้อมกัน PSG สามารถลดเวลาในการ build และเพิ่มประสิทธิภาพของเว็บไซต์ได้อย่างมาก โดยเฉพาะสำหรับเว็บไซต์ขนาดใหญ่ที่มี routes จำนวนมหาศาล แม้ว่าการนำ PSG ไปใช้จะต้องมีการวางแผนและการดำเนินการอย่างรอบคอบ แต่ประโยชน์ที่ได้รับก็มีมากมาย

ด้วยความเข้าใจในแนวคิด เทคนิค และแนวทางปฏิบัติที่ดีที่สุดที่สรุปไว้ในบล็อกโพสต์นี้ คุณสามารถใช้ประโยชน์จาก PSG ได้อย่างมีประสิทธิภาพเพื่อเพิ่มประสิทธิภาพแอปพลิเคชัน Next.js ของคุณสำหรับการขยายขนาดในระดับโลก และส่งมอบประสบการณ์ผู้ใช้ที่เหนือกว่า ในขณะที่เว็บยังคงพัฒนาต่อไป การเรียนรู้เทคนิคอย่าง PSG จะมีความสำคัญอย่างยิ่งในการก้าวให้ทันและสร้างเว็บไซต์ที่สามารถตอบสนองความต้องการของผู้ชมทั่วโลกได้ อย่าลืมติดตามประสิทธิภาพการ build ของคุณอย่างต่อเนื่อง ปรับเปลี่ยนกลยุทธ์ตามความจำเป็น และสำรวจเครื่องมือและเทคโนโลยีใหม่ๆ เพื่อเพิ่มประสิทธิภาพกระบวนการสร้างหน้าเว็บแบบสถิตของคุณต่อไป