本指南解释了如何设置 TinaCMS 来管理多个租户的内容,每个租户通过唯一的域名提供服务,并使用同一个代码库。这对于希望集中管理跨品牌或客户的内容和用户界面的项目非常理想。
在多租户配置中:
多租户的核心是中间件,它检查请求的域名并动态重写路径以加载正确的租户内容。
当用户访问 tenant1.com 时,中间件会将请求内部重写为 /tenant1/...,从而允许单一的 [tenant]/[slug]/page.tsx 模式为任何域名提供内容。
我们需要以下内容
在 .env 或 Vercel 环境变量中定义产品-域名映射:
NEXT_PUBLIC_PRODUCT_LIST = [{"product": "tenant1","domain": "tenant1.com"}, {"product": "tenant2","domain": "tenant2.ai"}]
在中间件中解析此列表以将传入的域名映射到租户 ID。
// middleware.tsimport { NextRequest, NextResponse } from 'next/server'const PRODUCT_LIST = JSON.parse(process.env.NEXT_PUBLIC_PRODUCT_LIST || '[]')const domainToProduct = Object.fromEntries(PRODUCT_LIST.map(({ domain, product }: any) => [domain, product]))export function middleware(request: NextRequest) {const hostname = request.headers.get('host') || ''const product = domainToProduct[hostname]if (product && !request.nextUrl.pathname.startsWith(`/${product}`)) {const url = request.nextUrl.clone()url.pathname = `/${product}${url.pathname}`return NextResponse.rewrite(url)}return NextResponse.next()}
或者在 SSW Products Repository 中找到更高级的中间件。
将你的 app/ 文件夹结构设置如下:
|- app /| |- [tenant] /| |- [slug] /| |- page.tsx
在 page.tsx 中,从相应的租户文件夹加载内容:
const Page = async ({ params }: { params: { tenant: string; slug: string } }) => {const content = await getPageContent(`${params.tenant}/${params.slug}.mdx`)return <PageRenderer data={content} />}
在 content/ 中创建租户特定的文件夹:
|- content /| |- docs /| |- tenant1 /| | |- intro.mdx| |- tenant2 /| |- intro.mdx
确保在 TinaCloud 中为每个域名添加相应的站点 URL,以便可以使用 Tina 管理内容!
例如,在 Vercel 中:
如果你想克隆一个多租户站点的示例,GitHub 上的 SSW Products repository 实现了使用 TinaCMS 的多租户功能。