Next.js 提供了一个实验性 API,允许您创建自定义适配器以介入构建过程。这对于需要修改 Next.js 配置或处理构建输出的部署平台或自定义构建集成非常有用。
要使用适配器,请在 experimental.adapterPath 中指定您的适配器模块路径:
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
adapterPath: require.resolve('./my-adapter.js'),
},
}
module.exports = nextConfig适配器是一个模块,它导出一个实现 NextAdapter 接口的对象:
export interface NextAdapter {
name: string
modifyConfig?: (
config: NextConfigComplete,
ctx: {
phase: PHASE_TYPE
}
) => Promise<NextConfigComplete> | NextConfigComplete
onBuildComplete?: (ctx: {
routes: {
headers: Array<ManifestHeaderRoute>
redirects: Array<ManifestRedirectRoute>
rewrites: {
beforeFiles: Array<ManifestRewriteRoute>
afterFiles: Array<ManifestRewriteRoute>
fallback: Array<ManifestRewriteRoute>
}
dynamicRoutes: ReadonlyArray<ManifestRoute>
}
outputs: AdapterOutputs
projectDir: string
repoRoot: string
distDir: string
config: NextConfigComplete
nextVersion: string
}) => Promise<void> | void
}这是一个最小的适配器示例:
/** @type {import('next').NextAdapter} */
const adapter = {
name: 'my-custom-adapter',
async modifyConfig(config, { phase }) {
// Modify the Next.js config based on the build phase
if (phase === 'phase-production-build') {
return {
...config,
// Add your modifications
}
}
return config
},
async onBuildComplete({
routes,
outputs,
projectDir,
repoRoot,
distDir,
config,
nextVersion,
}) {
// Process the build output
console.log('Build completed with', outputs.pages.length, 'pages')
// Access different output types
for (const page of outputs.pages) {
console.log('Page:', page.pathname, 'at', page.filePath)
}
for (const apiRoute of outputs.pagesApi) {
console.log('API Route:', apiRoute.pathname, 'at', apiRoute.filePath)
}
for (const appPage of outputs.appPages) {
console.log('App Page:', appPage.pathname, 'at', appPage.filePath)
}
for (const prerender of outputs.prerenders) {
console.log('Prerendered:', prerender.pathname)
}
},
}
module.exports = adaptermodifyConfig(config, context)当任何加载 next.config 的 CLI 命令执行时调用,以允许修改配置。
参数:
config:完整的 Next.js 配置对象context.phase:当前构建阶段(参见 阶段)返回: 修改后的配置对象(可以是异步的)
onBuildComplete(context)在构建过程完成后调用,提供有关路由和输出的详细信息。
参数:
routes:包含 headers、redirects、rewrites 和 dynamic routes 的路由清单对象
routes.headers:由 header 路由对象组成的数组,包含 source、sourceRegex、headers、has、missing 和可选的 priority 字段routes.redirects:由 redirect 路由对象组成的数组,包含 source、sourceRegex、destination、statusCode、has、missing 和可选的 priority 字段routes.rewrites:一个对象,包含 beforeFiles、afterFiles 和 fallback 数组,每个数组都包含 rewrite 路由对象,这些对象具有 source、sourceRegex、destination、has 和 missing 字段routes.dynamicRoutes:由动态路由对象组成的数组,包含 source、sourceRegex、destination、has 和 missing 字段outputs:按类型组织的关于所有构建输出的详细信息projectDir:Next.js 项目目录的绝对路径repoRoot:检测到的仓库根目录的绝对路径distDir:构建输出目录的绝对路径config:最终的 Next.js 配置(已应用 modifyConfig)nextVersion:正在使用的 Next.js 版本buildId:当前构建的唯一标识符outputs 对象包含不同输出类型的数组:
outputs.pages)来自 pages/ 目录的 React 页面:
{
type: 'PAGES'
id: string // Route identifier
filePath: string // Path to the built file
pathname: string // URL pathname
sourcePage: string // Original source file path in pages/ directory
runtime: 'nodejs' | 'edge'
assets: Record<string, string> // Traced dependencies (key: relative path from repo root, value: absolute path)
wasmAssets?: Record<string, string> // Bundled wasm files (key: name, value: absolute path)
config: {
maxDuration?: number
preferredRegion?: string | string[]
env?: Record<string, string> // Environment variables (edge runtime only)
}
}outputs.pagesApi)来自 pages/api/ 的 API 路由:
{
type: 'PAGES_API'
id: string
filePath: string
pathname: string
sourcePage: string // Original relative source file path
runtime: 'nodejs' | 'edge'
assets: Record<string, string>
wasmAssets?: Record<string, string>
config: {
maxDuration?: number
preferredRegion?: string | string[]
env?: Record<string, string>
}
}outputs.appPages)来自 app/ 目录中带有 page.{js,ts,jsx,tsx} 的 React 页面:
{
type: 'APP_PAGE'
id: string
filePath: string
pathname: string // Includes .rsc suffix for RSC routes
sourcePage: string // Original relative source file path
runtime: 'nodejs' | 'edge'
assets: Record<string, string>
wasmAssets?: Record<string, string>
config: {
maxDuration?: number
preferredRegion?: string | string[]
env?: Record<string, string>
}
}outputs.appRoutes)来自 app/ 目录中带有 route.{js,ts,jsx,tsx} 的 API 和元数据路由:
{
type: 'APP_ROUTE'
id: string
filePath: string
pathname: string
sourcePage: string
runtime: 'nodejs' | 'edge'
assets: Record<string, string>
wasmAssets?: Record<string, string>
config: {
maxDuration?: number
preferredRegion?: string | string[]
env?: Record<string, string>
}
}outputs.prerenders)启用 ISR 的路由和静态预渲染:
{
type: 'PRERENDER'
id: string
pathname: string
parentOutputId: string // ID of the source page/route
groupId: number // Revalidation group identifier (prerenders with same groupId revalidate together)
pprChain?: {
headers: Record<string, string> // PPR chain headers (e.g., 'x-nextjs-resume': '1')
}
parentFallbackMode?: 'blocking' | false | null // Fallback mode from getStaticPaths
fallback?: {
filePath: string
initialStatus?: number
initialHeaders?: Record<string, string | string[]>
initialExpiration?: number
initialRevalidate?: number
postponedState?: string // PPR postponed state
}
config: {
allowQuery?: string[] // Allowed query parameters
allowHeader?: string[] // Allowed headers for ISR
bypassFor?: RouteHas[] // Cache bypass conditions
renderingMode?: RenderingMode
bypassToken?: string
}
}outputs.staticFiles)静态资源和自动静态优化页面:
{
type: 'STATIC_FILE'
id: string
filePath: string
pathname: string
}outputs.middleware)中间件函数(如果存在):
{
type: 'MIDDLEWARE'
id: string
filePath: string
pathname: string // Always '/_middleware'
sourcePage: string // Always 'middleware'
runtime: 'nodejs' | 'edge'
assets: Record<string, string>
wasmAssets?: Record<string, string>
config: {
maxDuration?: number
preferredRegion?: string | string[]
env?: Record<string, string>
matchers?: Array<{
source: string
sourceRegex: string
has: RouteHas[] | undefined
missing: RouteHas[] | undefined
}>
}
}onBuildComplete 中的 routes 对象提供了完整的路由信息,其中包含已处理的模式,可用于部署:
每个标头路由包括:
source:原始路由模式(例如,/about)sourceRegex:用于匹配请求的编译正则表达式headers:要应用的标头键值对has:必须满足的可选条件missing:不得满足的可选条件priority:内部路由的可选标志每个重定向路由包括:
source:原始路由模式sourceRegex:用于匹配的编译正则表达式destination:目标 URL(可以包含捕获组)statusCode:HTTP 状态码(301, 302, 307, 308)has:可选的肯定条件missing:可选的否定条件priority:内部路由的可选标志重写分为三个阶段:
beforeFiles:在文件系统(包括页面和公共文件)之前检查afterFiles:在页面/公共文件之后但在动态路由之前检查fallback:在所有其他路由之后检查每个重写都包含 source、sourceRegex、destination、has 和 missing。
从动态路由段(例如,[slug]、[...path])生成。每个包含:
source:路由模式sourceRegex:带有命名捕获组的编译正则表达式destination:带有参数替换的内部目标has:可选的肯定条件missing:可选的否定条件适配器的常见用例包括: