使用Next.js Multi-Zones构建微前端

使用Next.js Multi-Zones构建微前端

Multi-Zones(多区域)是一种微前端方案:将同一域名下的大型应用拆分为多个较小的Next.js应用,每个应用负责一组路径。当某些页面集合与应用中的其他页面无关时,这种方式很有用。将这些页面移到独立区域,也就是独立应用,可以减小每个应用的体积,缩短构建时间,并移除只有另一个区域需要的代码。由于应用彼此解耦,同一域名下的其他应用也能选择自己的框架。

示例:With Zones。

例如,要拆分以下页面:

  • /blog/*:所有博客文章。
  • /dashboard/*:用户登录仪表盘后的所有页面。
  • /*:其他区域未覆盖的网站其余部分。

利用Multi-Zones,可以创建3个应用。它们通过同一域名提供服务,对用户看起来一致,但每个应用都能独立开发、独立部署。

A、B、C三个区域:区域内软导航,跨区域硬导航
同一区域中的页面使用软导航,不同区域之间使用硬导航。

在同一区域的页面之间跳转时,会执行软导航,不必重新加载页面。例如图中的/到/products。

从一个区域跳到另一个区域,例如从/到/dashboard,则会执行硬导航:卸载当前页面的资源,加载新页面的资源。经常一起访问的页面应放在同一区域,避免硬导航。

如何定义一个区域

区域是普通的Next.js应用,同时配置assetPrefix,避免与其他区域的页面和静态文件冲突。

next.config.js:

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

JavaScript、CSS等Next.js资源会加上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+',
        },
      ],
    }
  },
}

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

Multi-Zones中的区域由不同应用提供服务,因此必须将路径路由到正确区域。任何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。

使用Proxy路由请求

建议通过rewrites路由请求,以尽量减少额外延迟。不过,需要在路由时动态决策的场景也可以使用Proxy。例如在迁移期间,使用功能开关决定某个路径应该路由到哪里。

proxy.js:

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

区域之间的链接

指向其他区域路径的链接,应使用a标签,而非Next.js的<Link>组件。因为Next.js会尝试对<Link>中的任何相对路径预取并执行软导航,而跨区域时这样做无法正常工作。

共享代码

不同区域的Next.js应用可以位于任意仓库。不过,为了更方便地共享代码,通常可以把这些区域放进monorepo。如果区域位于不同仓库,也可以通过公开或私有NPM软件包共享代码。

不同区域的页面可能在不同时间发布;使用功能开关可以方便地让多个区域同步启用或禁用功能。

Server Actions

将Server Actions与Multi-Zones一起使用时,必须明确允许面向用户的来源,因为面向用户的域名可能为多个应用提供服务。在next.config.js中添加:

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

更多信息参见serverActions.allowedOrigins。

来源与署名

来源:Next.js官方文档:How to build micro-frontends using multi-zones and Next.js,Vercel与Next.js文档贡献者。本版为中文翻译,保留App Router范围与原始代码。项目许可见官方许可。

原始代码许可证全文
The MIT License (MIT)

Copyright (c) 2025 Vercel, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容