Skip to content
This repository was archived by the owner on Feb 1, 2025. It is now read-only.

Commit d8e2475

Browse files
sladgBender
authored and
Bender
committed
ref(rollup): bundling redefined, correctly generate standalone (#29)
* refactor(rollup): properly bundle different entry points, upgrade to node18 * ref(layers): nextjs layer to be pre-build so it can be used by server and image handler * doc: polished and updated documentation * doc: improved description of the project Co-authored-by: Jan Soukup <[email protected]>
1 parent e3b702a commit d8e2475

16 files changed

+1582
-7113
lines changed

Diff for: .autorc

-8
This file was deleted.

Diff for: .github/workflows/deployment.yml

-39
This file was deleted.

Diff for: .github/workflows/pr-check.yml

+20-20
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@ name: 'Check PR for word'
22
on: [pull_request]
33

44
jobs:
5-
check_pr:
6-
runs-on: ubuntu-22.04
7-
strategy:
8-
matrix:
9-
node-version: [16.x]
10-
steps:
11-
- uses: actions/checkout@v2
12-
- name: Use Node.js ${{ matrix.node-version }}
13-
uses: actions/setup-node@v3
14-
with:
15-
node-version: ${{ matrix.node-version }}
16-
cache: 'npm'
17-
- name: Install dependencies
18-
run: npm ci
19-
- uses: kceb/pull-request-url-action@v1
20-
id: pr-url
21-
- name: Validate SemVer
22-
run: npx auto pr-check --url ${{ steps.pr-url.outputs.url }}
23-
env:
24-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5+
check_pr:
6+
runs-on: ubuntu-22.04
7+
strategy:
8+
matrix:
9+
node-version: [16.x]
10+
steps:
11+
- uses: actions/checkout@v2
12+
- name: Use Node.js ${{ matrix.node-version }}
13+
uses: actions/setup-node@v3
14+
with:
15+
node-version: ${{ matrix.node-version }}
16+
cache: 'npm'
17+
- name: Install dependencies
18+
run: npm ci
19+
- uses: kceb/pull-request-url-action@v1
20+
id: pr-url
21+
- name: Validate SemVer
22+
run: npx auto pr-check --url ${{ steps.pr-url.outputs.url }}
23+
env:
24+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Diff for: .github/workflows/publish.yml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
on:
2+
push:
3+
branches: ['release/**']
4+
5+
jobs:
6+
check_pr:
7+
runs-on: ubuntu-22.04
8+
strategy:
9+
matrix:
10+
node-version: [16.x]
11+
steps:
12+
- uses: actions/checkout@v2
13+
- name: Use Node.js ${{ matrix.node-version }}
14+
uses: actions/setup-node@v3
15+
with:
16+
node-version: ${{ matrix.node-version }}
17+
cache: 'npm'
18+
- name: Install dependencies
19+
run: npm ci
20+
- name: Install zip
21+
run: |
22+
sudo apt-get update
23+
sudo apt-get install zip -y
24+
- name: Build & package
25+
run: npm run build
26+
- name: Release
27+
run: npm run release --gitUser @sladg --gitEmail [email protected]
28+
env:
29+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Diff for: .github/workflows/version.yml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
on:
2+
push:
3+
branches: ['master']
4+
5+
jobs:
6+
deployment:
7+
environment: production
8+
runs-on: ubuntu-22.04
9+
strategy:
10+
matrix:
11+
node-version: [16.x]
12+
13+
steps:
14+
- uses: actions/checkout@v3
15+
- name: Prepare repository
16+
run: git fetch --unshallow --tags
17+
- name: Use Node.js ${{ matrix.node-version }}
18+
uses: actions/setup-node@v3
19+
with:
20+
node-version: ${{ matrix.node-version }}
21+
cache: 'npm'
22+
- name: Install dependencies
23+
run: npm ci
24+
- name: Build CLI
25+
run: npm run build:main
26+
- name: Release
27+
run: npm run release --gitUser @sladg --gitEmail [email protected]
28+
env:
29+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Diff for: README.md

+62-61
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,35 @@
11
# NextJS Lambda Utils
22

3-
This is a set of utils needed for deploying NextJS into AWS Lambda.
4-
It includes a wrapper for `next/server/image-optimizer` allowing to use S3.
5-
And includes CLI and custom server handler to integrate with ApiGw.
3+
This is a project allowing to deploy Next applications (standalone options turned on) to AWS Lambda without hassle.
4+
5+
This is an alternative to existing Lambda@Edge implementation ([see](https://www.npmjs.com/package/@sls-next/lambda-at-edge)) as it has too many limitations (primarily inability to use env vars) and deployments take too long.
6+
7+
This library uses Cloudfront, S3, ApiGateway and Lambdas to deploy easily in seconds (hotswap supported).
8+
69

710
- [NextJS Lambda Utils](#nextjs-lambda-utils)
11+
- [TL;DR](#tldr)
812
- [Usage](#usage)
913
- [next.config.js](#nextconfigjs)
1014
- [Server handler](#server-handler)
1115
- [Image handler](#image-handler)
1216
- [Via CDK](#via-cdk)
13-
- [Sharp](#sharp)
17+
- [Sharp layer](#sharp-layer)
18+
- [Next layer](#next-layer)
1419
- [Packaging](#packaging)
1520
- [Server handler](#server-handler-1)
1621
- [Static assets](#static-assets)
1722
- [Versioning](#versioning)
1823
- [Guess](#guess)
1924
- [Shipit](#shipit)
20-
- [TODO](#todo)
2125
- [Disclaimer](#disclaimer)
2226

27+
## TL;DR
28+
- In your NextJS project, set output to standalone.
29+
- Run `npx @sladg/nextjs-lambda pack`
30+
- Prepare CDK ([see](#via-cdk))
31+
- Run `cdk deploy`
32+
2333
## Usage
2434

2535
We need to create 2 lambdas in order to use NextJS. First one is handling pages/api rendering, second is solving image optimization.
@@ -43,72 +53,68 @@ See:
4353

4454
### Server handler
4555

46-
```
47-
next build
56+
This is a Lambda entrypoint to handle non-asset requests. We need a way to start Next in lambda-friendly way and translate ApiGateway event into typical HTTP event. This is handled by server-handler, which sits alongside of next's `server.js` in standalone output.
4857

49-
npx @sladg/nextjs-lambda pack
50-
```
58+
### Image handler
5159

52-
Create new lambda function with NODE_16 runtime in AWS.
60+
Lambda consumes Api Gateway requests, so we need to create ApiGw proxy (v2) that will trigger Lambda.
5361

54-
```
55-
const dependenciesLayer = new LayerVersion(this, 'DepsLayer', {
56-
code: Code.fromAsset(`next.out/dependenciesLayer.zip`),
57-
})
58-
59-
const requestHandlerFn = new Function(this, 'LambdaFunction', {
60-
code: Code.fromAsset(`next.out/code.zip`, { followSymlinks: SymlinkFollowMode.NEVER }),
61-
runtime: Runtime.NODEJS_16_X,
62-
handler: 'server-handler.handler',
63-
layers: [dependenciesLayer],
64-
memorySize: 512,
65-
timeout: Duration.seconds(10),
66-
})
67-
```
62+
Lambda is designed to serve `_next/image*` route in NextJS stack and replaces the default handler so we can optimize caching and memory limits for page renders and image optimization.
6863

69-
### Image handler
64+
### Via CDK
7065

71-
Create new lambda function with NODE_16 runtime in AWS.
66+
See `NextStandaloneStack` construct in `lib/construct.ts`.
7267

68+
You can easily create `cdk/app.ts` and use following code:
7369
```
74-
const sharpLayer: LayerVersion
75-
const assetsBucket: Bucket
76-
77-
const imageHandlerZip = require.resolve('@sladg/nextjs-lambda/image-handler/zip')
78-
79-
const imageOptimizerFn = new Function(this, 'LambdaFunction', {
80-
code: Code.fromAsset(imageHandlerZip),
81-
runtime: Runtime.NODEJS_16_X,
82-
handler: 'image-handler.handler',
83-
layers: [sharpLayer],
84-
memorySize: 1024,
85-
timeout: Duration.seconds(15),
86-
environment: {
87-
S3_BUCKET_SOURCE: assetsBucket.bucketName
88-
}
89-
})
90-
```
70+
#!/usr/bin/env node
71+
import 'source-map-support/register'
72+
import * as cdk from 'aws-cdk-lib'
73+
import * as path from 'path'
9174
92-
Lambda consumes Api Gateway requests, so we need to create ApiGw proxy (v2) that will trigger Lambda.
75+
import { NextStandaloneStack } from '@sladg/nextjs-lambda'
9376
94-
Lambda is designed to serve `_next/image*` route in NextJS stack and replaces the default handler so we can optimize caching and memory limits for page renders and image optimization.
77+
const assetsZipPath = path.resolve(__dirname, '../next.out/assetsLayer.zip')
78+
const codeZipPath = path.resolve(__dirname, '../next.out/code.zip')
79+
const dependenciesZipPath = path.resolve(__dirname, '../next.out/dependenciesLayer.zip')
9580
96-
### Via CDK
81+
const app = new cdk.App()
9782
98-
See `NextStandaloneLambda` construct in `lib/construct.ts`.
99-
This is a complete definition which consumes output of `pack` CLI command. It requires 3 zips (assets, dependencies and code) and exposes get methods for all resources to provide a way to set custom routes, set environment variables, etc.
83+
new NextStandaloneStack(app, 'StandaloneNextjsStack-2', {
84+
assetsZipPath,
85+
codeZipPath,
86+
dependenciesZipPath,
87+
})
88+
```
89+
90+
This imports pre-made construct, you only need to worry about paths to outputed zip files from CLI `pack` command.
91+
92+
> More granular CDK construct coming soon.
10093
10194

102-
### Sharp
95+
### Sharp layer
10396

10497
Besides handler (wrapper) itself, underlying NextJS also requires sharp binaries.
10598
To build those, we use `npm install` with some extra parametes. Then we zip all sharp dependencies and compress it to easily importable zip file.
10699

107100
```
108-
const code = require.resolve('@sladg/nextjs-lambda/sharp-layer')
101+
import { sharpLayerZipPath } from '@sladg/nextjs-lambda'
102+
103+
const sharpLayer = new LayerVersion(this, 'SharpDependenciesLayer', {
104+
code: Code.fromAsset(sharpLayerZipPath)
105+
})
106+
```
107+
108+
### Next layer
109+
110+
To provide both image and server handlers with all depdencies (next is using `require.resolve` inside, so it cannot be bundled standalone for now).
111+
112+
We pre-package this layer so it can be included in Lambda without hassle.
113+
```
114+
import { nextLayerZipPath } from '@sladg/nextjs-lambda'
109115
110-
const sharpLayer = new LayerVersion(this, 'SharpLayer', {
111-
code: Code.fromAsset(code)
116+
const nextLayer = new LayerVersion(this, 'NextDependenciesLayer', {
117+
code: Code.fromAsset(nextLayerZipPath)
112118
})
113119
```
114120

@@ -147,6 +153,8 @@ Cloudfront paths used:
147153
- `_next/*`
148154
- `assets/*`
149155

156+
Keep in minda, Cloudfront does not allow for multiple regex patterns in single origin, so using extensions to distinguish image/server handlers is not doable.
157+
150158
# Versioning
151159

152160
This package exposes two CLI functions intended to deal with versioning your application and releasing.
@@ -164,15 +172,6 @@ Similar to guess command, however, it automatically tags a commit on current bra
164172
Simply call `@sladg/next-lambda shipit` on any branch and be done.
165173

166174

167-
# TODO
168-
169-
- Explain scripts used for packaging Next app,
170-
- Add CDK examples on how to set it up,
171-
- Export CDK contruct for simple plug-n-play use,
172-
- Use lib/index.ts as single entry and export all paths/functions from it (including zip paths).
173-
- Consider using \*.svg, \*.png, \*.jpeg etc. as routing rule for Cloudfront to distinguish between assets and pages.
174-
- Add command for guessing version bumps from git commits & keywords, existing solutions are horendously huge, we just need a simple version bumping.
175-
176175
# Disclaimer
177176

178177
At this point, advanced features were not tested with this setup. This includes:
@@ -184,3 +183,5 @@ At this point, advanced features were not tested with this setup. This includes:
184183
- custom babel configuration.
185184

186185
I am looking for advanced projects implementing those features, so we can test them out! Reach out to me!
186+
187+

0 commit comments

Comments
 (0)