我一直想把我的個人網站升級到Astro 6。發布說明在我的瀏覽器標籤頁裡躺了好幾個星期,每次想起來升級的時候,總能找到藉口去做別的事。這週,我終於沒藉口了。我抽出一個下午,執行了npx @astrojs/upgrade ,祈禱一切順利,期待著升級成功。
開發伺服器立即崩潰,並出現一個關於缺少tailwindcss套件的神秘錯誤。
我盯著錯誤看了一分鐘。然後,我做了任何一個理智的開發者在2026年都會做的事——我引入了一個人工智慧編碼代理,讓它幫我修復所有問題。
這篇文章正是我夢寐以求的實戰指南,同時也提醒我們,人工智慧代理雖然非常有用,但卻過於自信,存在安全隱患。你仍然需要清楚自己在做什麼。
Astro 5.x(各種補丁版本)
@astrojs/cloudflare v12.x
@astrojs/tailwind v5.x
舊版內容集合( src/content/config.ts , type: 'content' / 'data' )
astro-expressive-code v0.38.x
astro-icon v1.1.5
Astro 6.2
@astrojs/cloudflare v13
Tailwind CSS v4 ( @tailwindcss/vite )
astro-expressive-code v0.41.7
自訂內聯 SVG 圖示元件(替換astro-icon )
Cannot find package 'tailwindcss'Cannot find package 'tailwindcss' imported from
.../node_modules/@astrojs/tailwind/dist/index.js
透過升級指令安裝了@astrojs/tailwind v6,但它的package.json中只將tailwindcss列為對等依賴項,並沒有將其打包。由於tailwindcss不在我的dependencies中,Node 無法解析它。
我把錯誤訊息貼到代理程式中,詢問發生了什麼事。它立即診斷出是依賴項問題,並自信地轉向了 PostCSS。它新增了postcss.config.mjs 、 autoprefixed和@tailwind指令。網站恢復了功能,但方法完全錯誤。
我不得不要求代理人繼續使用 TailwindCSS 並遷移到 PostCSS。我要求代理人查閱 Astro 的文件,而不是憑空猜測。代理人隨後使用相關工具,提出了兩種方案:
方案A:繼續使用Tailwind 3(最簡單)
安裝tailwindcss@3並同時進行集成,保持所有設定不變:
npm install tailwindcss@3
您的astro.config.mjs保持不變:
import tailwind from '@astrojs/tailwind';
// ...
integrations: [tailwind()]
這是 Astro 文件推薦用於舊版 Tailwind 3 專案的路徑。
方案 B:升級到 Tailwind 4
Astro 5.2+ 包含一個astro add tailwind指令,用於安裝官方的 Vite 外掛程式 ( @tailwindcss/vite ),這是在 Astro 中使用 Tailwind 4 的新建議方法。
npx astro add tailwind
這就建立了以下關係:
在您的 Vite 外掛程式中設定@tailwindcss/vite (透過astro.config.mjs )
src/styles/global.css中使用@import "tailwindcss";
v4 版本不再需要tailwind.config.mjs文件,而是使用基於 CSS 的配置。
如果採用這種方法,您可以完全移除@astrojs/tailwind ,並按照Tailwind 的 v4 升級指南將您的自訂主題遷移到 CSS 變數。
我指示代理人執行方案 B ,執行npx astro add tailwind來設定正確的 Vite 插件,然後將自訂主題遷移到global.css中的新@theme區塊中:
@import "tailwindcss";
@theme {
--color-primary: #f97316;
--color-hover: #ea580c;
--color-light: rgba(249, 115, 22, 0.15);
--color-secondary: #fdba74;
}
@variant dark (&:where(.dark, .dark *));
如果你想保留 Tailwind 3:使用上面的選項 A,讓@astrojs/tailwind來完成工作。
如果你想使用 Tailwind 4:請使用選項 B 和官方的 Vite 插件。不要手動設定 PostCSS。
LegacyContentConfigError搞定 Tailwind 之後,我滿懷希望地重啟了開發伺服器。結果下一個錯誤又出現了。
[LegacyContentConfigError] Found legacy content config file in
"src/content/config.ts". Please move this file to
"src/content.config.ts" and ensure each collection has a loader defined.
Astro 5 引入了內容層 API ,但保留了對舊集合的自動向後相容性。 Astro 6 完全取消了此安全機制。我的src/content/config.ts檔案中包含type: 'content'和type: 'data'配置不再有效。
代理程式出色地完成了此次遷移。它移動了文件,重寫了導入語句,並配置了載入器:
前:
import { defineCollection, z } from 'astro:content';
const writings = defineCollection({
type: 'content',
schema: z.object({ ... })
});
const projects = defineCollection({
type: 'data',
schema: z.array(z.object({ ... }))
});
export const collections = { writings, projects };
後:
import { defineCollection } from 'astro:content';
import { glob, file } from 'astro/loaders';
import { z } from 'astro/zod';
const writings = defineCollection({
loader: glob({ pattern: '**/[^_]*.mdx', base: './src/content/writings' }),
schema: z.object({ ... })
});
const projects = defineCollection({
loader: file('src/content/projects/projects.json'),
schema: z.object({ ... }) // not z.array(...)
});
export const collections = { writings, projects };
主要變化:
檔案位置: src/content/config.ts → src/content.config.ts ( src/目錄下的專案根目錄)。
z導入: astro:content → astro/zod 。
type已移除:不再允許type: 'content'或type: 'data' 。您需要明確聲明一個loader 。
資料集合:如果您使用type: 'data'並傳入 JSON 文件,則新的file()載入器會為每個頂層物件傳回一個條目。模式應該是z.object(...) (單一條目),而不是z.array(...) (整個檔案)。
slug → id :在舊版 API 中, entry.slug是自動產生的。在新版 API 中, entry.id是辨識碼。我的 URL 需要更新:
// Before
href={`/writings/${post.slug}`}
// After
href={`/writings/${post.id}`}
這裡是代理程式越權的地方。它告訴我,由於我的貼文都儲存在folder/index.mdx結構中, glob()會根據檔案路徑產生 ID,產生類似migrating-astro-5-to-astro-6/index的檔案。它建議我去掉後綴:
href={`/writings/${post.id.replace(/\/index$/, '')}`}
總覺得哪裡不對勁。我writings庫裡的每篇文章在 frontmatter 裡都有slug字段,我預感 Astro 會用它作為文章id 。於是我提出異議,要求客服人員對照 Astro 的文件核實。
查閱文件後,無法確認當 frontmatter 中存在slug時, /index是否會被附加。實際上, post.id始終是migrating-astro-5-to-astro-6 ,而不是migrating-astro-5-to-astro-6/index 。對於我的配置來說, .replace()是不必要的,簡單的post.id就能正常運作。
注意:務必將代理程式的輸出與您自己的程式碼和建置輸出進行比對。代理程式執行速度很快,但最終發布它的責任在於您。
一切都還不錯。經紀人幫我節省了好幾個小時。但後來他變得自大起來。
Property 'runtime' does not exist on type 'Locals'內容集合已修復。我準備查看網站渲染效果。但 Cloudflare 適配器卻另有打算。
ts(2339): Property 'runtime' does not exist on type 'Locals'.
@astrojs/cloudflare v13 完全移除了Astro.locals.runtime 。新的文件說明如下:
import { env } from 'cloudflare:workers';
const kv = env.MY_KV;
我已將 API 路由遷移到這種模式。但是,我在開發環境中遇到了執行時錯誤:
module is not defined
源自 Cloudflare Vite 插件的工作進程。
客服人員花了不少時間嘗試各種隨機的修復方法——清除快取、重新排序導入、檢查 Vite 配置——但這些都沒用。最後我自己找到了問題所在: @astrojs/cloudflare v13 的開發伺服器執行在workerd內部,它與astro-icon整合有相容性問題。當astro-icon的<Icon>元件首次渲染時,workerd 模組執行器會崩潰,並出現module is not defined神秘錯誤,導致網站上的所有路由都無法正常運作。
此時,它感到很沮喪。它已經在這件事上花費了比預期更多的時間。為了讓某些功能正常執行,它不得不降級回@astrojs/cloudflare v12 版本。
但我們並沒有就此止步。代理人建議用一個小型自訂元件完全取代astro-icon該元件會內聯來自@iconify-json/mdi的 SVG 路徑。只需三十行程式碼,無需虛擬模組,也不存在workerd相容性問題。我們嘗試了一下,然後切換回 v13 版本,問題就解決了。
首先,更新wrangler.toml以使用 v13 入口點:
main = "@astrojs/cloudflare/entrypoints/server"
然後將所有程式碼從Astro.locals.runtime.env遷移到import { env } from 'cloudflare:workers' :
前:
const { env } = Astro.locals.runtime;
const kv = env.VOTES;
後:
import { env } from 'cloudflare:workers';
const kv = env.VOTES;
對於 TypeScript,我還必須在src/env.d.ts中擴充Cloudflare.Env ,新增wrangler.toml中未宣告的金鑰(例如YOUTUBE_API_KEY和GITHUB_TOKEN ):
declare namespace Cloudflare {
interface Env {
YOUTUBE_API_KEY: string;
PLAYLIST_ID: string;
GITHUB_TOKEN: string;
}
}
注意:代理程式不知道wrangler types命令。此命令會產生類型,從而避免手動新增類型。
這是必要的,因為import { env } from 'cloudflare:workers'是針對全域Cloudflare.Env介面進行類型定義的,而不是針對wrangler types產生的專案級Env進行類型定義。
最後,從package.json和astro.config.mjs中移除astro-icon ,並將所有<Icon name="mdi:github" />的用法替換為自訂元件。問題解決。
astro-expressive-code對等依賴項不匹配那是最大的挑戰。我以為已經萬事大吉了。結果npm run build提醒我,整合也有自己的時間表。
peer astro@"^4.0.0-beta || ^5.0.0-beta || ^3.3.0" from [email protected]
升級指令沒有更新astro-expressive-code ,因此它的對等依賴範圍仍然排除了 Astro 6。
npm install [email protected]
v0.41.7 正式支持 Astro 6。
這位經紀人第一次就猜對了。能贏就贏,我都欣然接受。
Buffer<ArrayBufferLike>' is not assignable to parameter of type 'BodyInit'正當我以為依賴之爭已經結束時,TypeScript 又給了我一個驚喜。
在我的原始影像生成端點中,我有:
const screenshot = await page.screenshot({ ... });
return new Response(screenshot, { ... });
升級後,TypeScript 開始拒絕將Buffer當作Response體。這不是執行時問題——Puppeteer仍然返回Buffer但astro check (以及npm run build )會標記出這個問題。
在傳遞給Response之前,已轉換為Uint8Array :
return new Response(new Uint8Array(screenshot), { ... });
這既符合 Workers 執行時期類型要求,也符合 TypeScript 的嚴格檢查要求。
| 指令 | 狀態 |
|---|---|
| npm install | ✅ (無--legacy-peer-deps ) |
| npm run dev | ✅ 所有路由都在workerd中渲染 |
| npm run build | ✅ |
| npm run preview | ✅ |
npx @astrojs/upgrade會處理 Astro 核心的版本升級,但整合元件通常有自己的升級時間表。升級後務必檢查npm ls是否有依賴項警告。
在 v6 版本中,內容集合遷移是不可避免的。 Astro 5 提供了一個過渡期,而 Astro 6 則沒有。新的loader API 實際上更清晰易懂,一旦你習慣了它。
適配器升級是最有風險的部分。 @astrojs/cloudflare v13 對環境綁定機制進行了重大更改,並將開發伺服器遷移到了workerd 。好處是你的開發環境現在幾乎與生產環境完全相同。缺點是某些整合(例如astro-icon )目前仍不相容於workerd的模組載入機制。
建構環境和開發環境不一樣。我的網站在開發伺服器執行之前很久就成功建置了。 v13 Cloudflare 適配器只在開發環境( astro dev )中出現問題,這是因為它在workerd內部執行程式碼的方式不同。務必同時測試建置環境和開發環境。
當整合出現問題時,請先查閱官方文件,然後再嘗試尋找變通方案。我之前已經拉取了@astrojs/tailwind並直接安裝了tailwindcss ,但客服人員建議我使用@tailwindcss/vite這是 Tailwind CSS v4 的正確 Vite 插件。 Astro 的npx astro add tailwind指令會自動為 v4 版本進行配置,而 v4 正是支援的版本。
import { env } from 'cloudflare:workers'是新的標準。它完全取代了Astro.locals.runtime.env 。如果您使用的是 v13 版本,請立即採用新標準——只需記住, wrangler types會生成Env接口,但cloudflare:workers讀取的是Cloudflare.Env ,因此您可能需要擴展命名空間以存儲密鑰。
AI代理是優秀的隊友,但卻不是好的團隊領導者。它們會自信地提出錯誤方案,忽略根本原因,甚至臆想出遷移細節。你需要掌握足夠的知識來反駁它們,核實它們的說法,並指導策略的發展。
從 Astro 5 升級到 6 並非只需一條指令即可完成。核心升級過程很順利,但圍繞著它整合的 Tailwind、Cloudflare 和 expressive-code 等元件,各自都存在一些重大變更。如果讓我重新來過,我會:
首先進行內容集合遷移( src/content/config.ts → src/content.config.ts )。
升級前請確定要使用 Tailwind 3 還是 4。對於 v4 版本,請使用npx astro add tailwind對於舊版 v3 版本,請使用 installtailwindcss@3` 。
直接升級到@astrojs/cloudflare v13。 Astro.locals.runtime → import { env } from 'cloudflare:workers' Astro.locals.runtime是機械式的。
測試時workerd npm run dev ,而不僅僅是npm run build比 Node 更嚴格。
v13 中的workerd開發伺服器整體來說是件好事——我的本地環境現在幾乎和生產環境一模一樣——但它容錯率很低。如果你遇到module is not defined或類似的底層錯誤,請追蹤是哪個整合觸發了這些錯誤。對我來說,用一個自訂的 30 行 SVG 元件取代astro-icon ,就解決了一整類相容性問題。
如果您正在計劃自行遷移,我很想知道進展如何。如果您遇到我未提及的問題,或找到了更簡潔的解決方案,歡迎隨時在X/Twitter上與我聯絡。敬請期待更多類似文章。
原文出處:https://dev.to/harshil1712/migrating-from-astro-5-to-astro-6-a-real-world-breakdown-2d0c