Skip to content

OpenNext V3 #402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 107 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
a420d9a
created basic config file
conico974 Oct 31, 2023
c2f29a8
basic wrapper and converter implementation
conico974 Nov 2, 2023
3379459
Minimal response writable
conico974 Nov 3, 2023
788913e
build config
conico974 Nov 3, 2023
b20f0b5
change response to transform to allow to use pipeline
conico974 Nov 3, 2023
a874fd7
fix streaming for v3
conico974 Nov 7, 2023
e7fe515
compression support
conico974 Nov 8, 2023
a5622de
better docker handler
conico974 Nov 8, 2023
26b3386
add converter for apigw-v1 & cloudfront
conico974 Nov 8, 2023
a9375ec
overridable queue
conico974 Nov 8, 2023
423831a
overridable s3 cache
conico974 Nov 8, 2023
70d3d64
overridable tag cache
conico974 Nov 8, 2023
6c10eed
prebuild middleware
conico974 Nov 17, 2023
14dbaac
refactor routing and middleware
conico974 Nov 18, 2023
5199eb9
big refactoring
conico974 Nov 20, 2023
8413270
refactor: cleanup plugins
conico974 Nov 21, 2023
a063596
make other lambdas overridable as well
conico974 Nov 23, 2023
8dabff0
externalMiddleware
conico974 Nov 23, 2023
2630bb7
improve plugins
conico974 Nov 24, 2023
51b5d46
fix proxy request and make it work with streaming
conico974 Nov 24, 2023
bac04a2
bugfix
conico974 Nov 25, 2023
df1142b
fix host
conico974 Nov 25, 2023
53b95d8
refactor wrapper
conico974 Nov 28, 2023
5b69d2f
generate basic dockerfile
conico974 Nov 28, 2023
a3dcb26
Only build open-next config once
conico974 Nov 28, 2023
a50cdf7
generate basic output file for IAC to use
conico974 Nov 29, 2023
d422b0b
basic splitting
conico974 Nov 30, 2023
3763bab
bundled next server
conico974 Dec 1, 2023
a5995db
fix external middleware cloudfront
conico974 Dec 6, 2023
6c1cbcf
fix image adapter rebase
conico974 Dec 6, 2023
23bdd78
couple of fix for node
conico974 Dec 7, 2023
d4aa85f
package version
conico974 Dec 7, 2023
cc9dcbb
support for warmer with splitted fn
conico974 Dec 11, 2023
7c4145d
basic support for edge runtime
conico974 Dec 12, 2023
132f3d5
external middleware support rewrite between splitted servers
conico974 Dec 13, 2023
65bec91
fix alias
conico974 Dec 13, 2023
09d023c
Merge branch 'feat/splitting' into v3-rc
conico974 Dec 13, 2023
7a20b15
update package.json
conico974 Dec 13, 2023
e864df2
use AsyncLocalStorage to scope lastModified to a single request
conico974 Jan 9, 2024
6f9a987
merge upstream/main
conico974 Jan 9, 2024
142aac3
Add basic validation
conico974 Jan 20, 2024
9d03aec
fix EISDIR issue with copying traced symlink
conico974 Jan 20, 2024
2f3bd61
added override name to the output for better IAC support
conico974 Jan 20, 2024
6b64a1d
rename BuildOptions
conico974 Jan 21, 2024
618d1ea
normalize locale path before passing to middleware
conico974 Jan 21, 2024
809ae1a
Copy necessary static files
conico974 Jan 21, 2024
8076ae6
fix issues with fallback and i18n in page router
conico974 Jan 23, 2024
e643578
Add a big warning for build on windows
conico974 Jan 23, 2024
770ac8a
fix for cloudflare workers
conico974 Jan 26, 2024
09b7b54
add wasm fils and assets
conico974 Jan 27, 2024
5daa00d
fix 14.1 cache
conico974 Jan 27, 2024
e96f69d
fix wasm import node
conico974 Jan 27, 2024
cb8c980
Merge branch 'feat/splitting' into v3-rc
conico974 Jan 27, 2024
94fde9f
update version
conico974 Jan 27, 2024
0af277a
merge upstream
conico974 Feb 5, 2024
51ba372
make open-next.config.ts optional
conico974 Feb 6, 2024
b86860c
Merge branch 'feat/splitting' into v3-rc
conico974 Feb 6, 2024
aa97c43
Fix cannot write default config file b/c folder not created (#364)
fwang Feb 16, 2024
12bf5d2
fix for monorepo
conico974 Feb 16, 2024
1a420eb
fix for output for dynamodb provider
conico974 Feb 16, 2024
b2879f6
fix dynamoProvider, skipTrailingSlash, weird ISR deduplication issue
conico974 Feb 16, 2024
4a55c2b
little improvement to streaming in lambda
conico974 Feb 16, 2024
8dc9e73
fix another monorepo error
conico974 Feb 16, 2024
2adb4ab
e2e fixes for v3 rc
conico974 Feb 16, 2024
e1a9589
update version
conico974 Feb 16, 2024
68858bb
Not use custom-resource converter for dynamodb seeding adapter (#365)
fwang Feb 20, 2024
2357429
fix fallback false for route without i18n
conico974 Feb 20, 2024
46562b1
version package update
conico974 Feb 20, 2024
429914a
Squashed commit of the following:
conico974 Mar 10, 2024
5dcb4c2
fix for next 12
conico974 Mar 10, 2024
8be4647
add support for basePath
conico974 Mar 10, 2024
be93d3b
allow customization of sharp runtime
conico974 Mar 11, 2024
63dc3b2
updated edge converter to match behaviour of lambda
conico974 Mar 11, 2024
3a489ad
update version
conico974 Mar 11, 2024
356a573
fix monorepo
conico974 Mar 12, 2024
2932436
improved streaming
conico974 Mar 12, 2024
f1b2b78
update version
conico974 Mar 12, 2024
2ab1717
fix open-next config build that depends on node
conico974 Mar 15, 2024
a2e5491
fix crypto middleware node 20
conico974 Mar 23, 2024
51a2639
Sync
conico974 Mar 23, 2024
059db68
fix resolve in image optimization
conico974 Mar 23, 2024
ae46f82
add better error when edge runtime is used inside node
conico974 Mar 23, 2024
1992b3f
update version
conico974 Mar 23, 2024
52a5127
fix null error on lambda
conico974 Mar 24, 2024
790881d
update version
conico974 Mar 24, 2024
9cff08a
fix 500 on aws-lambda wrapper
conico974 Mar 24, 2024
7f5ba6f
update version
conico974 Mar 24, 2024
daaeb38
fix duplex for request in node
conico974 Mar 27, 2024
90c59d9
fix & refactor middleware response headers
conico974 Mar 27, 2024
93ee01f
update version
conico974 Mar 27, 2024
245c139
Sync
conico974 Apr 4, 2024
e498e28
update version
conico974 Apr 4, 2024
c782117
removed specific lamda streaming hack
conico974 Apr 10, 2024
9f7e108
add geo in middleware
conico974 Apr 10, 2024
3751bf7
added helpers function for config file
conico974 Apr 10, 2024
d0c87c3
fix for 14.2
conico974 Apr 11, 2024
370547b
update version
conico974 Apr 11, 2024
905a6e4
fix redirect lambda streaming
conico974 Apr 11, 2024
8a822cb
fix e2e tests
conico974 Apr 11, 2024
fbfca43
test: improve reliability of test for revalidateTag
conico974 Apr 11, 2024
dae9d98
update version
conico974 Apr 11, 2024
965a014
Sync
conico974 Apr 11, 2024
1df7d78
review fix
conico974 Apr 12, 2024
050b8f5
fix cookies in streaming
conico974 Apr 18, 2024
9cb86cf
make all write to ddb chunked
conico974 Apr 18, 2024
dbb96cf
changeset
conico974 May 3, 2024
52641c1
fix e2e
conico974 May 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .changeset/rotten-trees-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
"open-next": major
---

OpenNext V3

This is the V3 of OpenNext. It includes some breaking changes and cannot be used as a drop-in replacement for V2. If your IAC is using OpenNext V2, you will need to update it to use V3.

If you are using OpenNext V2, please refer to the [migration guide](https://open-next.js.org/migration#from-opennext-v2) to upgrade to V3.

### New Features

- Add support for function splitting
- Add support for external middleware
- Custom config file support : `open-next.config.ts`
- Support for other deployment targets than lambda (Node.js, Docker and partial support for Cloudflare Workers)
- Allow for customizing the outputs bundle :
- Wrapper
- Converter
- Incremental Cache (Fetch cache and HTML/JSON/RSC cache)
- Tag Cache
- Queue (Used to trigger ISR revalidation)
- Origin Resolver (Only for external middleware)
- Image Loader (Only for image optimization)
- Invoke function (For the warmer function)
- Create an `open-next.output.json` file for easier integration with IAC tools

### Breaking Changes

- Edge runtime don't work out of the box anymore. You need to deploy them on a separate function see [the config for more info](https://open-next.js.org/config)
- Output directory structure has changed to support function splitting
- Removed build arguments in favor of `open-next.config.ts`

### Internal Changes

- Use OpenNextNodeResponse instead of ServerResponse (It uses transform stream to properly handle the stream)
- Big refactor of the codebase to support function splitting
- Added new plugins to support the new features and make the codebase more modular
2 changes: 1 addition & 1 deletion docs/pages/inner_workings/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
"caching": "Caching (ISR/SSG)",
"components": "Main Components",
"architecture": "Default Architecture"
}
}
7 changes: 7 additions & 0 deletions docs/pages/v3/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"index": "What's new",
"config": "Configuration file",
"reference-implementation": "Reference Construct",
"requirements": "Requirements",
"override": "Advanced - Create your own override"
}
69 changes: 69 additions & 0 deletions docs/pages/v3/config.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
Here is a simple example of an `open-next.config.ts` file:
This file need to be at the same place as your `next.config.js` file

