iT邦幫忙

2026 iThome 鐵人賽

DAY 27
0
Modern Web

用 Astro 打造 Content-first 前端網站:30 天從靜態內容到會員、資料庫與選型(3rd)系列 第 27

astro.config 裡的 integrations 到底在做什麼?該裝哪些?

  • 分享至 

  • xImage
  •  

安裝 integration 前,先說清楚缺的是哪一種能力。Astro integration 適合加入 framework
renderer、內容格式或跨建置流程的能力;adapter 負責部署輸出,Vite plugin 處理 bundler。它們都寫在
astro.config.mjs,但執行層不同。

現有內容站用了 React、Vue、MDX 三個 integrations;prefetch 與 dev toolbar 雖然也寫在 config 裡,卻分別影響 client
runtime 與 dev server。版本基準是 Astro 7.1.1、Vite 8.1.5;官方文件查證與瀏覽器實測日期為 2026-07-24。

Config 裡的擴充點不只一種

先看這個專案已經存在的三段設定:

export default defineConfig({
  integrations: [react(), vue(), mdx()],
  adapter: cloudflare(),
  vite: {
    plugins: [precompileServerDeps()],
  },
});

三段都會影響 Astro 的運作,但責任不同:

擴充點 本專案實例 負責什麼
Astro integration react()vue()mdx() 註冊 framework renderer、內容格式與 Astro lifecycle hooks
Adapter cloudflare() 把 build output 接到 Cloudflare runtime 與部署格式
Vite plugin precompileServerDeps() 修改 bundler 層的 dependency optimization

cloudflare() 不放在 integrations,因為它解決的是「產物要交給哪個 runtime」。precompileServerDeps()
也不是 integration,它只處理 Vite environment 裡的 React server dependencies。

如果只是需要在頁面裡呼叫一個日期函式或驗證資料,也不必先找 integration。一般 npm
library 可以直接 import;只有需要進入 Astro config、route、dev server 或 build
lifecycle 時,integration 才是合理的擴充層。

每個 integration 都要對應到實際用途

這個專案目前裝了三個 integrations:

import react from "@astrojs/react";
import vue from "@astrojs/vue";
import mdx from "@astrojs/mdx";

export default defineConfig({
  integrations: [react(), vue(), mdx()],
});

三個 integrations 各自都有實際使用點:

Integration 實際使用點 沒有它會少什麼
@astrojs/vue 搜尋、文章 reaction、登入、收藏、feedback、cart islands .vue renderer 與 hydration
@astrojs/react Day 8 的 React bench routes .tsx renderer 與 hydration
@astrojs/mdx demos/mdx-demo.mdx .mdx 編譯與 route

Day 8 的 Vue island 沒有把整站變成 SPA。Framework
integration 只是讓 Astro 認得該 framework 的 component,是否送 JS 到瀏覽器仍要逐一用 client:*
決定。Day 9 的 MDX 實作 也是如此:安裝 MDX 後才多出在內容中 import
component 的編譯能力,純 Markdown 不受影響。

Day
27 沒有再裝第四個 integration。目前三個套件都有可指出的 consumer,也沒有第四個能力缺口;marketplace 上有多少選項,並不構成安裝依據。

用「有可指出的 consumer」檢查真實專案,可以看出套件是否仍有實際用途。

一個上線中的多語系品牌官網,config 的三層都用到了:

export default defineConfig({
  integrations: [vue({ appEntrypoint: "/src/modules/app.js" }), UnoCSS({ injectReset: true })],
  vite: { plugins: [svgLoader()] },
});

vue()appEntrypoint 有明確 consumer。這個 integration option 指向一個檔案,讓每座 Vue
island 建立實例時都先跑同一段初始化:

export default (app) => {
  app.use(getI18n());
  app.component("SvgIcon", SvgIcon);
};

appEntrypoint 解決的是一個具體缺口:islands 彼此獨立,每座島都是一個獨立的 Vue
app,沒有這個入口就得在每個元件各自處理 i18n 與全域元件註冊。這段設定能「指向一個真實缺口」,也能對應到 consumer:每座 Vue
island 的共用初始化。

同一份 config 裡,其他套件的 consumer 沒那麼明確。UnoCSS 已經安裝,但跑完 build 統計,全站真正用到的 utility
class 只有一個。依賴清單裡還有一個字體套件從未被 import(UnoCSS 的 web fonts
preset 已經在載同一款字體);另有一個加密函式庫和一個裝置判斷函式庫,在程式碼裡也都是零引用。

