Next.js单仓库实现多域名对应多页面布局的动态路由方案问询
单仓库维护多风格Next.js站点实现方案
1. 目录结构落地
按你的预期规划路由组,同时抽离共用资源,确保复用性:
/app /(DesignOne) layout.tsx page.tsx /about page.tsx /contact page.tsx /(DesignTwo) layout.tsx page.tsx /about page.tsx /contact page.tsx /components # 全站点共用组件 /Button.tsx /Card.tsx /lib # 共用API、工具逻辑 /api.ts /utils.ts /public # 按站点分类存静态资源 /designone logo.png theme.css /designtwo logo.png theme.css
2. 站点路由匹配方案
方案一:环境变量驱动(适合独立部署时区分)
部署每个站点时设置专属环境变量,比如NEXT_PUBLIC_SITE_ID=designone,通过中间件做路由转发:
// middleware.ts import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' export function middleware(request: NextRequest) { // 从环境变量取站点标识,默认fallback到DesignOne const siteId = process.env.NEXT_PUBLIC_SITE_ID || 'designone' const formattedSiteId = `Design${siteId.charAt(0).toUpperCase()}${siteId.slice(1)}` const pathname = request.nextUrl.pathname // 已在对应站点路由组内,直接放行 if (pathname.startsWith(`/(${formattedSiteId})`)) { return NextResponse.next() } // 重定向到对应站点的路由 return NextResponse.redirect(new URL(`/(${formattedSiteId})${pathname}`, request.url)) } // 指定需要匹配的页面路径 export const config = { matcher: ['/', '/about/:path*', '/contact/:path*'], }
方案二:域名识别(适合多域名直接区分)
通过请求域名自动匹配对应站点,无需环境变量:
// middleware.ts import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' // 域名与站点路由组的映射表 const domainSiteMap = { 'designone.com': 'DesignOne', 'designtwo.com': 'DesignTwo', } export function middleware(request: NextRequest) { // 去掉开发环境的端口号 const domain = request.headers.get('host')?.replace(':3000', '') // 匹配站点,默认fallback到DesignOne const siteId = domainSiteMap[domain as keyof typeof domainSiteMap] || 'DesignOne' const pathname = request.nextUrl.pathname if (pathname.startsWith(`/(${siteId})`)) { return NextResponse.next() } return NextResponse.redirect(new URL(`/(${siteId})${pathname}`, request.url)) } export const config = { matcher: ['/', '/about/:path*', '/contact/:path*'], }
3. 样式与静态资源切换
在各站点的layout.tsx中加载专属静态资源:
// app/(DesignOne)/layout.tsx import '../../public/designone/theme.css' export default function DesignOneLayout({ children }: { children: React.ReactNode }) { return ( <html lang="zh-CN"> <body> <img src="/designone/logo.png" alt="DesignOne 品牌标识" /> {children} </body> </html> ) }
也可以用CSS变量统一管理主题色,在站点专属CSS中定义:
/* public/designone/theme.css */ :root { --primary-color: #2563eb; --bg-color: #f8fafc; }
4. 共用资源复用
所有站点直接导入/components和/lib下的内容即可:
// app/(DesignOne)/about/page.tsx import Button from '../../../components/Button' import { getAboutContent } from '../../../lib/api' export default async function AboutPage() { const content = await getAboutContent() return ( <div> <h1>关于DesignOne</h1> <p>{content}</p> <Button>联系我们</Button> </div> ) }
5. 部署配置
- 对于Vercel等托管平台,创建多个项目分别绑定对应域名,若用环境变量驱动则为每个项目设置专属
NEXT_PUBLIC_SITE_ID。 - Next.js构建时会自动按路由组生成对应站点的静态资源,确保每个站点只加载自身相关代码,也可结合增量静态生成优化构建效率。
内容的提问来源于stack exchange,提问作者Craig P
相关产品推荐
相关产品推荐

