Skip to main content

静态导出

Next.js 可以作为静态站点或单页应用 (SPA) 启动,然后可以选择升级以使用需要服务器的功能。

¥Next.js enables starting as a static site or Single-Page Application (SPA), then later optionally upgrading to use features that require a server.

运行 next build 时,Next.js 为每个路由生成一个 HTML 文件。通过将严格的 SPA 分解为单独的 HTML 文件,Next.js 可以避免在客户端加载不必要的 JavaScript 代码,从而减少包大小并实现更快的页面加载。

¥When running next build, Next.js generates an HTML file per route. By breaking a strict SPA into individual HTML files, Next.js can avoid loading unnecessary JavaScript code on the client-side, reducing the bundle size and enabling faster page loads.

由于 Next.js 支持这种静态导出,因此它可以部署和托管在任何可以提供 HTML/CSS/JS 静态资源的 Web 服务器上。

¥Since Next.js supports this static export, it can be deployed and hosted on any web server that can serve HTML/CSS/JS static assets.

配置

¥Configuration

要启用静态导出,请更改 next.config.js 内的输出模式:

¥To enable a static export, change the output mode inside next.config.js:

/**

* @type {import('next').NextConfig}
*/
const nextConfig = {
output: 'export',

// Optional: Change links `/me` -> `/me/` and emit `/me.html` -> `/me/index.html`
// trailingSlash: true,

// Optional: Prevent automatic `/me` -> `/me/`, instead preserve `href`
// skipTrailingSlashRedirect: true,

// Optional: Change the output directory `out` -> `dist`
// distDir: 'dist',
}

module.exports = nextConfig

运行 next build 后,Next.js 将生成一个 out 文件夹,其中包含应用的 HTML/CSS/JS 资源。

¥After running next build, Next.js will produce an out folder which contains the HTML/CSS/JS assets for your application.

支持的功能

¥Supported Features

Next.js 的核心被设计为支持静态导出。

¥The core of Next.js has been designed to support static exports.

服务器组件

¥Server Components

当你运行 next build 生成静态导出时,app 目录内使用的服务器组件将在构建期间运行,类似于传统的静态站点生成。

¥When you run next build to generate a static export, Server Components consumed inside the app directory will run during the build, similar to traditional static-site generation.

生成的组件将渲染为用于初始页面加载的静态 HTML 和用于客户端在路由之间导航的静态负载。使用静态导出时,不需要对服务器组件进行任何更改,除非它们消耗 动态服务器功能

¥The resulting component will be rendered into static HTML for the initial page load and a static payload for client navigation between routes. No changes are required for your Server Components when using the static export, unless they consume dynamic server functions.

export default async function Page() {
// This fetch will run on the server during `next build`
const res = await fetch('https://api.example.com/...')
const data = await res.json()

return <main>...</main>
}

客户端组件

¥Client Components

如果要在客户端执行数据获取,可以使用带有 SWR 的客户端组件来存储请求。

¥If you want to perform data fetching on the client, you can use a Client Component with SWR to memoize requests.

'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 'Failed to load'
if (!data) return 'Loading...'

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 'Failed to load'
if (!data) return 'Loading...'

return data.title
}

由于路由转换发生在客户端,因此其行为类似于传统的 SPA。例如,以下索引路由允许你导航到客户端上的不同帖子:

¥Since route transitions happen client-side, this behaves like a traditional SPA. For example, the following index route allows you to navigate to different posts on the client:

import Link from 'next/link'

export default function Page() {
return (
<>
<h1>Index Page</h1>
<hr />
<ul>
<li>
<Link href="/post/1">Post 1</Link>
</li>
<li>
<Link href="/post/2">Post 2</Link>
</li>
</ul>
</>
)
}
import Link from 'next/link'

export default function Page() {
return (
<>
<h1>Index Page</h1>
<p>
<Link href="/other">Other Page</Link>
</p>
</>
)
}

图片优化

¥Image Optimization

通过在 next.config.js 中定义自定义图片加载器,可以将 图片优化next/image 与静态导出一起使用。例如,你可以使用 Cloudinary 等服务优化图片:

¥Image Optimization through next/image can be used with a static export by defining a custom image loader in next.config.js. For example, you can optimize images with a service like Cloudinary:

/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
images: {
loader: 'custom',
loaderFile: './my-loader.ts',
},
}

module.exports = nextConfig

此自定义加载程序将定义如何从远程源获取图片。例如,以下加载器将构造 Cloudinary 的 URL:

