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

Config & Integrations

ทุกโปรเจกต์ Astro ตั้งค่าจาก astro.config.mjs ผ่าน defineConfig ครั้งเดียว มีไม่กี่ key ที่รับน้ำหนักส่วนใหญ่:

astro.config.mjs
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import sitemap from '@astrojs/sitemap';
import react from '@astrojs/react';
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
site: 'https://example.com', // absolute site URL (used for sitemap, canonical, RSS)
base: '/docs', // path prefix if not served at the domain root
output: 'static', // 'static' (default) or 'server' for on-demand
adapter: cloudflare(), // runtime for on-demand rendering
integrations: [mdx(), sitemap(), react()],
vite: { /* escape hatch to raw Vite config */ },
});
  • site คือ URL ที่ deploy จริง จำเป็นสำหรับอะไรก็ตามที่ต้องออก absolute URL (sitemap, canonical tag, RSS) base ตั้ง path prefix เมื่อเว็บอยู่ใต้ subpath (เหมือนคอร์สนี้อยู่ใต้ /astro)
  • output เลือก rendering mode เริ่มต้น adapter ให้ runtime เมื่อใช้ on-demand rendering (จากบทเรียน rendering)
  • integrations คือ list ของ plugin ที่ขยายความสามารถของ Astro

integration คือ plugin ทางการหรือของ community ที่ hook เข้ากับ build ของ Astro เพื่อเพิ่มความสามารถ — render UI framework, generate sitemap, เพิ่ม MDX support, ต่อ adapter คุณติดตั้งแล้วเพิ่มลงใน array integrations หลายตัวมีตัวติดตั้งแบบคำสั่งเดียวที่แก้ config ให้:

Terminal window
# astro add writes the import + integrations entry for you, and installs deps
npx astro add react
npx astro add mdx sitemap

