You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 05:30:04