Vercel 部署 Astro 完整教學|2025 內容網站最佳選擇
Astro 是 2025 年最受歡迎的內容網站框架之一。
零 JavaScript 預設、極快的載入速度、支援多框架整合。
部署到 Vercel,讓你的內容網站飛快。
這篇文章教你如何把 Astro 網站部署到 Vercel。
為什麼選擇 Astro + Vercel?
Astro 的優勢
| 優勢 | 說明 |
|---|---|
| 零 JS 預設 | 只在需要時載入 JavaScript |
| Islands 架構 | 部分互動、部分靜態 |
| 框架不限 | 可以用 React、Vue、Svelte |
| 內容優先 | 為內容網站而生 |
| 超快效能 | Lighthouse 滿分 |
Vercel 的加成
- 全球 CDN 加速
- 自動 HTTPS
- Preview 部署
- 免費額度充足
專案準備
Astro 專案結構
my-astro-site/
├── public/
│ └── favicon.svg
├── src/
│ ├── components/
│ ├── layouts/
│ │ └── Layout.astro
│ ├── pages/
│ │ ├── index.astro
│ │ └── about.astro
│ └── content/
│ └── blog/
│ └── first-post.md
├── astro.config.mjs
└── package.json
package.json
{
"name": "my-astro-site",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview"
},
"dependencies": {
"astro": "^4.5.0"
}
}
本機測試
# 執行 build
npm run build
# 預覽
npm run preview
輸出模式選擇
Static(預設)
所有頁面在 build 時生成。
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
output: 'static', // 預設值
});
適合: 部落格、文件網站、作品集
Hybrid
部分靜態、部分動態。
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
output: 'hybrid',
adapter: vercel(),
});
---
// 預設靜態,可以選擇性使用 SSR
export const prerender = false; // 這個頁面使用 SSR
---
Server(SSR)
所有頁面都是動態渲染。
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
output: 'server',
adapter: vercel(),
});
安裝 Vercel Adapter
安裝
npm install @astrojs/vercel
設定 Adapter
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
output: 'server', // 或 'hybrid'
adapter: vercel(),
});
Adapter 選項
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
output: 'server',
adapter: vercel({
// 啟用 ISR
isr: true,
// 設定 function 區域
functionPerRoute: false,
// 排除靜態資源
excludeFiles: ['./src/some-file.js'],
}),
});
部署到 Vercel
方法一:從 GitHub 部署
步驟一:推送到 GitHub
git init
git add .
git commit -m "Initial commit"
gh repo create my-astro-site --public --source=. --push
步驟二:連接 Vercel
- 前往 vercel.com
- 點擊 Add New → Project
- 選擇 Repository
- 點擊 Import
步驟三:確認設定
Vercel 自動偵測 Astro:
| 設定項目 | 值 |
|---|---|
| Framework | Astro |
| Build Command | npm run build |
| Output Directory | dist |
方法二:Vercel CLI
npm install -g vercel
vercel login
vercel
環境變數
在 Astro 使用
公開變數(會暴露給前端):
# .env
PUBLIC_API_URL=https://api.example.com
---
// 伺服器端
const apiUrl = import.meta.env.PUBLIC_API_URL;
---
<script>
// 客戶端
const apiUrl = import.meta.env.PUBLIC_API_URL;
</script>
私密變數(只在伺服器端):
# .env
API_SECRET=your-secret-key
---
// 只在伺服器端可用
const secret = import.meta.env.API_SECRET;
---
在 Vercel 設定
- 專案 Settings → Environment Variables
- 新增變數
Name: PUBLIC_API_URL
Value: https://api.example.com
內容集合
設定內容集合
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
date: z.date(),
description: z.string(),
tags: z.array(z.string()).optional(),
}),
});
export const collections = { blog };
建立內容
---
title: "我的第一篇文章"
date: 2025-01-15
description: "這是文章描述"
tags: ["astro", "vercel"]
---
# 我的第一篇文章
這是內容...
顯示內容
---
// src/pages/blog/[slug].astro
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map(post => ({
params: { slug: post.slug },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await post.render();
---
<Layout title={post.data.title}>
<h1>{post.data.title}</h1>
<time>{post.data.date.toLocaleDateString()}</time>
<Content />
</Layout>
Islands 架構
什麼是 Islands?
Astro 使用 Islands 架構:
- 頁面大部分是靜態 HTML
- 互動元件是「島嶼」
- 只在需要時載入 JavaScript
使用 React 元件
npm install @astrojs/react react react-dom
// astro.config.mjs
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
export default defineConfig({
integrations: [react()],
});
---
import Counter from '../components/Counter.jsx';
---
<Counter client:load />
客戶端指令
| 指令 | 說明 |
|---|---|
client:load |
頁面載入後立即載入 |
client:idle |
瀏覽器閒置時載入 |
client:visible |
元件進入視窗時載入 |
client:media |
符合媒體查詢時載入 |
client:only |
只在客戶端渲染 |
<!-- 延遲載入,提升效能 -->
<HeavyChart client:visible />
<!-- 手機才載入 -->
<MobileMenu client:media="(max-width: 768px)" />
API 端點
建立 API 端點
// src/pages/api/hello.ts
import type { APIRoute } from 'astro';
export const GET: APIRoute = async () => {
return new Response(
JSON.stringify({ message: 'Hello!' }),
{
status: 200,
headers: { 'Content-Type': 'application/json' },
}
);
};
POST 請求
// src/pages/api/contact.ts
import type { APIRoute } from 'astro';
export const POST: APIRoute = async ({ request }) => {
const data = await request.json();
// 處理表單...
return new Response(
JSON.stringify({ success: true }),
{ status: 200 }
);
};
動態路由
// src/pages/api/users/[id].ts
import type { APIRoute } from 'astro';
export const GET: APIRoute = async ({ params }) => {
const { id } = params;
return new Response(
JSON.stringify({ userId: id }),
{ status: 200 }
);
};
效能優化
圖片優化
---
import { Image } from 'astro:assets';
import myImage from '../assets/photo.jpg';
---
<Image
src={myImage}
alt="描述"
width={800}
height={600}
format="webp"
loading="lazy"
/>
使用 View Transitions
---
// src/layouts/Layout.astro
import { ViewTransitions } from 'astro:transitions';
---
<html>
<head>
<ViewTransitions />
</head>
<body>
<slot />
</body>
</html>
預載入
---
import { prefetch } from 'astro:prefetch';
---
<a href="/about" data-astro-prefetch>關於我們</a>
設定快取
// vercel.json
{
"headers": [
{
"source": "/_astro/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
}
]
}
常見問題排解
問題一:Build 失敗
錯誤訊息:
Cannot use import statement outside a module
解決方法:
確認 astro.config.mjs 使用 .mjs 副檔名。
問題二:SSR 頁面 404
可能原因: 沒有安裝 Adapter
解決方法:
npm install @astrojs/vercel
// astro.config.mjs
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
output: 'server',
adapter: vercel(),
});
問題三:環境變數讀不到
檢查項目:
- 公開變數是否有
PUBLIC_前綴 - 是否重新部署了
- Vercel 是否有設定
問題四:React 元件不渲染
可能原因: 忘記加 client: 指令
<!-- ❌ 不會互動 -->
<Counter />
<!-- ✅ 會互動 -->
<Counter client:load />
問題五:內容集合錯誤
錯誤訊息:
Content collections must be in src/content
解決方法:
確認目錄結構:
src/
└── content/
├── config.ts ← 必須有這個
└── blog/
└── post.md
Sitemap 和 SEO
安裝 Sitemap
npm install @astrojs/sitemap
// astro.config.mjs
import sitemap from '@astrojs/sitemap';
export default defineConfig({
site: 'https://example.com',
integrations: [sitemap()],
});
設定 SEO
---
// src/components/SEO.astro
const { title, description, image } = Astro.props;
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
---
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonicalURL} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={image} />
部署檢查清單
部署前
- [ ]
npm run build成功 - [ ] 本機預覽正常
- [ ] 環境變數已設定
- [ ] Adapter 正確安裝(如果用 SSR)
- [ ] 內容集合沒有錯誤
部署後
- [ ] 頁面正常顯示
- [ ] 互動元件正常運作
- [ ] API 端點可訪問
- [ ] 圖片載入正常
- [ ] SEO meta 正確
常見問題 FAQ
Q1:Static 和 SSR 怎麼選?
| 選擇 Static | 選擇 SSR |
|---|---|
| 部落格 | 動態內容 |
| 文件網站 | 需要認證 |
| 作品集 | 即時資料 |
| 內容不常更新 | 個人化內容 |
大多數情況,Static 就夠了。
Q2:Astro 適合什麼專案?
- 部落格和內容網站
- 行銷頁面
- 文件網站
- 作品集
不適合:
- 高度互動的應用
- 即時應用
Q3:可以混用 React 和 Vue 嗎?
可以!這是 Astro 的特色:
npm install @astrojs/react @astrojs/vue
---
import ReactComponent from './ReactComponent.jsx';
import VueComponent from './VueComponent.vue';
---
<ReactComponent client:load />
<VueComponent client:load />
Q4:Astro 部署免費嗎?
是的,Vercel 免費方案足夠大多數 Astro 網站。
Q5:如何更新已發布的內容?
重新推送到 GitHub,Vercel 自動重新部署。
或使用 Vercel CLI:
vercel --prod
Vercel 部署失敗?
Build Error、環境變數、自訂網域,我們幫你快速排除問題。