← 返回内容与观点
2026-06-14 · 部署 · Next.js · 阿里云 ESA · 静态导出
把 Next.js 静态导出项目部署到阿里云 ESA Pages
本站(Orion AI Lab 官网)就是用这套配置部署的:Next.js 15 App Router + Tailwind CSS v4, 构建产物是纯静态文件,托管在阿里云 ESA(Edge Security Acceleration)Pages 上, 每次 push 代码自动构建发布。这篇文章记录这套方案的关键配置点,方便以后复用,也方便有同样需求的朋友参考。
1. 为什么选择 output: "export"
ESA Pages 本质上是一个静态资源托管 + CDN 加速服务,不提供 Node.js 运行时。
所以项目里 next.config.ts 必须开启静态导出:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "export",
trailingSlash: true,
images: {
unoptimized: true,
},
};
export default nextConfig;三个配置项分别对应:
output: "export":next build产物变成纯 HTML/CSS/JS 静态文件,输出到./out目录,不依赖服务器运行时。trailingSlash: true:所有路由生成xxx/index.html而不是xxx.html,静态服务器按目录访问更稳,URL 也统一带斜杠。images.unoptimized: true:关闭next/image的服务端按需优化(这需要运行时),图片原样输出。
2. ESA Pages 怎么读这个项目
ESA Pages 的 Next.js 模板里有一个 esa.jsonc,描述了构建产物在哪、404 怎么处理:
{
"name": "nextjs-template",
"installCommand": "pnpm install",
"assets": {
"directory": "./out",
"notFoundStrategy": "404Page"
}
}整体流程很简单:每次 push 到主分支,ESA 会执行 pnpm install → pnpm build(即 next build),
然后把 ./out 目录整体作为静态站点发布,访问不到的路径走 404Page 策略。
没有单独的"部署"步骤——提交即上线,所以本地验证 pnpm build 是否成功,比在很多项目里更重要。
3. 静态导出对 Next.js 功能的限制
output: "export" 会在构建时直接报错提示哪些功能不兼容,主要踩坑点:
- 不能用 API Routes / Route Handlers 里的动态逻辑、Middleware、ISR:这些都需要服务器在请求时运行代码。
- 动态路由必须配
generateStaticParams:比如本站的/projects/[slug],需要在构建时列出所有 slug, 让 Next 把每个值都预渲染成一个静态页面:
export function generateStaticParams() {
return projects.map((project) => ({ slug: project.slug }));
}- 图片必须
unoptimized:否则next/image会尝试请求一个不存在的图片优化接口。
把这些限制摸清楚之后,其实日常开发体验和普通 Next.js 项目几乎没区别,只是多了一道 "这个功能是不是依赖运行时"的判断。
4. trailingSlash 与 SEO canonical 的小细节
开启 trailingSlash: true 后,所有内部链接和 sitemap.ts 里的 URL 都要带上结尾斜杠,
否则会出现 /blog 和 /blog/ 两个版本同时被搜索引擎收录的重复内容问题。
做法是统一约定:
- 内部
<Link href="/blog">这种不带斜杠的写法没问题(Next 会处理跳转), - 但
sitemap.ts、generateMetadata里的alternates.canonical、openGraph.url等 要显式写成带斜杠的完整地址,保证搜索引擎抓到的规范地址和实际渲染出的 HTML 路径一致。
5. 上线前自查清单
每次改动比较大的时候,我会按这个顺序自查一遍:
pnpm lint—— 先过一遍 ESLint,类型和明显错误能在这一步暴露。pnpm build—— 本地完整跑一次静态导出,确认没有运行时特性被误用。- 检查
./out目录结构是否符合预期(动态路由是否都生成了对应文件夹)。 - 抽查
sitemap.xml、robots.txt是否包含新增页面。 - 确认新页面的
generateMetadata/metadata里 title、description、OG 图、canonical 都补全。
因为 ESA 是 push 即部署,这五步基本就是"上线前最后一道闸",比平时多花两三分钟, 能避免直接把构建失败或者 SEO 信息缺失的版本发布到生产环境。
后续如果遇到 ESA 构建环境的其他坑(比如 Turbopack 对某些库的兼容性问题),我会继续在这个系列里更新。