Skip to content

Commit 4f9ada6

Browse files
committed
Add docs
1 parent 9aa74e4 commit 4f9ada6

File tree

6 files changed

+112
-12
lines changed

6 files changed

+112
-12
lines changed

README.md

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,108 @@
1+
<p align="center">
2+
<a href="https://sst.dev/discord"><img alt="Discord" src="https://img.shields.io/discord/983865673656705025?style=flat-square" /></a>
3+
<a href="https://www.npmjs.com/package/open-next"><img alt="npm" src="https://img.shields.io/npm/v/open-next.svg?style=flat-square" /></a>
4+
</p>
5+
16
# OpenNext
27

38
OpenNext takes the Next.js build output and converts it into a package that can be deployed to any functions as a service platform.
49

5-
It supports all Next.js 13 features including, SSG, ISR, SSR, Image Optimization, and Middleware.
10+
## Features
11+
12+
OpenNext aims to support all Next.js 13 features. Some features are work in progress. Please open a [new issue](/issues/new) to let us know!
13+
14+
[x] API routes
15+
[x] Dynamic routes
16+
[x] Static site generation (SSG)
17+
[x] Server-side rendering (SSR)
18+
[x] Incremental static regeneration (ISR)
19+
[] Image optimization (work in progress)
20+
[] Middleware (work in progress)
21+
22+
## Quick start
23+
24+
Naviate to your Next.js app
25+
26+
```bash
27+
cd my-next-app
28+
```
29+
30+
Build app
31+
32+
```bash
33+
npx open-next build
34+
```
35+
36+
This will generate an `.open-next` directory with the following bundles:
37+
38+
```bash
39+
my-next-app/
40+
.open-next/
41+
assets/ -> Static assets to upload to an S3 Bucket
42+
server-function/ -> Handler code for server Lambda Function
43+
middleware-function/ -> Handler code for middleware Lambda@Edge Function
44+
```
45+
46+
## Recommeded infrastructure
47+
48+
OpenNext does not create the underlying infrastructure. You can create the infrastructure for your app with your preferred tool — SST, CDK, Serverless Framework, Terraform, etc.
49+
50+
This is the recommended setup.
51+
52+
<p align="center">
53+
<img alt="Architecture" src="/readme/architecture.png" width="600" />
54+
</p>
55+
56+
A few AWS resources are created:
57+
58+
- An S3 bucket to host static assets from `.open-next/assets`.
59+
- A Lambda function handling server and API requests.
60+
- A Lambda function handling image optimization requests.
61+
- A CloudFront distribution that routes incoming requests based on URL path.
62+
- And finally a Lambda@Edge function that runs the middleware before requests hit the CloudFront.
63+
64+
## How does OpenNext work?
65+
66+
When you call `npx open-next build`, behind the scene OpenNext builds your Next.js app using the `@vercel/next` package. This package does 2 things:
67+
68+
- It calls `next build` with the [`minimalMode`](https://github.com/vercel/next.js/discussions/29801) flag. This flag disables running middleware in the server code.
69+
70+
- Instead, it bundles the middleware separately. This allows us to deploy middleware to edge locations.
71+
72+
Then `open-next` transforms `@vercel/next`'s build output into a format that can be deployed to AWS. The following steps are performed:
73+
74+
1. Creates a `.open-next` directory in user's Next.js app.
75+
76+
1. Bundles the middleware handler with the [middleware adapter](/cli/assets/middleware-adapter.js). And outputs the handler file into `.open-next/middleware-function`.
77+
78+
1. Bundles the server handler with the [server adapter](/cli/assets/server-adapter.cjs). And outputs the handler file into `.open-next/server-function`. Also copies over other server assets from `.next/standalone`.
79+
80+
1. Bundles the static assets into `.open-next/assets` with the following content:
81+
82+
- `public`
83+
- `.next/BUILD_ID`
84+
- `.next/static`
85+
86+
## Example
87+
88+
In the `example` folder, you can find a benchmark Next.js app. Here is a link deployed using SST's [`NextjsSite`](https://docs.sst.dev/constructs/NextjsSite) construct. It contains a handful of pages. Each page aims to test a single Next.js feature.
89+
90+
## Opening an issue
91+
92+
Create a PR and add a new page to the benchmark app in `example` with the issue.
93+
94+
### Debugging
95+
96+
You can find the server log in the AWS CloudWatch console of the **region you deployed to**.
97+
98+
You can find the middleware log in the AWS CloudWatch console of the **region you are physically close to**. For example, if you deployed your app to `us-east-1` and you are in London, it's likely you will find the logs in `eu-west-2`.
99+
100+
## FAQ
101+
102+
#### Why use the `@vercel/next` package for building the Next.js app?
103+
104+
`next build` generates a server function that runs middleware. With this setup, if you use middleware for static pages, these pages cannot be cached. If cached, CDN (CloudFront) will send back cached response without calling the origin (server Lambda function). To ensure the middleware is invoked on every request, caching is always disabled.
105+
106+
Vercel deploys the middleware code to edge functions, which gets invoked before the request reaches the CDN. This way, static pages can be cached. On request, middleware gets called, and then the CDK can send back cached response.
107+
108+
OpenNext is designed to adopt the same setup as Vercel. And building using `@vercel/next` allows us to separate the middleware code from the server code.
File renamed without changes.
File renamed without changes.

cli/src/build.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ function createServerBundle() {
5555
);
5656
const result = buildSync({
5757
entryPoints: [
58-
path.resolve(__dirname, "../assets/server-handler.cjs")
58+
path.resolve(__dirname, "../assets/server-adapter.cjs")
5959
],
6060
bundle: true,
6161
target: "node16",
@@ -83,14 +83,14 @@ function createMiddlewareBundle(src: string) {
8383
fs.mkdirSync(buildTempPath, { recursive: true });
8484
fs.writeFileSync(path.join(buildTempPath, "middleware.js"), src);
8585
fs.copyFileSync(
86-
path.join(__dirname, "../assets/middleware-handler.js"),
87-
path.join(buildTempPath, "middleware-handler.js")
86+
path.join(__dirname, "../assets/middleware-adapter.js"),
87+
path.join(buildTempPath, "middleware-adapter.js")
8888
);
8989

9090
// Create a directory that we will use to create the bundled version
9191
// of the "core server build" along with our custom Lamba server handler.
9292
const result = buildSync({
93-
entryPoints: [path.join(buildTempPath, "middleware-handler.js")],
93+
entryPoints: [path.join(buildTempPath, "middleware-adapter.js")],
9494
target: "esnext",
9595
format: "esm",
9696
platform: "node",

docs/pages/index.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,16 +166,13 @@ export default function Home() {
166166
<ol>
167167
<li>
168168
<p>
169-
Run <code>next build</code> to generate the <code>.next</code>{" "}
169+
Run <code>open-next build</code> to generate the <code>.open-next</code>{" "}
170170
directory.
171171
</p>
172-
</li>
173-
<li>
174172
<p>
175-
Run <code>open-next</code>. This'll in turn generate the an{" "}
176-
<code>.open-next</code> directory. This directory contains a zip
173+
This directory contains a zip
177174
file of your app that'll run in a Lambda function, a zip file
178-
that'll run the image optimization Lambda, and a zip file
175+
that'll run the middleware Lambda@Edge function, and a zip fileectory
179176
containing your static assets that'll go to S3.
180177
</p>
181178
</li>
@@ -196,7 +193,7 @@ export default function Home() {
196193
</li>
197194
<li>
198195
<p>
199-
Finally, upload the generated assets in step 2 to the
196+
Finally, upload the generated assets in step 1 to the
200197
infrastructure you created.
201198
</p>
202199
</li>

readme/architecture.png

558 KB
Loading

0 commit comments

Comments
 (0)