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

ข้อควรพิจารณาเฉพาะของ Astro

ความยืดหยุ่นของ Astro ที่รองรับทั้ง static, SSR และ hybrid rendering นำมาซึ่งการตัดสินใจสำคัญหลายข้อที่ส่งผลโดยตรงต่อพฤติกรรมของ service worker การทำความเข้าใจเรื่องเหล่านี้จะช่วยให้ผู้ใช้ได้รับประสบการณ์ offline ที่รวดเร็วและเชื่อถือได้

โหมด output เริ่มต้นของ Astro คือ static ซึ่งจะ render ทุกหน้าเป็นไฟล์ .html ในช่วง build time ทำให้ @vite-pwa/astro สามารถสแกนโฟลเดอร์ dist/ และนำทุกไฟล์ HTML เข้า precache manifest ได้โดยอัตโนมัติ

เมื่อเปลี่ยนเป็น output: 'server' หรือ output: 'hybrid' สถานการณ์จะเปลี่ยนไป เนื่องจาก SSR routes ถูก generate บน server เมื่อมีการร้องขอ จึงไม่มีไฟล์ .html ให้ Workbox hash และ precache ได้ routes เหล่านั้นต้องใช้ runtime caching แทน

// astro.config.mjs — SSG (default), all pages precached
AstroPWA({
registerType: 'autoUpdate',
workbox: {
globPatterns: ['**/*.{css,js,html,svg,png,ico}'],
// Every /blog/*, /about, / etc. is a static file — precached
},
})
// astro.config.mjs — hybrid SSR
// output: 'hybrid' or 'server'
AstroPWA({
registerType: 'autoUpdate',
workbox: {
globPatterns: ['**/*.{css,js,svg,png,ico}'], // assets only — no .html for SSR routes
runtimeCaching: [
{
urlPattern: ({ url }) => url.pathname.startsWith('/api/'),
handler: 'NetworkFirst',
options: { cacheName: 'api-cache', networkTimeoutSeconds: 3 },
},
],
},
})
สถานการณ์PrecacheRuntime cache
SSG page (output: 'static')ใช่ (อัตโนมัติ)ไม่จำเป็น
SSR page (output: 'server')ไม่จำเป็น
Static asset (CSS/JS/images)ใช่ไม่
External APIไม่จำเป็น

เมื่อ deploy Astro ไปยัง sub-path เช่น GitHub Pages ที่ /my-app/ scope ของ service worker จะต้องตรงกับ base นั้น หาก scope เป็น / แต่แอปอยู่ที่ /my-app/ SW จะไม่สามารถควบคุมหน้าของคุณได้

ตั้งค่า base, scope, manifest.start_url และ root ของ Workbox globPatterns ให้สอดคล้องกัน:

// astro.config.mjs — deployed at /my-app/
export default defineConfig({
base: '/my-app/',
integrations: [
AstroPWA({
scope: '/my-app/',
base: '/my-app/',
manifest: { start_url: '/my-app/' },
workbox: { globPatterns: ['**/*.{css,js,html,svg,png,ico}'] },
}),
],
})

ค่าเริ่มต้น trailingSlash ของ Astro คือ 'ignore' หมายความว่าทั้ง /about และ /about/ ใช้ได้ ให้แน่ใจว่า scope ลงท้ายด้วย slash (/my-app/) เพื่อให้ SW ควบคุม path ทั้งหมดภายใต้ prefix นั้น

Astro islands จะส่ง JavaScript ของแต่ละ component เป็น chunk แยกต่างหากใน dist/ เนื่องจาก @vite-pwa/astro precache ทุกไฟล์ที่ตรงกับ globPatterns bundle JS ของ island ทั้งหมดจึงถูก cache โดยอัตโนมัติ island ที่ใช้ client:visible หรือ client:idle จะ hydrate ได้ถูกต้องแม้ offline ตราบที่ chunk ของตัวเองอยู่ใน precache manifest ซึ่งจะเป็นเช่นนั้นหาก globPatterns ครอบคลุม **/*.js

ไม่จำเป็นต้องกำหนดค่าพิเศษสำหรับ islands offline support ข้อจำกัดสำคัญคือข้อมูลของ island ต้องพร้อมใช้งาน offline ด้วย: หาก component นั้น fetch จาก API ที่ไม่ได้ cache ไว้ขณะ runtime ข้อมูลนั้นจะหายไปเมื่อ offline

Service worker จะถูก generate เฉพาะระหว่าง astro build เท่านั้น การรัน astro dev ไม่ สร้าง SW ดังนั้น DevTools จะไม่แสดง service worker ที่ register ไว้ ให้ทดสอบ PWA กับ production build เสมอ:

Terminal window
# Build first, then preview — the SW only works in the built output
npm run build
npm run preview
# Open http://localhost:4321 in DevTools > Application > Service Workers

หลังเปิด preview URL ไปที่ DevTools → Application → Service Workers เพื่อยืนยันว่า SW registered และ active แล้ว ใช้ Cache Storage เพื่อตรวจสอบว่า precache manifest entries มีอยู่ครบถ้วน หากต้องการจำลองพฤติกรรม offline ให้ติ๊ก Offline ใน Network panel แล้ว reload

ตัวเลือกBenefitCost
Astro SSG (precache ผลลัพธ์ build ทั้งหมด)offline ทำงานได้ทันทีหลัง build เพราะทุกหน้าเป็น static file อยู่แล้วเนื้อหาที่เปลี่ยนบ่อยต้อง rebuild+redeploy ใหม่ทุกครั้งถึงจะ cache ตัวใหม่
Astro + island architecture (partial hydration)ส่ง JS ลง client น้อยกว่ามาก เหมาะกับ PWA ที่เน้นความเร็วต้องระวัง service worker cache แยก JS ของแต่ละ island ให้ถูก scope
  • ลืมว่า Astro เป็น multi-page app โดย default ทำให้ navigation ระหว่างหน้าเป็น full page load ที่ service worker ต้อง handle ต่างจาก SPA
  • ไม่เผื่อ cache สำหรับหน้าที่ render แบบ SSR (ถ้าใช้ hybrid mode) ทำให้ offline fallback ใช้ไม่ได้กับหน้าที่ไม่ใช่ static
  • Precache ทุกหน้ารวมถึงหน้าที่แทบไม่มีคนเข้า ทำให้ storage โตเกินจำเป็นโดยไม่ได้ประโยชน์เพิ่ม

💡 ตัวอย่างจากของจริง

VitePress / Astro documentation sites — ใช้ SSG ร่วมกับ service worker precache ทำให้ documentation เปิดอ่านได้แบบ offline ทันทีหลังเข้าชมครั้งแรก

Astro blog starter ecosystem — หลายเว็บบล็อกที่ build ด้วย Astro ใช้แนวทาง precache ทั้งเว็บเพราะขนาดไฟล์เล็กพอจะทำได้จริง

ในโหมด SSG ทำไมหน้า HTML ถึงถูกนำเข้า precache manifest โดยอัตโนมัติ?
คุณ deploy Astro site ที่ /docs/ สิ่งที่ต้องตั้งค่าใน AstroPWA เพื่อให้ SW ควบคุมทุกหน้าภายใต้ path นั้นคืออะไร?
ทำไมต้องรัน npm run build ก่อนทดสอบ service worker ด้วย astro preview?
Astro island ที่ใช้ client:visible ดึงข้อมูลจาก external API ขณะ runtime จะทำงานได้ offline ไหม?