`server` in here could refer to a lambda function, a docker container, a node server or whatever that can support running nodejs code. (Even cloudflare workers in the future)

For more information about the options here, just look at the source file

```ts
import type { OpenNextConfig } from 'open-next/types/open-next'
const config = {
default: { // This is the default server, similar to the server-function in open-next v2
// You don't have to provide the below, by default it will generate an output
// for normal lambda as in open-next v2
override: {
wrapper: "aws-lambda-streaming", // This is necessary to enable lambda streaming
// You can override any part that is a `LazyLoadedOverride` this way
queue: () => Promise.resolve({
send: async (message) => {
//Your custom code here
}
})
},
},
// Below we define the functions that we want to deploy in a different server
functions: {
ssr: {
routes: [
"app/api/isr/route", "app/api/sse/route", "app/api/revalidateTag/route", // app dir Api routes
"app/route1/page", "app/route2/page", // app dir pages
"pages/route3" // page dir pages
], // For app dir, you need to include route|page, no need to include layout or loading
patterns: ['api/*', 'route1', 'route2', 'route3'], // patterns needs to be in a cloudfront compatible format, this will be used to generate the output
override: {
wrapper: "aws-lambda-streaming",
},
experimentalBundledNextServer: true // This enables the bundled next server which is faster and reduce the size of the server
},
pageSsr: {
Copy link
Contributor

@khuezy khuezy Apr 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct:
ssr => appDir
pageSsr => pagesDir

I'm wondering if people would easily understand/get this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily, you can give whatever name you want here, and you can mix app and page dir as much as you want. The ssr functions for example has a page/route3 route
You can also have as many different functions as you want

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops had a dyslexic typo, should have been is this correct, not this is correct... updated comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how to properly explain these things, but i think with some time and people asking questions about it, we'll figure a proper way to explain it.

routes: ["pages/pageSsr"], // For page dir routes should be in the form `pages/${route}` without the extension, it should match the filesystem
patterns: [ 'pageSsr', "_next/data/BUILD_ID/pageSsr.json"],
override: {
wrapper: "node",
converter: "node",
// This is necessary to generate the dockerfile and for the implementation to know that it needs to deploy on docker
generateDockerfile: true,
},
},
edge: {
runtime: "edge",
routes: ["app/ssr/page"],
patterns: ["ssr"],
override: {}
}
},
// By setting this, it will create another bundle for the middleware,
// and the middleware will be deployed in a separate server.
// If not set middleware will be bundled inside the servers
// It could be in lambda@edge, cloudflare workers, or anywhere else
// By default it uses lambda@edge
// This is not implemented in the reference construct implementation.
middleware: {
external: true
}
buildCommand: "echo 'hello world'",
} satisfies OpenNextConfig

export default config;
export type Config = typeof config
```
67 changes: 67 additions & 0 deletions docs/pages/v3/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Callout } from 'nextra/components'