integration ทางการที่พบบ่อย (@astrojs/*): react / vue / svelte / solid / preact (UI framework island), mdx (component ใน Markdown), sitemap และ adapter ของแต่ละ platform (cloudflare, node, vercel, netlify) หมายเหตุ: @astrojs/rss ไม่ใช่ integration — เป็น helper package ที่ import ใน endpoint เพื่อ generate feed จึงไม่มี astro add rss และไม่ต้องใส่ใน array integrations

astro add ไม่ใช่คำสั่ง “เพิ่ม npm package อะไรก็ได้” แบบ generic — มันรู้จักแค่ integration ที่มัน ship recipe ให้เท่านั้น ตามที่ CLI help จริงบน 7.3.5 ที่ติดตั้งจริงโชว์:

$ npx astro add --help
astro add [...integrations] [...adapters]
UI Frameworks
react astro add react
preact astro add preact
vue astro add vue
svelte astro add svelte
solid-js astro add solid-js
lit astro add lit
alpinejs astro add alpinejs
Documentation Frameworks
starlight astro add starlight
SSR Adapters
netlify astro add netlify
vercel astro add vercel
deno astro add deno
cloudflare astro add cloudflare
node astro add node
Others
tailwind astro add tailwind
mdx astro add mdx
markdoc astro add markdoc
partytown astro add partytown
sitemap astro add sitemap
For more integrations, check out: https://astro.build/integrations

อะไรที่ไม่อยู่ในลิสต์นั้น (community integration หรือ raw Vite plugin) ต้องเพิ่มด้วยมือเอง: npm install แล้วดันเข้า integrations (หรือ vite.plugins) เอง

integration คือ object ธรรมดาที่มี name กับ hooks map — แต่ละ hook fire ที่จุดเฉพาะใน lifecycle ของ Astro เอง สองตัวที่ใช้บ่อยที่สุด: astro:config:setup (ตอน Astro กำลัง resolve config ก่อนอะไรจะ build) กับ astro:build:done (หลัง build ทั้งหมดเสร็จ พร้อม output directory) พิสูจน์ด้วย integration จริง ๆ ตัวเล็ก ๆ กับ build จริง:

my-log-integration.mjs
export default function myLogIntegration() {
return {
name: 'my-log-integration',
hooks: {
'astro:config:setup': ({ logger }) => {
logger.info('config:setup ran');
},
'astro:build:done': ({ logger, dir }) => {
logger.info(`build:done, output at ${dir}`);
},
},
};
}
astro.config.mjs
import { defineConfig } from 'astro/config';
import myLogIntegration from './my-log-integration.mjs';
export default defineConfig({
integrations: [myLogIntegration()],
});
$ npx astro build --outDir dist
[my-log-integration] config:setup ran
[my-log-integration] build:done, output at file:///.../dist/client/

ทั้งสองบรรทัดคือ logger output จริงจาก build จริง — astro:config:setup fire ครั้งเดียว แต่เนิ่น ๆ ตอน Astro ยังประกอบ config อยู่ (จุดที่ integration ส่วนใหญ่ register Vite plugin หรือ content collection); astro:build:done fire ครั้งเดียว ตอนจบเลย และส่ง dir มาให้ — ตำแหน่ง output จริง — ซึ่งตรงกับที่ integration ที่ต้องประมวลผล build output ต่อ (เขียน manifest, upload asset) รอคอยพอดี

ข้างใต้นั้น dev server และ build ของ Astro ขับเคลื่อนด้วย Vite — ตั้งแต่ Astro 7 คือ Vite 8 ที่ bundler default เป็น Rolldown ซึ่งเขียนใหม่ด้วย Rust เร็วกว่า Rollup 10–30 เท่าแต่ยังใช้ plugin API เดิม นั่นคือเหตุผลที่ dev server เริ่มทันที, HMR เร็ว และคุณใช้ plugin จาก ecosystem ของ Vite/Rollup ได้เกือบทั้งหมด (เช็กว่า plugin รองรับ Vite 8 ตอนอัปเกรด) เมื่อต้องการอะไรที่ Astro ไม่ได้เปิดให้ตรง ๆ ก็ลงไปที่ key vite แล้วตั้งค่า Vite เอง:

export default defineConfig({
vite: {
plugins: [/* any Vite plugin */],
resolve: { alias: { '@': '/src' } },
},
});
flowchart TB
  cfg["astro.config.mjs (defineConfig)"] --> integ["integrations: UI frameworks, mdx, sitemap, adapter"]
  cfg --> vite["vite: raw Vite 8 (Rolldown) plugins and config"]
  integ --> build["Astro build"]
  vite --> build
Astro ประกอบ integrations บน Vite

Astro 7 ทำให้หลายฟีเจอร์ stable ซึ่งแปลว่า flag experimental ที่คู่กัน หายไปแล้ว — ปล่อยทิ้งไว้จะเกิด config error ให้ย้ายขึ้นมาระดับบนสุด:

// Astro 6 // Astro 7
experimental: { cache: { ... } } cache: { ... }
experimental: { routeRules: { ... } } routeRules: { ... }
experimental: { logger: { ... } } logger: { ... }
experimental: { rustCompiler: true } // removed — the Rust compiler is the only compiler
experimental: { queuedRendering: true } // removed — now the default
experimental: { advancedRouting: true } // removed — src/fetch.ts is always on

key ระดับบนใหม่ที่ควรรู้: compressHTML ตอนนี้ default เป็น 'jsx' (กฎ whitespace แบบ JSX); fetchFile ย้ายหรือปิด entrypoint src/fetch.ts ที่ถูกจองชื่อ; markdown.processor ให้สลับ Sätteri เป็น unified() จาก @astrojs/markdown-remark และมี package หนึ่งที่หายไป: @astrojs/db ไม่ได้ดูแลต่อแล้ว — ใช้ node:sqlite, Drizzle หรือ database แบบ hosted (Turso, Neon, PlanetScale) แทน

