如何在Next.js App Router的客户端模块中使用运行时变量?
在Next.js App Router中为工具模块获取运行时变量的方案
App Router确实移除了publicRuntimeConfig,这源于其架构对服务端/客户端边界的严格隔离。你的困惑并非操作错误,而是架构设计带来的必然限制,以下是几种实用解决方案:
1. 依赖注入(推荐)
将运行时变量作为参数传入工具函数,而非让工具函数主动获取,这种方式最贴合模块化设计,同时兼容服务端和客户端:
// utils/your-tool.js export function processRuntimeData(data, runtimeVars) { // 使用传入的runtimeVars处理数据 return data.map(item => ({ ...item, env: runtimeVars.NEXT_PUBLIC_APP_ENV })); } // 服务端组件中调用 import { processRuntimeData } from '@/utils/your-tool'; import { env } from 'process'; export default async function ServerComponent() { const data = await fetchSomeData(); const processedData = processRuntimeData(data, { NEXT_PUBLIC_APP_ENV: env.NEXT_PUBLIC_APP_ENV }); return <ClientComponent processedData={processedData} />; } // 客户端组件中调用(若需客户端侧处理) 'use client'; import { processRuntimeData } from '@/utils/your-tool'; export default function ClientComponent({ processedData }) { const clientProcessed = processRuntimeData(processedData, { NEXT_PUBLIC_APP_ENV: process.env.NEXT_PUBLIC_APP_ENV }); return <div>{clientProcessed.map(item => <p key={item.id}>{item.env}</p>)}</div>; }
2. 创建运行时变量初始化模块
若工具函数需频繁复用相同变量,可创建专门的初始化模块,在服务端和客户端分别完成初始化:
// lib/runtime-vars.js let runtimeVars = null; export function initRuntimeVars(vars) { runtimeVars = vars; } export function getRuntimeVars() { if (!runtimeVars) { throw new Error('Runtime vars未初始化,请先调用initRuntimeVars'); } return runtimeVars; } // 服务端入口(如root layout) import { initRuntimeVars } from '@/lib/runtime-vars'; import { env } from 'process'; export default async function RootLayout({ children }) { initRuntimeVars({ NEXT_PUBLIC_APP_ENV: env.NEXT_PUBLIC_APP_ENV, API_URL: env.API_URL }); return ( <html> <body>{children}</body> </html> ); } // 客户端入口(如单独的client初始化文件) 'use client'; import { initRuntimeVars } from '@/lib/runtime-vars'; initRuntimeVars({ NEXT_PUBLIC_APP_ENV: process.env.NEXT_PUBLIC_APP_ENV }); // 工具函数中使用 import { getRuntimeVars } from '@/lib/runtime-vars'; export function processData(data) { const vars = getRuntimeVars(); return data.map(item => ({ ...item, apiUrl: vars.API_URL })); }
注意:客户端仅能访问带NEXT_PUBLIC_前缀的环境变量,服务端则可访问所有环境变量。
3. 路由处理器统一提供变量(适合纯客户端工具)
若工具函数仅在客户端使用,可通过路由处理器暴露运行时变量,再在客户端工具模块中请求获取:
// app/api/runtime-vars/route.js import { NextResponse } from 'next/server'; import { env } from 'process'; export async function GET() { return NextResponse.json({ NEXT_PUBLIC_APP_ENV: env.NEXT_PUBLIC_APP_ENV, API_URL: env.API_URL // 服务端可安全返回非public变量 }); } // utils/client-tool.js let cachedVars = null; export async function getRuntimeVars() { if (cachedVars) return cachedVars; const res = await fetch('/api/runtime-vars'); cachedVars = await res.json(); return cachedVars; } export async function processClientData(data) { const vars = await getRuntimeVars(); return data.map(item => ({ ...item, apiUrl: vars.API_URL })); }
该方案适合客户端需动态获取服务端环境变量的场景,建议缓存请求结果以减少网络开销。
为什么组件可行但工具模块不行?
组件属于React渲染流程的一部分,可直接接触服务端上下文或客户端请求能力;而普通工具模块独立于渲染流程,没有内置的上下文或请求通道,因此无法直接获取运行时变量,必须通过显式传递或初始化的方式拿到变量。
内容的提问来源于stack exchange,提问作者dingdingding
相关产品推荐
相关产品推荐