這些依賴是逐步累積的:每個套件裝進來時都對應某個當下的打算,打算後來換了,套件卻留著。保留它們仍有成本:它們會待在 lockfile 裡、跟著升級,相關安全通報也得繼續判斷。

這個判準也要用在安裝之後:除了「裝之前有沒有真實缺口」,還要問「現在還指得出 consumer 嗎」。npm ls
列出來的每個套件,最好都答得出是誰在用。

Integration hooks 跑在哪一層?

Astro integration 的公開介面是一個帶 namehooks 的物件:

function exampleIntegration() {
  return {
    name: "example-integration",
    hooks: {
      "astro:config:setup": ({ updateConfig, logger }) => {
        logger.info("config setup");
        updateConfig({
          // 合併一小段 Astro config
        });
      },
    },
  };
}

Astro 會依 integrations 陣列順序執行它們。常見 hooks 可以先分成三組:

生命週期 代表 hooks 適合觀察什麼
Config astro:config:setupastro:config:done config 合併、renderer、route、script 註冊
Dev server astro:server:setupserver:startserver:done Vite dev server、dev toolbar、watch 行為
Production build astro:build:startbuild:setupbuild:done bundling、產出目錄、pages 與 assets

這些 hooks 不等於 production 的每次 request。Integration 可以在 build 時注入一段 browser
script,也可以註冊 middleware,但「integration hook 本身」仍屬於 config、dev server 或 build lifecycle。

Astro 7 的公開 API 也沒有 addIntegration()。新增套件時,可以把 integration 放進 integrations 陣列,或用 astro add
協助安裝與更新 config。astro:config:setup 提供的
updateConfig()addRenderer()addWatchFile()addDevToolbarApp(),則各自處理特定能力。

只看 config,會誤判 prefetch 根本沒開

Day 25 已在共用 layout 加入 <ClientRouter />

<head>
  <ClientRouter />
</head>

但 Day 27 開始前,astro.config.mjs 沒有 prefetch,source 也找不到
data-astro-prefetch。只查這兩處,很容易得到「網站沒有 prefetch」的結論。

Astro 7.1.1 套件內的程式碼顯示,ClientRouter 會在 prefetch 沒被停用時這樣初始化:

init({ prefetchAll: true });

正式頁原本會對所有同源連結採用預設 hover 策略。滑鼠停在 header、文章卡或頁尾連結時,符合條件的目的頁都可能先被抓取。

Prefetch 能縮短點擊後的等待,代價是額外 request。文章列表有很多連結,讀者只是移動滑鼠,就可能發出最後沒有用到的 request。這個內容站更適合只預取主要導覽,讓文章卡維持點擊時再載入。

把全站預取改成明確 opt in

先在 config 覆寫 ClientRouter 的預設:

export default defineConfig({
  prefetch: {
    prefetchAll: false,
    defaultStrategy: "hover",
  },
});

Astro 7 的正確鍵名是 prefetch.defaultStrategy。如果舊文章寫 defaultPrefetchStrategy,那不是現行公開設定。

prefetchAll: false 代表只有帶 data-astro-prefetch 的連結會被處理。defaultStrategy: 'hover'
則讓沒有指定值的標記在 hover 或 keyboard focus 時觸發:

<a href="/blog/page/1" data-astro-prefetch> 依序閱讀 </a>

網站只替品牌與 header 的三個主要導覽加標記。首頁文章卡、CTA、language
picker 與 footer 維持未標記,Network 結果才有可歸因的對照組。

除了 hover,Astro 還提供三種策略;四種策略的觸發時機如下:

策略 觸發時機 適合的情境
tap pointer 按下、正式 click 前 最保守;行動裝置也能提早一小步
hover hover 或 focus 少量、高意圖的主要導覽
viewport 連結進入 viewport 接近畫面才有較高機率會用到的連結
load page load 後 連結少,而且幾乎確定下一步會前往

慢速連線或 data saver 下,Astro 會把積極策略退回
tap。策略要配合連結數量、使用意圖與讀者網路成本,觸發得早不一定比較合適。

另外,@astrojs/prefetch 已停止維護。Astro 3.5 之後應使用內建 prefetch config,不要為了舊教學再裝一次 integration。