ไม่ใช่ทุกอย่างย้ายขึ้นระดับบนสุด — บาง flag ยัง experimental จริง ๆ นี่คือลิสต์จริงครบถ้วน อ่านตรง ๆ จาก config schema ของ package ที่ติดตั้งจริง (node_modules/astro/dist/core/config/schemas/base.js) ไม่ใช่ blog post ที่อาจล้าสมัยไปแล้วตอนคุณอ่าน:

experimental: {
clientPrerender, // pre-render <a> targets on hover/viewport-entry via speculation rules
contentIntellisense, // editor JSON schemas for content collection frontmatter
chromeDevtoolsWorkspace,// wires the dev server into Chrome DevTools' Workspaces feature
incrementalBuild, // only rebuild what changed, for faster repeated builds
svgOptimizer, // hook to run your own optimizer over inlined SVGs
collectionStorage, // 'single-file' | 'chunked' | { type: 'chunked', chunkSize } — content store layout
}

ถ้า config snippet (ของคุณเองหรือ AI generate มา) ตั้ง experimental.rustCompiler, experimental.queuedRendering, หรือ experimental.advancedRouting มันล้าสมัยแล้ว — สามตัวนี้ถูกถอดออก ไม่ใช่เปลี่ยนชื่อ เพราะพฤติกรรมของมันเปิดเป็น default อยู่แล้ว (พิสูจน์ข้างบน) การตั้ง key ที่ไม่รู้จักใต้ experimental เป็น schema validation error จริง เพราะ schema ข้างบนคือ z.strictObject

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

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
rustCompiler: true,
contentIntellisense: true,
},
});
เฉลย

contentIntellisense เป็นของจริงและยัง experimental อยู่ใน 7.3.5 — ส่วนนั้นไม่มีปัญหา rustCompiler ไม่ใช่: Rust compiler เลิกเป็น optional ตั้งแต่ Astro 7 ทำให้มันเป็นคอมไพเลอร์เดียวแล้ว flag เลยถูกลบไปพร้อมกับตัวเก่าที่ใช้ JS ที่มันเคยไว้สลับออก เพราะ experimental ถูก validate เป็น z.strictObject (verify แล้วจาก schema ที่ติดตั้งจริง) key ที่ไม่รู้จักแบบนี้จะทำให้ config validation ล้มเหลวจริง ๆ พิสูจน์ด้วย config เป๊ะ ๆ นี้กับ build จริง:

[config] Astro found issue(s) with your configuration:
! Invalid or outdated experimental feature.
Check for incorrect spelling or outdated Astro version.
See https://docs.astro.build/en/reference/experimental-flags/ for a list of all current experiments.

ไม่ใช่ no-op เงียบ ๆ — build ปฏิเสธที่จะเริ่มเลย วิธีแก้ก็แค่ลบบรรทัด rustCompiler ทิ้ง

Tailwind ใน Astro ปัจจุบันติดตั้งเป็น Vite plugin (@tailwindcss/vite, Tailwind v4) — ไม่ใช่ integration @astrojs/tailwind แบบเก่า ตัวติดตั้งคำสั่งเดียวต่อให้เรียบร้อย:

Terminal window
npx astro add tailwind

คำสั่งนั้นติดตั้ง plugin, เพิ่มลง Vite config และสร้าง CSS entry ให้ จากนั้น import CSS ครั้งเดียว (เช่นใน layout) แล้วใช้ Tailwind utility class ใน markup ได้ ถ้าเจอ guide ที่อ้างถึง integration @astrojs/tailwind นั่นคือวิธีเก่า วิธีปัจจุบันคือ Vite plugin ผ่าน astro add tailwind

เสถียรตั้งแต่ Astro 6.0, security.csp generate Content-Security-Policy จริงให้ทุกหน้า — hash inline script/style ของ Astro เองอัตโนมัติ จึงไม่ต้องดูแล hash list เองทุกครั้งที่ build output เปลี่ยน:

astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
security: {
csp: true, // or an object: { algorithm: 'SHA-512', directives: [...], scriptDirective: {...}, styleDirective: {...} }
},
});

