如何创建 Next.js 应用程序的静态导出
Next.js 支持从静态站点或单页应用程序(SPA)开始,然后可以选择性地升级到使用需要服务器的功能。
当运行 next build
时,Next.js 为每个路由生成一个 HTML 文件。通过将严格的 SPA 分解为单独的 HTML 文件,Next.js 可以避免在客户端加载不必要的 JavaScript 代码,减少包大小并实现更快的页面加载。
由于 Next.js 支持这种静态导出,它可以部署和托管在任何可以提供 HTML/CSS/JS 静态资源的 Web 服务器上。
配置
要启用静态导出,请在 next.config.js
中更改输出模式:
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
output: 'export',
// 可选:更改链接 `/me` -> `/me/` 并生成 `/me.html` -> `/me/index.html`
// trailingSlash: true,
// 可选:防止自动 `/me` -> `/me/`,而是保留 `href`
// skipTrailingSlashRedirect: true,
// 可选:更改输出目录 `out` -> `dist`
// distDir: 'dist',
}
module.exports = nextConfig
运行 next build
后,Next.js 将创建一个包含应用程序 HTML/CSS/JS 资源的 out
文件夹。
你可以利用 getStaticProps
和 getStaticPaths
为 pages
目录中的每个页面(或动态路由的更多页面)生成 HTML 文件。
支持的功能
Next.js 的核心设计支持静态导出。
服务端组件
当你运行 next build
生成静态导出时,app
目录中使用的服务端组件将在构建期间运行,类似于传统的静态站点生成。
生成的组件将被渲染为初始页面加载的静态 HTML 和路由间客户端导航的静态载荷。使用静态导出时,你的服务端组件不需要任何更改,除非它们使用动态服务器函数。
- TypeScript
export default async function Page() {
// 这个 fetch 将在 `next build` 期间在服务器上运行
const res = await fetch('https://api.example.com/...')
const data = await res.json()
return <main>...</main>
}
客户端组件
如果你想在客户端执行数据获取,可以使用带有 SWR 的客户端组件来记忆化请求。
- TypeScript
- JavaScript
'use client'
import useSWR from 'swr'
const fetcher = (url: string) => fetch(url).then((r) => r.json())
export default function Page() {
const { data, error } = useSWR(
`https://jsonplaceholder.typicode.com/posts/1`,
fetcher
)
if (error) return '加载失败'
if (!data) return '加载中...'
return data.title
}
'use client'
import useSWR from 'swr'
const fetcher = (url) => fetch(url).then((r) => r.json())
export default function Page() {
const { data, error } = useSWR(
`https://jsonplaceholder.typicode.com/posts/1`,
fetcher
)
if (error) return '加载失败'
if (!data) return '加载中...'
return data.title
}
部署
静态导出后,你可以将 out
文件夹部署到任何静态托管服务。
使用 Vercel
如果你使用 Vercel,静态导出会自动处理。你只需要在 next.config.js
中设置 output: 'export'
,Vercel 就会检测到这是一个静态导出并相应地处理它。
手动部署
你可以将 out
文件夹上传到任何静态托管服务,例如:
本地测试
要本地测试静态导出,你可以使用任何静态文件服务器:
npx serve out
不支持的功能
静态导出不支持需要服务器的功能。以下功能在静态导出中不可用:
动态服务器函数
以下函数在静态导出中不可用,因为它们需要服务器:
路由处理器
路由处理器在静态导出中不可用,因为它们需要服务器。
中间件
中间件在静态导出中不可用,因为它需要服务器。
动态路由
动态路由需要 generateStaticParams
来生成静态页面。
图像优化
图像优化在静态导出中不可用,因为它需要服务器。
增量静态再生成
增量静态再生成在静态导出中不可用,因为它需要服务器。
图像
当使用静态导出时,Next.js 的 <Image>
组件 需要配置为使用外部图像优化服务,或者你可以使用 unoptimized
属性来跳过图像优化。
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
images: {
unoptimized: true,
},
}
module.exports = nextConfig
基础路径
如果你的应用程序不是部署在域名的根目录下,你需要设置 basePath
。
例如,如果你的应用程序部署在 https://example.com/my-app
,你需要在 next.config.js
中设置:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
basePath: '/my-app',
}
module.exports = nextConfig
导出路径映射
你可以使用 exportPathMap
来自定义导出的路径:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
exportPathMap: async function (
defaultPathMap,
{ dev, dir, outDir, distDir, buildId }
) {
return {
'/': { page: '/' },
'/about': { page: '/about' },
'/contact': { page: '/contact' },
}
},
}
module.exports = nextConfig
注意事项
- 静态导出不支持需要服务器的功能
- 所有数据获取必须在构建时完成
- 客户端导航仍然可以工作
- 你可以稍后升级到使用需要服务器的功能