Astro 和 SvelteKit 是近年增长最快的两个现代前端框架:Astro 以"零 JS 默认"的 Islands 架构统治内容站点,SvelteKit 以极致编译时优化和最小运行时成为高交互应用的利器。两者都原生支持 Vercel 部署——Astro 有官方 @astrojs/vercel 适配器,SvelteKit 有 @sveltejs/adapter-vercel。本文分别讲解两个框架在 Vercel 上的完整部署流程与优化策略。
第一部分:Astro 在 Vercel 上部署
一、Astro 架构特点与 Vercel 适配
Astro 的核心理念:
- 默认零 JS:页面初始加载时,HTML 是纯静态的,没有客户端 JavaScript
- Islands 架构:只有在需要交互的地方,才注入对应组件的 JS(React、Vue、Svelte、Solid 等都可以)
- 内容优先:博客、文档、电商展示页、营销页的最佳选择
- 混合渲染:支持
static(SSG)、server(SSR)、hybrid(混合)三种输出模式
Astro 在 Vercel 上的部署适配:
| 输出模式 | Vercel 行为 | 适用场景 |
|---|---|---|
static | 纯静态 HTML/CSS/JS,上传到 Vercel CDN | 博客、文档、营销页 |
server | SSR 渲染,每个请求通过 Vercel Serverless Function | 登录态页面、实时数据 |
hybrid | 大部分静态,部分动态路由走 SSR | 内容站带少量动态内容 |
二、项目初始化与配置
2.1 创建 Astro 项目
# 使用官方模板
npm create astro@latest my-astro-site
# 选择:
# - Template: 推荐 "Astro Basics" 或 "Blog"
# - TypeScript: 是
# - Install dependencies: 是
# - Initialize git: 是
cd my-astro-site
npm install
2.2 安装 Vercel 适配器
# Astro 3.0+ 推荐安装
npm install -D @astrojs/vercel
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';
export default defineConfig({
output: 'static', // 或 'server' / 'hybrid'
adapter: vercel(),
});
适配器会自动处理:
- 静态文件上传到 Vercel CDN
- SSR 路由生成
functions/目录并打包为 Vercel Serverless Functions - 图片优化对接 Vercel Image Optimization API
2.3 三种输出模式详解
模式一:Static(静态生成)
// astro.config.mjs
export default defineConfig({
output: 'static',
adapter: vercel(),
});
构建时生成纯 HTML 文件:
dist/
├── index.html
├── about/
│ └── index.html
├── blog/
│ ├── hello-world/
│ │ └── index.html
│ └── index.html
- 最快:Vercel CDN 直接服务 HTML,无 Serverless 冷启动
- 最便宜:不产生 Functions 调用费用
- 最适合:博客、文档、营销站
模式二:Server(服务端渲染)
// astro.config.mjs
export default defineConfig({
output: 'server',
adapter: vercel({
edgeMiddleware: false, // SSR 用 Node runtime
functionPerRoute: true, // 每个路由一个 Function(推荐生产环境)
}),
});
每个路由变成 Serverless Function:
.vercel/output/functions/
├── about.func/
│ └── index.js
├── blog.hello-world.func/
│ └── index.js
└── index.func/
└── index.js
- 可以读取 Cookie / Session / 请求头
- 每次请求都通过 Vercel Function(有冷启动)
- 适合登录页面、管理后台
模式三:Hybrid(混合)
// astro.config.mjs
export default defineConfig({
output: 'hybrid',
adapter: vercel(),
});
---
// src/pages/about.astro
// 默认静态生成
export const prerender = true;
---
<html><body><h1>About Us</h1></body></html>
---
// src/pages/dashboard.astro
// 强制 SSR
export const prerender = false;
const user = Astro.locals.user; // 从中间件获取
---
<html><body><h1>Welcome, {user.name}</h1></body></html>
- 兼顾速度和动态能力
- 静态页面直接 CDN,动态页面 Functions
- 推荐大多数 Astro 项目使用
三、内容管理:Markdown + CMS
Astro 原生支持 Markdown / MDX:
npm install -D @astrojs/mdx
// astro.config.mjs
import mdx from '@astrojs/mdx';
export default defineConfig({
integrations: [mdx()],
});
目录结构:
src/
├── content/
│ └── posts/
│ ├── hello-world.md
│ └── astro-guide.mdx
├── pages/
│ └── blog/
│ └── [slug].astro
Astro Content Collections(类型安全的内容管理):
// src/content/config.ts
import { defineCollection, z } from 'astro:content';
const posts = defineCollection({
schema: z.object({
title: z.string(),
date: z.date(),
tags: z.array(z.string()),
draft: z.boolean().default(false),
}),
});
export const collections = { posts };
---
// src/pages/blog/[slug].astro
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('posts');
return posts.map(post => ({
params: { slug: post.slug },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await post.render();
---
<article>
<h1>{post.data.title}</h1>
<time>{post.data.date.toDateString()}</time>
<Content />
</article>
四、图片优化
Astro 的 <Image> 组件在 Vercel 上自动对接 Vercel Image Optimization:
---
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---
<Image
src={heroImage}
alt="Hero"
widths={[320, 640, 1280]}
sizes="(max-width: 640px) 100vw, 50vw"
quality={80}
/>
<!-- 外部图片 -->
<Image
src="https://cdn.example.com/photo.jpg"
alt="Photo"
width={800}
height={600}
inferSize
/>
Vercel Image Optimization 会自动:
- 生成多尺寸 WebP/AVIF
- 按
sizes属性加载合适尺寸 - CDN 缓存优化后的图片
五、部署验证
git push origin main
Vercel 自动检测 Astro 项目并部署。验证命令:
# 首页(应极速加载,纯 HTML)
curl -w "@curl-format.txt" https://my-astro-site.vercel.app/
# 博客文章页
curl https://my-astro-site.vercel.app/blog/hello-world
# 检查 TTFB
curl -s -o /dev/null -w "%{time_starttransfer}" https://my-astro-site.vercel.app/
# 期望值:< 200ms(静态页面 Cloudflare 加速后)
性能基准(Astro 静态页面 + Vercel + Cloudflare Proxy):
- TTFB: 50-150ms
- LCP: 800ms-1.5s(无 JS 干扰)
- JS Bundle: 0-5KB(仅 Islands 注入的交互组件)
第二部分:SvelteKit 在 Vercel 上部署
一、SvelteKit 架构特点
SvelteKit 的核心优势:
- 编译时优化:框架代码在构建时编译为高效的原生 JS,运行时极小
- 文件路由:
src/routes/+page.svelte自动成为页面路由 - 多输出适配:同一套代码可以打包为 SSG、SSR、SPA、Edge Functions 等
- 原生支持 Edge:SvelteKit 有第一方的
@sveltejs/adapter-vercel
二、项目初始化与 Vercel 适配
# 创建 SvelteKit 项目
npm create svelte@latest my-sveltekit-app
# 选择:
# - Skeleton project
# - TypeScript: Yes
# - ESLint + Prettier: Yes
cd my-sveltekit-app
npm install
# 安装 Vercel 适配器
npm install -D @sveltejs/adapter-vercel
// svelte.config.js
import adapter from '@sveltejs/adapter-vercel';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: vitePreprocess(),
kit: {
adapter: adapter({
// Edge Functions 模式
runtime: 'edge',
// 或 Node.js 模式:runtime: 'nodejs20.x'
}),
},
};
export default config;
三、Edge Runtime vs Node Runtime
SvelteKit @sveltejs/adapter-vercel 支持两种运行时:
| 维度 | Edge Runtime | Node.js Runtime |
|---|---|---|
| runtime 配置 | runtime: 'edge' | runtime: 'nodejs20.x' |
| 执行环境 | V8 Isolate(轻量) | 完整 Node.js |
| 冷启动 | 极快(< 5ms) | 中等(50-200ms) |
| Node API | 受限(无 fs、少量 npm 包) | 完整 Node.js 生态 |
| 数据库直连 | ❌ 不支持(Prisma 需 Data Proxy) | ✅ 支持(Prisma/Postgres) |
| Bundle 大小 | 极小 | 较大 |
| 适用场景 | 轻 API、中间件、A/B 测试、简单 SSR | 重 API、数据库交互、复杂后端逻辑 |
建议:
- 纯内容/展示型 SvelteKit 项目 → Edge Runtime(最快最省)
- 需要数据库 + 复杂业务逻辑 → Node.js Runtime
- 混合:API 路由用 Node,页面渲染用 Edge(
edge = false特定路由)
四、路由与数据获取
4.1 页面路由
<!-- src/routes/+page.svelte -->
<script>
/** @type {import('./$types').PageData} */
export let data;
</script>
<h1>{data.title}</h1>
<p>{data.description}</p>
// src/routes/+page.server.ts(服务端数据获取)
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async () => {
// 这里可以查数据库或调用 API
return {
title: 'Welcome to SvelteKit',
description: 'Deployed on Vercel',
};
};
4.2 API 路由
// src/routes/api/users/+server.ts
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
export const GET: RequestHandler = async () => {
// const users = await db.user.findMany();
const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
return json(users);
};
export const POST: RequestHandler = async ({ request }) => {
const body = await request.json();
// const newUser = await db.user.create({ data: body });
return json({ created: true }, { status: 201 });
};
4.3 服务器钩子(Hooks)
// src/hooks.server.ts
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
// 认证检查
const token = event.cookies.get('session');
if (!token && event.url.pathname.startsWith('/dashboard')) {
return new Response('Unauthorized', { status: 401 });
}
const response = await resolve(event);
// 添加安全头
response.headers.set('X-Frame-Options', 'DENY');
return response;
};
4.4 环境变量
# .env
DATABASE_URL="postgresql://user:pass@host/db"
PUBLIC_API_BASE="https://api.example.com"
SECRET_KEY="your-secret"
// SvelteKit 环境变量规则:
// - PUBLIC_ 前缀:客户端 + 服务端都可访问
// - 无前缀:仅服务端
import { env } from '$env/dynamic/private'; // 服务端动态
import { PUBLIC_API_BASE } from '$env/static/public'; // 客户端静态
五、Edge 模式下的限制与解法
5.1 无法直接连接 Postgres
Edge Runtime 没有 TCP Socket,Prisma 直接连接会报错。解法:
npm install @prisma/client @prisma/extension-accelerate
// src/lib/db.ts(Edge-compatible)
import { PrismaClient } from '@prisma/client';
import { withAccelerate } from '@prisma/extension-accelerate';
const prisma = new PrismaClient().$extends(withAccelerate());
export { prisma };
使用 Prisma Data Proxy / Accelerate 通过 HTTP 连接数据库。
5.2 文件系统访问受限
Edge Runtime 没有 fs,不能读写本地文件:
// ❌ Edge 下不可用
import fs from 'fs';
fs.readFileSync('./data.json');
// ✅ 改用 fetch 从外部加载
const data = await fetch('https://cdn.example.com/data.json').then(r => r.json());
5.3 npm 包兼容性
部分原生 C++ 扩展的 npm 包(如 sharp 图片处理、bcrypt 加密)在 Edge 下不可用。改用:
| 不可用 | 替代方案 |
|---|---|
| sharp | @vercel/image(托管)或 Cloudinary |
| bcrypt | bcryptjs(纯 JS 实现) |
| sqlite3 | better-sqlite3(Node only)或 Turso(Edge SQLite) |
六、部署验证
git push origin main
# 测试首页 SSR
curl https://my-sveltekit-app.vercel.app
# 测试 API
curl https://my-sveltekit-app.vercel.app/api/users
# 测试 POST
curl -X POST https://my-sveltekit-app.vercel.app/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Alice"}'
七、Astro vs SvelteKit:在 Vercel 上怎么选?
| 维度 | Astro | SvelteKit |
|---|---|---|
| 静态内容性能 | ⭐⭐⭐⭐⭐(零 JS 默认) | ⭐⭐⭐⭐(编译优化,但默认有 hydration) |
| 交互应用 | ⭐⭐⭐(Islands 架构够用) | ⭐⭐⭐⭐⭐(天生为富交互设计) |
| SSR 灵活性 | ⭐⭐⭐(hybrid 模式够用) | ⭐⭐⭐⭐⭐(Server/SPA/Prerender/Edge 任意切换) |
| 学习曲线 | ⭐⭐⭐⭐⭐(接近纯 HTML) | ⭐⭐⭐⭐(概念清晰但需要时间) |
| Vercel 适配 | ⭐⭐⭐⭐(官方适配器) | ⭐⭐⭐⭐⭐(官方第一方适配器 + Edge 支持) |
| 生态组件 | React/Vue/Svelte 全兼容 | Svelte 生态为主 |
| 最佳场景 | 博客、文档、营销、内容站 | SaaS、Dashboard、交互应用 |
一句话决策:
- 内容为王(文字多、图片多、交互少)→ Astro
- 交互为王(表单、动画、状态管理多)→ SvelteKit
- Vercel 两者都完美支持,选框架看项目类型。
常见问题(FAQ)
Astro 的 Islands 在 Vercel 上是怎么工作的?
Astro 构建时会把 Islands 组件(如 React、Svelte、Vue 组件)编译为独立的 JS chunk。页面 HTML 是纯静态的,只有当 Islands 组件进入视口时,对应的 JS chunk 才会懒加载执行。Vercel CDN 负责分发这些 chunk,和分发普通 JS 文件一样简单。
SvelteKit Edge 模式下能跑服务端渲染吗?
能。SvelteKit @sveltejs/adapter-vercel 的 runtime: 'edge' 模式会让整站(页面渲染 + API 路由)都跑在 Vercel Edge Functions 上。SSR 的 load 函数在 Edge Runtime 中执行,但受限于 Edge 的 API 子集(如不能直接连 Postgres)。
Astro Hybrid 模式的 prerender = false 在 Vercel 上费用高吗?
不高。prerender = false 的页面走 Serverless Functions,但请求量通常不大(管理后台、用户中心)。纯静态页面(prerender = true)直接走 CDN,费用为 0。对于博客类项目,通常 95% 的请求都是静态页面。
SvelteKit 的 +page.server.ts 和 +page.ts 在部署后有什么区别?
+page.server.ts:只在服务端执行(SSR 时运行一次),不会暴露到客户端,适合查数据库+page.ts:在服务端和客户端都会执行(客户端 hydration 后再执行一次),适合调用外部 API- 在 Vercel 上,
+page.server.ts的代码打包在 Functions 中,+page.ts的代码会出现在客户端 bundle 中
相关阅读
- Vercel 详解:前端与 AI 应用的一站式云平台
- Vercel 部署 Nuxt.js (Vue) 实战
- Vercel 国内访问优化指南
- Vercel Edge Functions 深度指南
- Vercel 专题导航
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。