Astro ส่ง policy เดียวกันผ่านสองกลไกต่างกันขึ้นอยู่กับว่าหน้านั้น render ยังไง — พิสูจน์กับ build จริงที่มี security: { csp: true } หน้าแบบ on-demand (prerender = false หรือทั้งโปรเจกต์อยู่ใต้ output: 'server') ได้มันเป็น HTTP response header จริง เพราะมี response ที่มีชีวิตให้แนบ:

$ curl -sD - -o /dev/null http://127.0.0.1:4351/ | grep -i content-security-policy
content-security-policy: script-src 'self' 'sha256-mzyhaPlEXQku46rgza6MekztMi+pKj5BkQ4z75dLyDw=' 'sha256-BF0290pkb3jxQsE7z00xR8Imp8X34FLC88L0lkMnrGw=' ...; style-src 'self' ;

หน้าแบบ prerendered (prerender = true หรือ default 'static') ไม่มี response ที่มีชีวิตให้แนบ header — directive เดียวกันเป๊ะถูกเขียนลงใน HTML ที่ build แล้วแทน เป็น tag <meta http-equiv>:

$ grep -o '<meta[^>]*content-security-policy[^>]*>' dist/client/static-about/index.html
<meta http-equiv="content-security-policy" content="script-src 'self' 'sha256-mzyhaPlEXQku46rgza6MekztMi+pKj5BkQ4z75dLyDw=' ...; style-src 'self' ;">

ทั้งสองมาจาก config security.csp ตัวเดียวกันเป๊ะและพก script/style hash ที่ generate เหมือนกันเป๊ะ — มีแค่กลไกการส่ง (header vs <meta>) ที่ต่างกัน เลือกอัตโนมัติต่อ route ตาม prerender ซึ่งเป็น setting เดียวกับที่บท SSR & adapters สอนไว้

astro.config.mjs ที่ AI generate มา — หรือคำตอบทั้งหมดแบบ “นี่คือวิธี config Astro” — ควรเช็คกับสิ่งที่ 7.3.5 validate จริง:

  • มัน nest อะไรใต้ experimental ที่ไม่ใช่หนึ่งในหก flag จริงที่พิสูจน์ข้างบนหรือเปล่า (clientPrerender, contentIntellisense, chromeDevtoolsWorkspace, incrementalBuild, svgOptimizer, collectionStorage)? flag ที่ล้าสมัยจาก blog post Astro 4/5 เป็น startup error จริง พิสูจน์แล้วข้างบน ไม่ใช่แค่ warning
  • มันยัง nest cache, routeRules, หรือ logger ใต้ experimental อยู่หรือเปล่า? พวกนี้เป็น key ระดับบนสุดตั้งแต่ Astro 7 แล้ว
  • มันเพิ่ม @astrojs/tailwind เข้า integrations หรือเปล่า? นั่นคือ integration ก่อนยุค Tailwind v4 Astro ปัจจุบันใช้ Vite plugin @tailwindcss/vite แทน ติดตั้งผ่าน astro add tailwind
  • มันแนะนำ @astrojs/db สำหรับ database layer หรือเปล่า? มันถูก npm deprecate แล้ว — verify ตรง ๆ: npm view @astrojs/db deprecated คืนค่า “This package is deprecated. Use a database client (Drizzle, Kysely, etc.) directly instead.”
  • hook ของ integration อ่าน dir (output directory) ใน astro:config:setup แทนที่จะเป็น astro:build:done หรือเปล่า? พิสูจน์แล้วข้างบน: dir มีความหมายก็ต่อเมื่อ build ผลิต output จริงแล้วเท่านั้น — astro:config:setup รันก่อนอะไรจะ build เลยด้วยซ้ำ

