experimental.adapterPath
Next.js 提供了一个实验性 API,允许您创建自定义适配器以介入构建过程。这对于需要修改 Next.js 配置或处理构建输出的部署平台或自定义构建集成非常有用。
配置
要使用适配器,请在 experimental.adapterPath
中指定适配器模块的路径
next.config.js
/** @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
}
基本适配器结构
这是一个最小的适配器示例
my-adapter.js
/** @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 = adapter
API 参考
modifyConfig(config, context)
对于任何加载 next.config 的 CLI 命令都会调用此函数,以允许修改配置。
参数
config
: 完整的 Next.js 配置对象context.phase
: 当前构建阶段(参阅阶段)
返回: 修改后的配置对象(可以是异步的)
onBuildComplete(context)
在构建过程完成后调用,其中包含有关路由和输出的详细信息。
参数
routes
: 包含用于标头、重定向、重写和动态路由的路由清单的对象routes.headers
: 标头路由对象数组,包含source
、sourceRegex
、headers
、has
、missing
和可选的priority
字段routes.redirects
: 重定向路由对象数组,包含source
、sourceRegex
、destination
、statusCode
、has
、missing
和可选的priority
字段routes.rewrites
: 包含beforeFiles
、afterFiles
和fallback
数组的对象,每个数组都包含重写路由对象,其中包含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)
}
}
API 路由 (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>
}
}
App 页面 (outputs.appPages
)
来自 app/
目录的 React 页面,文件名为 page.{js,ts,jsx,tsx}
{
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>
}
}
App 路由 (outputs.appRoutes
)
来自 app/
的 API 和元数据路由,文件名为 route.{js,ts,jsx,tsx}
{
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
: 可选的否定条件
用例
适配器的常见用例包括
- 部署平台集成:自动为特定托管平台配置构建输出
- 资产处理:转换或优化构建输出
- 监控集成:收集构建指标和路由信息
- 自定义打包:以平台特定格式打包输出
- 构建验证:确保输出满足特定要求
- 路由生成:使用已处理的路由信息生成平台特定路由配置
这有帮助吗?