Skip to content

Commit

Permalink
[Multi-Zones] Update example and documentation with most recent pract…
Browse files Browse the repository at this point in the history
…ices for Multi-Zones (#70565)

<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

### Improving Documentation

- Run `pnpm prettier-fix` to fix formatting issues before opening the
PR.
- Read the Docs Contribution Guide to ensure your contribution follows
the docs guidelines:
https://nextjs.org/docs/community/contribution-guide

### Adding or Updating Examples

- The "examples guidelines" are followed from our contributing doc
https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md
- Make sure the linting passes by running `pnpm build && pnpm lint`. See
https://github.com/vercel/next.js/blob/canary/contributing/repository/linting.md

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See:
https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md

### Adding a feature

- Implements an existing feature request or RFC. Make sure the feature
request has been accepted for implementation before opening a PR. (A
discussion must be opened, see
https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added
(https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md


## For Maintainers

- Minimal description (aim for explaining to someone not on the team to
understand the PR)
- When linking to a Slack thread, you might want to share details of the
conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Closes NEXT-
Fixes #

-->

---------

Co-authored-by: JJ Kasper <[email protected]>
  • Loading branch information
mknichel and ijjk committed Sep 28, 2024
1 parent 179f2e4 commit 1facc7f
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ description: Learn how to build micro-frontends using Next.js Multi-Zones to dep

</details>

Multi-Zones are an approach to micro-frontends that separate a large application on a domain into smaller Next.js applications that each serve a set of paths. This is useful when there are collections of pages unrelated to the other pages in the application. By moving those pages to a separate zone (i.e., a separate application), you can reduce the size of each application which improves build times and removes code that is only necessary for one of the zones.
Multi-Zones are an approach to micro-frontends that separate a large application on a domain into smaller Next.js applications that each serve a set of paths. This is useful when there are collections of pages unrelated to the other pages in the application. By moving those pages to a separate zone (i.e., a separate application), you can reduce the size of each application which improves build times and removes code that is only necessary for one of the zones. Since applications are decoupled, Multi-Zones also allows other applications on the domain to use their own choice of framework.

For example, let's say you have the following set of pages that you would like to split up:

Expand All @@ -36,20 +36,37 @@ Navigating from a page in one zone to a page in another zone, such as from `/` t

## How to define a zone

There are no special APIs to define a new zone. A zone is a normal Next.js application where you also configure a [basePath](/docs/app/api-reference/next-config-js/basePath) to avoid conflicts with pages and static files in other zones.
A zone is a normal Next.js application where you also configure an [assetPrefix](/docs/app/api-reference/next-config-js/assetPrefix) to avoid conflicts with pages and static files in other zones.

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

The default application that will handle all paths not sent to a more specific zone does not need a `basePath`.
Next.js assets, such as JavaScript and CSS, will be prefixed with `assetPrefix` to make sure that they don't conflict with assets from other zones. These assets will be served under `/assetPrefix/_next/...` for each of the zones.

Next.js assets, such as JavaScript and CSS, will also be prefixed with `basePath` to make sure that they don't conflict with assets from other zones. These assets will be served under `/basePath/_next/...` for each of the zones.
The default application handling all paths not routed to another more specific zone does not need an `assetPrefix`.

If the zone serves pages that don't share a common path prefix, such as `/home` and `/blog`, then you can also set [`assetPrefix`](/docs/app/api-reference/next-config-js/assetPrefix) to ensure that all Next.js assets are served under a unique path prefix for the zone without adding a path prefix to the rest of the routes in your application.
In versions older than Next.js 15, you may also need an additional rewrite to handle the static assets. This is no longer necessary in Next.js 15.

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

## How to route requests to the right zone

Expand All @@ -76,6 +93,19 @@ async rewrites() {

> **Good to know**: URL paths should be unique to a zone. For example, two zones trying to serve `/blog` would create a routing conflict.
### Routing requests using middleware

Routing requests through [`rewrites`](/docs/app/api-reference/next-config-js/rewrites) is recommended to minimize latency overhead for the requests, but middleware can also be used when there is a need for a dynamic decision when routing. For example, if you are using a feature flag to decide where a path should be routed such as during a migration, you can use middleware.

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

## Linking between zones

Links to paths in a different zone should use an `a` tag instead of the Next.js [`<Link>`](/docs/pages/api-reference/components/link) component. This is because Next.js will try to prefetch and soft navigate to any relative path in `<Link>` component, which will not work across zones.
Expand All @@ -87,3 +117,23 @@ The Next.js applications that make up the different zones can live in any reposi
Since the pages in different zones may be released at different times, feature flags can be useful for enabling or disabling features in unison across the different zones.

For [Next.js on Vercel](https://vercel.com?utm_source=next-site&utm_medium=docs&utm_campaign=next-website) applications, you can use a [monorepo](https://vercel.com/blog/monorepos-are-changing-how-teams-build-software?utm_source=next-site&utm_medium=docs&utm_campaign=next-website) to deploy all affected zones with a single `git push`.

<AppOnly>

## Server Actions

When using [Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) with Multi-Zones, you must explicitly allow the user-facing origin since your user facing domain may serve multiple applications. In your `next.config.js` file, add the following lines:

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

See [`serverActions.allowedOrigins`](/docs/app/api-reference/next-config-js/serverActions#allowedorigins) for more information.

</AppOnly>
File renamed without changes.
File renamed without changes.
10 changes: 1 addition & 9 deletions examples/with-zones/blog/next.config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
basePath: "/blog",
experimental: {
// Next.js will automatically prefix `basePath` to client side links which
// is useful when all links are relative to the `basePath` of this
// application. This option opts out of that behavior, which can be useful
// if you want to link outside of your zone, such as linking to
// "/" from "/blog" (the `basePath` for this application).
manualClientBasePath: true,
},
assetPrefix: "/blog-static",
};

module.exports = nextConfig;
6 changes: 4 additions & 2 deletions examples/with-zones/home/.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# Replace this URL with the URL of your blog app
BLOG_URL="https://with-zones-blog.vercel.app"
# Replace this URL with the URL of your blog app.
# For example, when deploying on production with Vercel, this may look like:
# BLOG_URL="https://with-zones-blog.vercel.app"
BLOG_URL="http://localhost:4000"
4 changes: 4 additions & 0 deletions examples/with-zones/home/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ const nextConfig = {
source: "/blog/:path+",
destination: `${BLOG_URL}/blog/:path+`,
},
{
source: "/blog-static/_next/:path+",
destination: `${BLOG_URL}/blog-static/_next/:path+`,
},
];
},
};
Expand Down
6 changes: 6 additions & 0 deletions examples/with-zones/home/test/next-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,11 @@ describe("next.config.js test", () => {
`${BLOG_URL}/blog/post/1`,
);
});

it("/blog static resources are rewritten to child zone", () => {
expect(
getRewrittenUrl("/blog-static/_next/static/chunks/chunk.css"),
).toEqual(`${BLOG_URL}/blog-static/_next/static/chunks/chunk.css`);
});
});
});

0 comments on commit 1facc7f

Please sign in to comment.