ข้ามไปยังเนื้อหา

Deployment & Ecosystem

astro build สร้าง output ที่ deploy ได้ใน dist/ สิ่งที่อยู่ในนั้นขึ้นกับ rendering mode:

  • Static — dist/ เป็นโฟลเดอร์ของไฟล์ .html, CSS และ island JavaScript เป็นแค่ไฟล์
  • On-demand / hybrid — dist/ มี server entry ในรูปแบบที่ adapter ของคุณ target ด้วย (Cloudflare Worker, Node server, serverless function) พร้อม static asset

ต่อ type-checking เข้ากับ build เพื่อให้ type error หยุด deploy ที่ไม่ดี: astro check && astro build

การตัดสินใจ deploy ที่ใหญ่ที่สุดคือ static vs on-demand — ตัวเลือกนี้กำหนดว่าคุณ host ที่ไหน ได้:

Static On-demand (SSR)
Output ไฟล์ HTML server entry + assets
ต้องการ static host / CDN อะไรก็ได้ runtime (ผ่าน adapter)
Host Cloudflare Pages, Netlify, GitHub Pages, S3, CDN อะไรก็ได้ Cloudflare Workers, Node server, Vercel, Netlify Functions
เหมาะกับ content ที่เหมือนกันสำหรับทุกคน ข้อมูลต่อ request: auth, form, live data
Adapter ไม่ต้อง ต้อง

เว็บ static ล้วน deploy ที่ไหนก็ได้ที่ serve ไฟล์ พอมี route ไหนเป็น on-demand (หรือใช้ server island หรือ Actions) คุณต้องตั้ง adapter ที่ตรงกัน — deploy โดยไม่มี adapter ก็เจอ error คลาสสิก “an adapter is required”

flowchart TB
  build["astro build"] --> static["Static: HTML files"]
  build --> ssr["On-demand: server entry + assets"]
  static --> cdn["any CDN / static host"]
  ssr --> runtime["adapter runtime: Workers, Node, serverless"]
build ไปได้ที่ไหนบ้าง

version ล่าสุดของ adapter ทางการทุกตัว verify ด้วย npm view <pkg> version กับ npm registry จริง (ไม่ใช่จำจาก changelog):

Adapter Package Version ล่าสุด
Node @astrojs/node 11.1.6
Cloudflare @astrojs/cloudflare 14.3.3
Vercel @astrojs/vercel 11.0.11
Netlify @astrojs/netlify 8.2.6

Cloudflare น่าสนใจเป็นพิเศษเพราะครอบคลุมเป้าหมาย deploy ทั้งสองแบบที่บทนี้พูดถึง จาก package เดียว: เว็บ Astro ที่ static ล้วนสามารถ deploy ไป Cloudflare Pages/Workers เป็น static asset โดยไม่ต้องมี adapter เลย (แค่ไฟล์ serve จาก CDN ของ Cloudflare); พอมี route ไหนต้องการ on-demand rendering adapter: cloudflare() เปลี่ยนโปรเจกต์ เดียวกันนั้นเอง ให้กลายเป็น Cloudflare Worker ที่รัน server code ต่อ request — adapter คือสิ่งที่เพิ่ม “assets” binding กับ worker entry (dist/_worker.js/index.js) เข้าไปใน Cloudflare deploy config ไม่ใช่สิ่งที่ static-only deploy ต้องการ

astro preview เปิด local server ให้ build output ของคุณ — แต่มันจะรัน route แบบ on-demand ได้จริงหรือเปล่าขึ้นกับว่า adapter ที่คุณใช้ ship preview server ของตัวเองหรือเปล่า อ้างตรง ๆ จาก reference ของ Astro เอง: “If an adapter is set in the configuration, the preview server is provided by the adapter. Adapters are not required to provide a preview server, so this feature may not be available depending on your adapter of choice.” verify ตรง ๆ จาก exports map ของแต่ละ adapter ที่ publish จริง:

Adapter Ship preview entrypoint ไหม?
@astrojs/node มี (./preview.js)
@astrojs/cloudflare มี (./entrypoints/preview)
@astrojs/vercel ไม่มี
@astrojs/netlify ไม่มี