astro.config.mjs ไม่ใช่ถุงรวม setting แบบแบน ๆ — มันใกล้เคียงกับคำอธิบาย pipeline มากกว่า: integrations (และ adapter) คือพฤติกรรมสำเร็จรูปที่ hook เข้ากับจุดเฉพาะใน build lifecycle (astro:config:setup, astro:build:done, … พิสูจน์แล้วข้างบนด้วย logging integration จริง) ในขณะที่ vite คือทางออกดิบที่อยู่ข้างใต้ทั้งหมดนั้น experimental เป็นพื้นที่ชั่วคราวที่ validate แบบ strictObject อย่างชัดเจน — พิสูจน์แล้วข้างบน key ที่ไม่รู้จักตรงนั้นจะล้มเหลวเสียงดัง ไม่ใช่ถูกเมินเงียบ ๆ ก็เพื่อให้ flag ที่ล้าสมัยจาก tutorial เก่าไม่ทำอะไรแบบเงียบ ๆ

Official integration (astro add x) Raw Vite plugin (vite.plugins)
การติดตั้ง คำสั่งเดียว แก้ config ให้ npm install ด้วยมือ + ต่อเข้า vite.plugins เอง
รู้จัก Astro ไหม ใช่ — hook astro:config:setup, register content collection ได้ ฯลฯ ไม่ — เป็น Vite plugin API ธรรมดาเท่านั้น
ครอบคลุมอะไร UI framework, MDX, sitemap, adapter, Tailwind อะไรก็ได้ใน ecosystem ที่ compatible กับ Vite/Rollup
ความเสี่ยงตกรุ่น ต่ำ — ดูแลตาม release cadence ของ Astro เอง ขึ้นกับว่าคนเขียน plugin ตาม Vite 8/Rolldown ทันไหม
  • “flag experimental ทั้งหมดจาก tutorial Astro 4/5 ยังใช้ได้ อาจแค่มี warning” พิสูจน์แล้วข้างบน: key experimental ที่ไม่รู้จักเป็น config error จริงบน 7.3.5 (z.strictObject) ไม่ใช่ warning — build ปฏิเสธที่จะเริ่มเลย
  • “astro add ติดตั้ง npm package อะไรก็ได้เข้า config” พิสูจน์แล้วข้างบนด้วย --help output จริง: มันรู้จักแค่ลิสต์ recipe ตายตัว อะไรนอกจากนั้นต้อง npm install เองบวกแก้ config เอง
  • “hook ของ integration อ่าน output dist/ ที่เสร็จแล้วได้ตั้งแต่ build เพิ่งเริ่ม” พิสูจน์แล้วข้างบน: astro:build:done — ไม่ใช่ astro:config:setup — คือตัวที่ fire หลังจาก output มีอยู่จริง พร้อม dir จริงชี้ไปที่มัน
  • “@astrojs/tailwind ยังเป็นวิธีที่ถูกต้องในการเพิ่ม Tailwind” มันคือ integration ก่อนยุค v4 Astro ปัจจุบัน astro add tailwind ติดตั้ง Vite plugin @tailwindcss/vite แทน
config option site ทำอะไร?
วิธีที่ง่ายที่สุดในการเพิ่ม integration ทางการอย่าง React คือ?
build tool ตัวไหนอยู่ใต้ Astro และเข้าถึงตรง ๆ ยังไง?
วิธีที่แนะนำในปัจจุบันสำหรับเพิ่ม Tailwind ใน Astro คือ?
หลังอัปเกรดเป็น Astro 7 config ของคุณยังมี experimental: { cache: ... } จะเกิดอะไรขึ้น?
บน [email protected] ที่ติดตั้งจริง build จริงจะทำอะไรกับ config นี้?
// astro.config.mjs
export default defineConfig({
  experimental: {
    rustCompiler: true,
    contentIntellisense: true,
  },
});
astro:build:done fire ตอนไหน และ dir ชี้ไปที่อะไร?
// my-log-integration.mjs
export default function myLogIntegration() {
  return {
    name: 'my-log-integration',
    hooks: {
      'astro:build:done': ({ logger, dir }) => {
        logger.info(`build:done, output at ${dir}`);
      },
    },
  };
}