Network 實測:0 次對 1 條 request chain

Production preview 開在同一個首頁,先清空 Network request log,再各 hover 250ms:

測試連結 是否有 data-astro-prefetch 目的頁 request
Day 26 文章卡 0
Header「依序閱讀」 1 條 prefetch request chain

標記過的連結會先請求 /blog/page/1,初始 request 帶著 Sec-Purpose: prefetch。Cloudflare preview 接著把它整理成
/blog/page/1/,兩筆 Network 紀錄共用同一個 request
ID,最後回 200;這是一條 redirect 後完成的 prefetch,不是兩次獨立預取。

這組結果確認兩件事:

  1. prefetchAll: false 確實覆寫了 ClientRouter 的隱式全站預取。
  2. data-astro-prefetch 仍能替高意圖連結保留 prefetch。

Prefetch script 在支援的瀏覽器會建立 <link rel="prefetch">,否則退回低優先序
fetch()。因此驗收應看 Network 是否在策略觸發時出現目的頁 request,不是只確認 HTML 上有一個 attribute。

Dev toolbar 是開發工具,不是產品功能

Astro dev toolbar 預設開啟,可以檢查 islands、accessibility 與 performance audits。Day 27 另外設定的只有團隊預設位置:

export default defineConfig({
  devToolbar: {
    placement: "bottom-right",
  },
});

Astro dev server 首頁右下角顯示 Inspect、Audit、Settings 等 dev toolbar 按鈕

placement 不需要搭配 enabled: true,因為它本來就是 project default。使用者若在 toolbar UI 改過位置,瀏覽器
localStorage 的個人偏好仍會覆寫 config;這個欄位是團隊的初始值,不是強制鎖位。

Production 的結果要單獨驗證。Node 24 build 完成後,production preview 實測結果為:

檢查項目 數量
astro-dev-toolbar element 0
指向 @vite/client 的 script 0

Toolbar、Vite
HMR 與 framework 的 dev-only 輔助碼不該被算進產品 bundle。Day 1 的 JS 量測若改在 dev
server 重做,就會把這些工具碼混進來;量產品成本要看 production build 或 preview。

安裝 integration 前,先回答五個問題

Integrations 可以延伸 Astro,但每多裝一個,就多一項版本相容與升級工作。安裝前先回答:

  1. 缺的是 framework renderer、內容格式、build hook、adapter,還是一般 runtime library?
  2. 不裝它,哪個具體檔案或流程無法工作?
  3. 套件是否仍維護,並支援目前的 Astro、Vite 與 adapter 版本?
  4. 它會注入 client JS、只跑 build,還是只存在 dev?
  5. 移除或升級時,可以用哪個 route、request、build output 或錯誤訊息驗證?

這五個問題也能用來檢查 config。Day 22 的 env schema服務 server
secrets,Day 26 的 i18n config改變 URL 規則,prefetch 則改變 client
runtime 的 request 時機。這些設定雖然都放在同一個檔案,仍要用不同方式驗收。

今日驗收

  • astro info 能列出實際使用的 React、Vue、MDX integrations 與 Cloudflare adapter。
  • Node 24 執行 Astro 7.1.1 production build 成功,output 維持 static
  • 未標記文章卡 hover 250ms,目的頁 request 為 0。
  • 標記過的 header link hover 250ms,出現 1 條帶 Sec-Purpose: prefetch 的 request chain。
  • Dev server 顯示右下角 toolbar;production 的 toolbar element 與 @vite/client script 都是 0。
  • 390px viewport 沒有水平 overflow。header client navigation 與 back/forward 後,aria-current 正確,navigation
    entry 維持 1;console 與 page errors 都是 0。

Day 28 會先分清 CMS 的內容來源、編輯體驗與部署邊界,再判斷 Google Sheets、Keystatic 或 Strapi 哪一種能補上需求。

官方查證:Configuration referenceIntegrations guideIntegration APIPrefetch guideDev toolbar guideDev Toolbar App API


上一篇
要支援多語系時,路由與內容怎麼組織才不會失控?
下一篇
Astro 內容站該選 Google Sheets、Keystatic 還是 Strapi?
系列文
用 Astro 打造 Content-first 前端網站:30 天從靜態內容到會員、資料庫與選型(3rd)28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言