跳到主要内容

如何使用多区域和 Next.js 构建微前端

示例

多区域是一种微前端方法,将域上的大型应用程序分离为较小的 Next.js 应用程序,每个应用程序服务一组路径。当应用程序中有与其他页面无关的页面集合时,这很有用。通过将这些页面移动到单独的区域(即单独的应用程序),您可以减少每个应用程序的大小,这改善了构建时间并移除了仅对其中一个区域必要的代码。由于应用程序是解耦的,多区域还允许域上的其他应用程序使用他们自己选择的框架。

例如,假设您有以下页面集合,您希望拆分:

  • /blog/* 用于所有博客文章
  • /dashboard/* 用于用户登录仪表板时的所有页面
  • /* 用于其他区域未涵盖的网站其余部分

通过多区域支持,您可以创建三个应用程序,它们都在同一域名上提供服务,对用户看起来相同,但您可以独立开发和部署每个应用程序。

三个区域:A、B、C。显示来自不同区域的路由之间的硬导航,以及同一区域内路由之间的软导航。三个区域:A、B、C。显示来自不同区域的路由之间的硬导航,以及同一区域内路由之间的软导航。

在同一区域内的页面之间导航将执行软导航,这是一种不需要重新加载页面的导航。例如,在此图中,从 / 导航到 /products 将是软导航。

从一个区域的页面导航到另一个区域的页面,例如从 //dashboard,将执行硬导航,卸载当前页面的资源并加载新页面的资源。经常一起访问的页面应该位于同一区域以避免硬导航。

如何定义区域

区域是一个普通的 Next.js 应用程序,您还可以配置 assetPrefix 以避免与其他区域中的页面和静态文件冲突。

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
assetPrefix: '/blog-static',
}

Next.js 资源(如 JavaScript 和 CSS)将使用 assetPrefix 前缀,以确保它们不会与其他区域的资源冲突。这些资源将在每个区域的 /assetPrefix/_next/... 下提供服务。

处理所有未路由到其他更具体区域的路径的默认应用程序不需要 assetPrefix

在 Next.js 15 之前的版本中,您可能还需要额外的重写来处理静态资源。这在 Next.js 15 中不再需要。

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
assetPrefix: '/blog-static',
async rewrites() {
return {
beforeFiles: [
{
source: '/blog-static/_next/:path+',
destination: '/_next/:path+',
},
],
}
},
}

如何将请求路由到正确的区域

通过多区域设置,您需要将路径路由到正确的区域,因为它们由不同的应用程序提供服务。您可以使用任何 HTTP 代理来执行此操作,但也可以使用其中一个 Next.js 应用程序来路由整个域的请求。

要使用 Next.js 应用程序路由到正确的区域,您可以使用 rewrites。对于由不同区域服务的每个路径,您将添加一个重写规则以将该路径发送到其他区域的域,您还需要重写静态资源的请求。例如:

next.config.js
async rewrites() {
return [
{
source: '/blog',
destination: `${process.env.BLOG_DOMAIN}/blog`,
},
{
source: '/blog/:path+',
destination: `${process.env.BLOG_DOMAIN}/blog/:path+`,
},
{
source: '/blog-static/:path+',
destination: `${process.env.BLOG_DOMAIN}/blog-static/:path+`,
}
];
}

destination 应该是由区域服务的 URL,包括方案和域。这应该指向区域的生产域,但也可以用于在本地开发中将请求路由到 localhost

提示:URL 路径应该对区域是唯一的。例如,两个区域试图服务 /blog 将创建路由冲突。

使用中间件路由请求

建议通过 rewrites 路由请求以最小化请求的延迟开销,但当路由时需要动态决策时也可以使用中间件。例如,如果您使用功能标志来决定路径应该路由到哪里,例如在迁移期间,您可以使用中间件。

middleware.js
export async function middleware(request) {
const { pathname, search } = req.nextUrl;
if (pathname === '/your-path' && myFeatureFlag.isEnabled()) {
return NextResponse.rewrite(`${rewriteDomain}${pathname}${search}`);
}
}

区域之间的链接

指向不同区域中路径的链接应该使用 a 标签而不是 Next.js <Link> 组件。这是因为 Next.js 将尝试预取并软导航到 <Link> 组件中的任何相对路径,这在区域之间不起作用。

共享代码

组成不同区域的 Next.js 应用程序可以存在于任何存储库中。但是,通常将这些区域放在单体仓库中以便更容易共享代码。对于存在于不同存储库中的区域,也可以使用公共或私有 NPM 包共享代码。

由于不同区域中的页面可能在不同时间发布,功能标志对于在不同区域中统一启用或禁用功能很有用。

服务器操作

当在多区域中使用服务器操作时,您必须明确允许面向用户的源,因为您的面向用户域可能服务多个应用程序。在您的 next.config.js 文件中,添加以下行:

next.config.js
const nextConfig = {
experimental: {
serverActions: {
allowedOrigins: ['your-production-domain.com'],
},
},
}

查看 serverActions.allowedOrigins 以获取更多信息。