บน Vercel หรือ Netlify astro preview ยังรันได้ แต่ serve ได้แค่ส่วน static ของ build — ไม่มี preview local ของ route on-demand สำหรับสองตัวนี้ โดยการออกแบบ ต้อง preview ด้วย local dev tool ของ platform เอง (vercel dev, netlify dev) แทน astro preview ยังบอกตรง ๆ ด้วยว่า “is not designed to be run in production” ไม่ว่า adapter ไหน

สอง config value ที่มักทำคนสะดุดตอน deploy:

  • site ต้องเป็น URL ที่ deploy จริง (เช่น https://example.com) sitemap, canonical tag และ RSS สร้าง absolute URL จากค่านี้ — site ผิด link ก็ผิด
  • base ต้องตรงกับ subpath ที่คุณถูก serve deploy ไป example.com/docs/ ก็ตั้ง base: '/docs' แล้วอ้าง internal link ด้วย base prefix serve ที่ domain root ก็ละไว้ base ที่ไม่ตรงเป็นสาเหตุปกติของ “CSS และ link ของเว็บที่ deploy 404 หมด” — asset ถูกหาที่ path ผิด

Astro เป็น content-first และ ecosystem ของตัวเองสะท้อนสิ่งนั้น:

  • Starlight — documentation-site framework ทางการที่สร้างบน Astro (คอร์สนี้ก็สร้างด้วย Starlight): sidebar, search, i18n และ dark mode มาในตัว
  • Integrations directory — catalog ขนาดใหญ่ของ integration ทางการและ community: UI framework, CMS connector, image service, analytics และ adapter สำหรับ host หลักทุกตัว
  • content-focused patterns — เมื่อรวมกับ content collection Astro เป็นตัวเลือกที่เหมาะสำหรับ blog, docs, marketing site และ headless-CMS front-end ที่คุณได้เว็บ static (หรือ on-demand) ที่เร็วพร้อม content ที่มี type

มี package สองตัวที่ควรระวังเป็นพิเศษ ทั้งคู่ verify ตรง ๆ จาก npm metadata จริง ไม่ใช่ความจำจาก blog post:

  • @astrojs/db — npm view @astrojs/db deprecated คืนค่า: “This package is deprecated. Use a database client (Drizzle, Kysely, etc.) directly instead.” ใช้ node:sqlite, Drizzle หรือ database แบบ hosted (Turso, Neon, PlanetScale) แทน
  • astro-integration-kit — ก็ npm deprecate เหมือนกัน (npm view astro-integration-kit deprecated ชี้ไปที่ migration guide ของตัวเอง) ถ้า snippet ที่ AI generate มาใช้มันเพื่อสร้าง integration เอง เช็คก่อนว่า helper ที่มันใช้ย้ายเข้า Astro core แล้วหรือยัง ก่อนจะเพิ่ม dependency ใหม่

หยิบ framework อย่าง Starlight เมื่อตรงกับ use case ของคุณ แทนที่จะสร้าง docs infrastructure ใหม่ด้วยมือ — สัญชาตญาณ “compose อย่าสร้างใหม่” เดียวกันที่ไหลผ่าน Astro

โปรเจกต์ส่วนใหญ่อัปเกรดได้ในบ่ายเดียว checklist มีดังนี้:

  1. Node 22.12+ เป็นขั้นต่ำ (เท่ากับ Astro 6) รัน npx @astrojs/upgrade เพื่อ bump astro และ integration @astrojs/* ทุกตัวพร้อมกัน
  2. ถอด experimental flag ที่ stable แล้ว: experimental.cache, experimental.routeRules, experimental.logger ย้ายไปเป็น cache, routeRules, logger ระดับบนสุด ส่วน experimental.rustCompiler, queuedRendering, advancedRouting ลบทิ้ง (เป็น default แล้ว)
  3. แก้สิ่งที่ Rust compiler ปฏิเสธ: tag ที่ไม่ปิดและการซ้อนที่ผิดเป็น build error แล้ว error message ชี้ไฟล์และบรรทัดให้
  4. เช็ก whitespace: compressHTML default เป็น 'jsx' ใส่ {" "} ตรงที่ inline element ต้องมีช่องว่าง หรือตั้ง compressHTML: true ชั่วคราว
  5. Markdown plugin: ถ้าใช้ remark/rehype plugin ให้ติดตั้ง @astrojs/markdown-remark และตั้ง markdown: { processor: unified() } ถ้าไม่ใช้ก็รับความเร็วของ Sätteri ไปเลย
  6. Vite 8: ทบทวน migration note ของ Vite 8 สำหรับ plugin เฉพาะของ Vite ที่ตั้งไว้ใต้ key vite
  7. เปลี่ยนชื่อ src/fetch.ts ถ้าคุณมีไฟล์ชื่อนี้ที่ไม่เกี่ยวกัน (หรือตั้ง fetchFile)
  8. API ที่ถูกถอด: @astrojs/db (เปลี่ยนไป node:sqlite, Drizzle หรือ DB แบบ hosted), ค่าคงที่ event ของ astro:transitions (ใช้ชื่อ event แบบ string เช่น 'astro:before-preparation') และ getContainerRenderer ตอนนี้ import จาก subpath ที่เจาะจงกับ framework (@astrojs/preact/container-renderer ถ้าใช้ Preact — subpath ตรงกับ package @astrojs/<framework> ที่โปรเจกต์ติดตั้งจริง verify แล้วในบท testing)

จากนั้น astro check && astro build — build เร็วขึ้นอย่างเห็นได้ชัด ซึ่งคือรางวัล

คำตอบ “นี่คือวิธี deploy Astro” ที่ AI generate มา ควรเช็คกับสิ่งที่เป็นจริงจริง ๆ บน 7.3.5:

  • มันบอกว่า adapter เป็น optional สำหรับ server island หรือ Actions บนเว็บที่ static ล้วนหรือเปล่า? พิสูจน์แล้วข้างบน (และในบท rendering-modes): feature พวกนั้นต้องมี on-demand rendering ถึงจะรันได้เลย ซึ่งต้องมี adapter แม้ว่าทุก page route จะ prerender ก็ตาม
  • มันแนะนำ @astrojs/db หรือ astro-integration-kit โดยไม่มีคำเตือนหรือเปล่า? ทั้งคู่ npm deprecate แล้ว — พิสูจน์แล้วข้างบนด้วยประกาศ deprecation จริง ไม่ใช่การเดาว่าไม่ค่อยมีคนใช้
  • มันอ้างว่า astro preview เป็น production server แบบเบา ๆ ที่ใช้ได้จริงหรือเปล่า? พิสูจน์แล้วข้างบนด้วยคำพูดของ CLI เอง: “not designed to be run in production”
  • มันสมมติว่า astro preview ทดสอบ route on-demand ได้เหมือนกันหมดไม่ว่า adapter ไหนหรือเปล่า? พิสูจน์แล้วข้างบน: มีแค่ Node กับ Cloudflare ที่ ship preview entrypoint; Vercel กับ Netlify ไม่มี ดังนั้น astro preview serve ได้แค่ static output บนสองตัวนั้น
  • มันแนะนำว่า Cloudflare ต้อง มี adapter: cloudflare() เสมอถึงจะ deploy ได้หรือเปล่า? เว็บ static ล้วน deploy ไป Cloudflare Pages/Workers เป็น static asset ได้โดยไม่ต้องมี adapter เลย — adapter มีไว้เฉพาะ on-demand rendering พิสูจน์แล้วข้างบน

🐛 หา bug ในโค้ดนี้

astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';
export default defineConfig({
adapter: vercel(),
});
เฉลย

ตรงนี้ไม่มี config error เลย — แต่ทีมที่พึ่งพา astro preview ในการ verify route on-demand ด้วยมือก่อน deploy ไป Vercel กำลังเชื่อ step ที่ พิสูจน์แล้วข้างบน ไม่ได้รัน route นั้นจริง ๆ: exports ของ package @astrojs/vercel ไม่มี preview entrypoint เลย ดังนั้น astro preview บน config นี้ serve ได้แค่ส่วน static ของ build เท่านั้น วิธีแก้ไม่ใช่การแก้โค้ดในไฟล์นี้ — แต่เป็นเรื่อง process: ใช้ vercel dev (หรือ deploy ไป Vercel preview environment จริง) เพื่อทดสอบ route on-demand จริง ๆ ก่อน ship เพราะ astro preview ทำไม่ได้เงียบ ๆ

deploy target จริง ๆ คือสองคำถามแยกกันที่ Astro ตอบเป็นอิสระจากกัน: “ไฟล์ไปอยู่ที่ไหน” (static host อะไรก็ได้ สำหรับ HTML/CSS/JS ที่ dist/client ผลิต) กับ “ใครรัน server code” (adapter ที่แปล on-demand rendering ของ Astro เป็น runtime shape ของ platform นั้นเจาะจง) Cloudflare ที่ตอบทั้งสองคำถาม — static asset ล้วน ๆ หรือ Worker จาก package เดียวกัน — คือภาพที่ชัดที่สุดว่านี่เป็นสองแกนที่แยกกันจริง ๆ ไม่ใช่การตัดสินใจ “hosting provider” เดียวรวมกัน

Deploy แบบ static Deploy แบบ on-demand
ต้องมี adapter ไหม ไม่ต้อง ต้อง
Host CDN/static host อะไรก็ได้ รวมถึง Cloudflare Pages โดยไม่ต้องมี adapter Cloudflare Workers, Node, Vercel, Netlify Functions
astro preview ทดสอบได้จริง local ไหม ได้เสมอ เฉพาะ adapter ที่ ship preview entrypoint (Node, Cloudflare — พิสูจน์แล้วข้างบน; ไม่ใช่ Vercel/Netlify)
เหมาะกับ content ที่เหมือนกันสำหรับทุกคน auth, form, ข้อมูล live/request-time
  • “astro preview เป็นวิธี smoke-test production build ก่อน deploy ที่ใช้ได้ดี ไม่ว่า adapter ไหน” พิสูจน์แล้วข้างบน: บน Vercel กับ Netlify โดยเฉพาะ มันรัน route on-demand ไม่ได้เลย — ได้แค่ส่วน static เท่านั้น มันยังบอกตรง ๆ ด้วยว่าไม่ได้ตั้งใจให้รับ production traffic ไม่ว่า adapter ไหน
  • “deploy ไป Cloudflare ต้องมี adapter: cloudflare() เสมอ” เว็บ static ล้วน deploy ไป Cloudflare เป็น static asset ธรรมดาโดยไม่ต้องมี adapter เลย — adapter มีไว้แค่สำหรับ on-demand rendering บน platform เดียวกันนั้น
  • “@astrojs/db แค่ไม่ค่อยมีคนใช้เท่า Drizzle ไม่ได้ deprecate จริง” พิสูจน์แล้วข้างบนด้วยประกาศ deprecation จริงบนตัว package เอง
  • “อัปเกรด Astro 6 → 7 ส่วนใหญ่คือแก้โค้ดของตัวเอง” ส่วนใหญ่ของ checklist ข้างบนคือการลบสิ่งที่ไม่มีอยู่แล้ว (experimental flag, ค่าคงที่ astro:transitions) มากกว่าจะเป็นการแก้ bug ในโค้ดของคุณเอง
เว็บ Astro ที่ static ล้วน deploy ที่ไหนได้?
adapter จำเป็นสำหรับ deploy เมื่อไร?
เว็บที่ deploy ใต้ example.com/docs/ มี CSS และ link คืน 404 หมด สาเหตุที่น่าจะเป็นคือ?
Starlight คืออะไร?
ข้อไหนเป็นส่วนหนึ่งของการอัปเกรด Astro 6 → 7 ตามปกติ?
โปรเจกต์ deploy ไป Vercel ด้วย adapter: vercel() เพื่อนร่วมทีมบอกว่า "ฉันรัน astro preview แล้ว route on-demand ทำงาน เลยพร้อม ship" อะไรคือความจริง พิสูจน์แล้วข้างบน?
deployment guide ที่ AI generate มาแนะนำ @astrojs/db ว่าเป็น "embedded database แบบเบา ๆ" npm registry จริงพูดว่าอะไร?