<Callout type="warning" emoji="⚠️">

`open-next@3.0.0-rc.3` is here!!! Please report any issues you find on [discord](https://discord.com/channels/983865673656705025/1164872233223729152) or on the github [PR](https://github.com/sst/open-next/pull/327)

This is a release candidate, it is mostly ready for production (You might still experience some quirks). We are looking for feedback on this release, so please try it out and let us know what you think. See [getting started](#get-started) to quickly test it.

It also requires an updated version of the IAC tools that you use, see the sst PR [here](https://github.com/sst/sst/pull/3567) for more information.

You could also use SST Ion which should support it out of the box pretty soon. See [here for more info](https://github.com/sst/ion) or in the [ion discord](https://discord.com/channels/983865673656705025/1177071497974648952).
</Callout>

## What's new in V3?

- Rewritten server (We moved from the serverless-http `ServerResponse` into our own version which respect nodejs stream)
- A new `open-next.config.ts` file to configure your project
- Native support for aws lambda, aws lambda streaming, lambda@edge, node and docker
- In this `open-next.config.ts` you can now override a lot of things which allow for more customization:
- Wrapper component
- Converter component
- Incremental Cache
- Tag Cache
- Queue
- Custom warmer function
- Custom revalidation function
- Custom loader for image optimization
- Custom initialization function

- Allow for splitting, you can now split your next app into multiple servers, which could each have their own configuration
- Allow to move the middleware/routing part in a separate lambda or cloudflare workers in front of your server functions
- An experimental bundled `NextServer` could be used which can reduce the size of your lambda by up to 24 MB
- Experimental support for the `edge` runtime of next with some limitations:
- Only app router for now
- Only 1 route per function
- Works fine in node, only for api route in cloudflare workers
- No support for `revalidateTag` or `revalidatePath` for now

## Get started

The easiest way to get started is to use the [reference implementation construct](/v3/reference-implementation). Copy this reference implementation into your project and then use it like that in your sst or cdk project:

```ts
import { OpenNextCdkReferenceImplementation } from "path/to/reference-implementation"

const site = new OpenNextCdkReferenceImplementation(stack, "site", {
openNextPath: ".open-next",
})
```

You also need to create an `open-next.config.ts` file in your project root, you can find more info [here](/v3/config).

A very simple example of this file could be:

```ts
import type { OpenNextConfig } from 'open-next/types/open-next'
const config = {
default: {

}
}
export default config;
```

Then you need to run `npx open-next@3.0.0-rc.3 build` to build your project before running the `sst deploy` or `cdk deploy` command to deploy your project.

In V3 `open-next build` don't accept any arguments, all the args are passed in the `open-next.config.ts` file.
74 changes: 74 additions & 0 deletions docs/pages/v3/override.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
In this version of open-next, you could override a lot of the default behaviour.

For some real example of how to override each behaviour:
- [Wrapper](https://github.com/conico974/open-next/blob/feat/splitting/packages/open-next/src/wrappers/aws-lambda.ts)
- [Converter](https://github.com/conico974/open-next/blob/feat/splitting/packages/open-next/src/converters/aws-apigw-v2.ts)
- [IncrementalCache](https://github.com/conico974/open-next/blob/feat/splitting/packages/open-next/src/cache/incremental/s3.ts)
- [TagCache](
https://github.com/conico974/open-next/blob/feat/splitting/packages/open-next/src/cache/tag/dynamoDb.ts
)
- [Queue](
https://github.com/conico974/open-next/blob/feat/splitting/packages/open-next/src/queue/sqs.ts
)

This means it could allow people to write their own custom open-next.
For example you could create a custom `withGcp` plugin to allow to deploy open-next on GCP functions

A boilerplate for such a plugin could look like this (This is not real code):

```ts

import { OpenNextConfig } from "open-next/types/open-next";

function withGcp(config: TrimmedDownConfig): OpenNextConfig {
return {
default: {
override: {
wrapper: async () => (await import("./gcp-wrapper")).default,
converter: async () => (await import("./gcp-converter")).default,
incrementalCache: async () => (await import("./gcp-incremental-cache")).default,
tagCache: async () => (await import("./gcp-tag-cache")).default,
queue: async () => (await import("./gcp-queue")).default,
},
...config.default,
},
functions: {
// Same as default but for each splitted function
//...
}
warmer: {
override: {
wrapper: async () => (await import("./gcp-wrapper")).default,
converter: async () => (await import("./gcp-converter")).default,
},
invokeFunction: async () => (await import("./gcp-invoke-function")).default,
},
revalidate: {
override: {
wrapper: async () => (await import("./gcp-wrapper")).default,
converter: async () => (await import("./gcp-queue-converter")).default,
},
},
imageOptimization: {
override: {
wrapper: async () => (await import("./gcp-wrapper")).default,
converter: async () => (await import("./gcp-converter")).default,
},
loader: async () => (await import("./gcp-object-loader")).default,
},
}
}
```

Using this plugin would look like this inside `open-next.config.ts`:

```ts
import { withGcp } from "./with-gcp";
const config = withGcp({
default: {
// ...
},
});

export default config;
```
Loading
Loading