¥This custom loader will define how to fetch images from a remote source. For example, the following loader will construct the URL for Cloudinary:

export default function cloudinaryLoader({
src,
width,
quality,
}: {
src: string
width: number
quality?: number
}) {
const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`]
return `https://res.cloudinary.com/demo/image/upload/${params.join(
','
)}${src}`
}
export default function cloudinaryLoader({ src, width, quality }) {
const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`]
return `https://res.cloudinary.com/demo/image/upload/${params.join(
','
)}${src}`
}

然后,你可以在应用中使用 next/image,在 Cloudinary 中定义图片的相对路径:

¥You can then use next/image in your application, defining relative paths to the image in Cloudinary:

import Image from 'next/image'

export default function Page() {
return <Image alt="turtles" src="/turtles.jpg" width={300} height={300} />
}
import Image from 'next/image'

export default function Page() {
return <Image alt="turtles" src="/turtles.jpg" width={300} height={300} />
}

路由处理程序

¥Route Handlers

运行 next build 时,路由处理程序将渲染静态响应。仅支持 GET HTTP 谓词。这可用于从缓存或未缓存的数据生成静态 HTML、JSON、TXT 或其他文件。例如:

¥Route Handlers will render a static response when running next build. Only the GET HTTP verb is supported. This can be used to generate static HTML, JSON, TXT, or other files from cached or uncached data. For example:

export async function GET() {
return Response.json({ name: 'Lee' })
}
export async function GET() {
return Response.json({ name: 'Lee' })
}

上述文件 app/data.json/route.ts 将在 next build 期间渲染为静态文件,生成包含 { name: 'Lee' }data.json

¥The above file app/data.json/route.ts will render to a static file during next build, producing data.json containing { name: 'Lee' }.

如果你需要从传入请求中读取动态值,则不能使用静态导出。

¥If you need to read dynamic values from the incoming request, you cannot use a static export.

浏览器 API

¥Browser APIs

客户端组件在 next build 期间预渲染为 HTML。由于 网络 APIwindowlocalStoragenavigator 等在服务器上不可用,因此只有在浏览器中运行时才需要安全地访问这些 API。例如:

¥Client Components are pre-rendered to HTML during next build. Because Web APIs like window, localStorage, and navigator are not available on the server, you need to safely access these APIs only when running in the browser. For example:

'use client';

import { useEffect } from 'react';

export default function ClientComponent() {
useEffect(() => {
// You now have access to `window`
console.log(window.innerHeight);
}, [])

return ...;
}

不支持的功能

¥Unsupported Features

不支持需要 Node.js 服务器的功能,或在构建过程中无法计算的动态逻辑:

¥Features that require a Node.js server, or dynamic logic that cannot be computed during the build process, are not supported:

尝试对 next dev 使用任何这些功能都会导致错误,类似于在根布局中将 dynamic 选项设置为 error

¥Attempting to use any of these features with next dev will result in an error, similar to setting the dynamic option to error in the root layout.

export const dynamic = 'error'

部署

¥Deploying

通过静态导出,Next.js 可以部署并托管在任何可以提供 HTML/CSS/JS 静态资源的 Web 服务器上。

¥With a static export, Next.js can be deployed and hosted on any web server that can serve HTML/CSS/JS static assets.

运行 next build 时,Next.js 会生成静态导出到 out 文件夹中。例如,假设你有以下路由:

¥When running next build, Next.js generates the static export into the out folder. For example, let's say you have the following routes:

  • /

  • /blog/[id]

运行 next build 后,Next.js 会生成以下文件:

¥After running next build, Next.js will generate the following files:

  • /out/index.html

  • /out/404.html

  • /out/blog/post-1.html

  • /out/blog/post-2.html

如果你使用的是 Nginx 等静态主机,你可以配置将传入请求重写为正确的文件:

¥If you are using a static host like Nginx, you can configure rewrites from incoming requests to the correct files:

server {
listen 80;
server_name acme.com;

root /var/www/out;

location / {
try_files $uri $uri.html $uri/ =404;
}

# This is necessary when `trailingSlash: false`.
# You can omit this when `trailingSlash: true`.
location /blog/ {
rewrite ^/blog/(.*)$ /blog/$1.html break;
}

error_page 404 /404.html;
location = /404.html {
internal;
}
}

版本历史

¥Version History

版本变化
v14.0.0next export 已被删除,取而代之的是 "output": "export"
v13.4.0App Router(稳定版)添加了增强的静态导出支持,包括使用 React 服务器组件和路由处理程序。
v13.3.0next export 已弃用并替换为 "output": "export"