Multi-Zones
示例
Multi-Zones 是一种微前端方案,它将同一域名下的大型应用拆分成多个较小的 Next.js 应用,每个应用负责处理一组特定的路径。当应用中存在一些与其他页面无关的页面集合时,这种方案特别有用。通过将这些页面移至单独的 zone (即单独的应用),你可以减小每个应用的体积,从而改善构建时间,并删除仅对某个 zone 必要的代码。由于应用之间是解耦的,Multi-Zones 还允许域名下的其他应用使用它们各自选择的框架。
例如,假设你有以下一组需要拆分的页面:
/blog/*
用于所有博客文章/dashboard/*
用于用户登录后的所有仪表盘页面/*
用于网站其他未被其他 zone 覆盖的部分
借助 Multi-Zones 支持,你可以创建三个应用,它们都在同一个域名下提供服务,对用户来说看起来是一样的,但你可以独立开发和部署每个应用。
在同一个 zone 内的页面之间导航将执行软导航,即不需要重新加载页面的导航。例如,在这个示意图中,从 /
导航到 /products
将是一个软导航。
从一个 zone 的页面导航到另一个 zone 的页面时,例如从 /
导航到 /dashboard
,将执行硬导航,卸载当前页面的资源并加载新页面的资源。经常一起访问的页面应该放在同一个 zone 中,以避免硬导航。
如何定义 zone
zone 是一个普通的 Next.js 应用,你还需要配置 assetPrefix 以避免与其他 zone 中的页面和静态文件发生冲突。
/** @type {import('next').NextConfig} */
const nextConfig = {
assetPrefix: '/blog-static',
}
Next.js 的资源,如 JavaScript 和 CSS,将以 assetPrefix
为前缀,以确保它们不会与其他 zone 的资源发生冲突。这些资源将在每个 zone 的 /assetPrefix/_next/...
下提供服务。
处理所有未路由到其他更具体 zone 的路径的默认应用不需要 assetPrefix
。
在早于 Next.js 15 的版本中,你可能还需要一个额外的 rewrite 来处理静态资源。在 Next.js 15 中这不再必要。
/** @type {import('next').NextConfig} */
const nextConfig = {
assetPrefix: '/blog-static',
async rewrites() {
return {
beforeFiles: [
{
source: '/blog-static/_next/:path+',
destination: '/_next/:path+',
},
],
}
},
}
如何将请求路由到正确的 zone
使用 Multi Zones 设置后,你需要将路径路由到正确的 zone,因为它们是由不同的应用提供服务的。你可以使用任何 HTTP 代理来实现这一点,但其中一个 Next.js 应用也可以用来路由整个域名的请求。
要使用 Next.js 应用路由到正确的 zone,你可以使用 rewrites
。对于每个由不同 zone 提供服务的路径,你需要添加一个 rewrite 规则,将该路径发送到其他 zone 的域名。例如:
async rewrites() {
return [
{
source: '/blog',
destination: `${process.env.BLOG_DOMAIN}/blog`,
},
{
source: '/blog/:path+',
destination: `${process.env.BLOG_DOMAIN}/blog/:path+`,
}
];
}
destination
应该是由该 zone 提供服务的 URL,包括协议和域名。这应该指向该 zone 的生产域名,但也可以用于在本地开发中将请求路由到 localhost
。
值得注意的是:URL 路径对于每个 zone 应该是唯一的。例如,两个 zone 试图提供
/blog
会造成路由冲突。
使用中间件路由请求
通过 rewrites
路由请求是推荐的方式,可以最小化请求的延迟开销,但当需要在路由时进行动态决策时,也可以使用中间件。例如,如果你在迁移过程中使用功能标志来决定路径应该路由到哪里,你可以使用中间件。
export async function middleware(request) {
const { pathname, search } = req.nextUrl;
if (pathname === '/your-path' && myFeaturFlag.isEnabled()) {
return NextResponse.rewrite(`${rewriteDomain}${pathname}${search});
}
}
zone 之间的链接
链接到其他 zone 的路径时应该使用 a
标签,而不是 Next.js 的 <Link>
组件。这是因为 Next.js 会尝试预取并软导航到 <Link>
组件中的任何相对路径,这在跨 zone 时不会生效。
共享代码
构成不同 zone 的 Next.js 应用可以存在于任何仓库中。但是,将这些 zone 放在 monorepo 中通常更方便,可以更轻松地共享代码。对于存在于不同仓库中的 zone,代码也可以通过公共或私有的 NPM 包来共享。
由于不同 zone 中的页面可能在不同时间发布,功能标志对于在不同 zone 之间统一启用或禁用功能很有用。
对于 Next.js on Vercel 应用,你可以使用 monorepo 通过单个 git push
部署所有受影响的 zone。
Server Actions
在 Multi-Zones 中使用 Server Actions 时,由于你的面向用户的域名可能会提供多个应用,你必须明确允许面向用户的源。在你的 next.config.js
文件中,添加以下行:
const nextConfig = {
experimental: {
serverActions: {
allowedOrigins: ['your-production-domain.com'],
},
},
}
查看 serverActions.allowedOrigins
了解更多信息。