Skip to content

Commit dd91ab1

Browse files
committed
feat: baseline for the plugin
0 parents  commit dd91ab1

File tree

9 files changed

+1121
-0
lines changed

9 files changed

+1121
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
16

LICENCE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2022 Christian Musa
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.
22+

README.md

Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
# AWS Lambda & Next.js serverless plugin
2+
3+
Plugin that helps to deploy a Next.js app using Cloudfront, API Gateway and Lambda. The plugin acts as a basic layer between a normal Next.js app, using the standalone mode and translating the API Gateway requests into the format supported by the framework.
4+
5+
It sits on top of the serverless framework and uses the aws-cli to upload the assets.
6+
7+
## Usage
8+
9+
1. Add the required dependencies
10+
11+
```sh
12+
yarn add -D serverless lambda-nextjs-serverless-plugin
13+
```
14+
15+
2. Add a `serverless.yml` file (feel free to extend/adapt it beyond this basic template)
16+
17+
```yml
18+
service: { your-service-name }
19+
20+
frameworkVersion: "3"
21+
22+
package:
23+
individually: true
24+
excludeDevDependencies: false
25+
patterns:
26+
- "!**/*"
27+
- "package.json"
28+
29+
provider:
30+
name: aws
31+
runtime: nodejs16.x
32+
region: us-east-1
33+
memorySize: 1024
34+
timeout: 29
35+
deploymentMethod: direct
36+
versionFunctions: false
37+
38+
functions:
39+
nextjs-handler:
40+
handler: .next/standalone/bridge.handler
41+
description: Next.js bridge handler
42+
events:
43+
- http: GET /
44+
- http: GET /{uri+}
45+
- http: GET /_next/data/{uri+}
46+
- http: POST /api/{uri+}
47+
package:
48+
patterns:
49+
- ".next/standalone/**"
50+
51+
resources:
52+
Resources:
53+
StaticFilesBucket:
54+
Type: AWS::S3::Bucket
55+
Properties:
56+
BucketName: static-${self:service}-${opt:stage}
57+
58+
CloudfrontToBucketAccessIdentity:
59+
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
60+
Properties:
61+
CloudFrontOriginAccessIdentityConfig:
62+
Comment: ${self:service}-${opt:stage}
63+
64+
StaticFilesBucketPolicy:
65+
Type: AWS::S3::BucketPolicy
66+
Properties:
67+
Bucket:
68+
Ref: StaticFilesBucket
69+
PolicyDocument:
70+
Statement:
71+
- Sid: OriginAccess
72+
Effect: Allow
73+
Principal:
74+
AWS:
75+
Fn::Join:
76+
- " "
77+
- - arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity
78+
- Ref: CloudfrontToBucketAccessIdentity
79+
Action:
80+
- s3:GetObject
81+
Resource:
82+
Fn::Join:
83+
- ""
84+
- - Fn::GetAtt:
85+
- StaticFilesBucket
86+
- Arn
87+
- /*
88+
89+
CloudfrontGateway:
90+
Type: AWS::CloudFront::Distribution
91+
Properties:
92+
DistributionConfig:
93+
Enabled: true
94+
HttpVersion: http2
95+
IPV6Enabled: true
96+
Comment: ${self:service} ${opt:stage}
97+
DefaultCacheBehavior:
98+
AllowedMethods:
99+
- HEAD
100+
- DELETE
101+
- POST
102+
- GET
103+
- OPTIONS
104+
- PUT
105+
- PATCH
106+
CachedMethods:
107+
- GET
108+
- HEAD
109+
- OPTIONS
110+
Compress: true
111+
DefaultTTL: 0
112+
ForwardedValues:
113+
QueryString: true
114+
Headers:
115+
- Accept-Language
116+
- Cloudfront-Viewer-Country
117+
Cookies:
118+
Forward: all
119+
MaxTTL: 0
120+
MinTTL: 0
121+
TargetOriginId: lambda-handler
122+
ViewerProtocolPolicy: redirect-to-https
123+
CacheBehaviors:
124+
- PathPattern: robots.txt
125+
AllowedMethods:
126+
- HEAD
127+
- GET
128+
CachedMethods:
129+
- GET
130+
- HEAD
131+
Compress: true
132+
DefaultTTL: 86400
133+
ForwardedValues:
134+
QueryString: false
135+
Cookies:
136+
Forward: none
137+
MaxTTL: 31536000
138+
MinTTL: 0
139+
TargetOriginId: s3-static-public
140+
ViewerProtocolPolicy: allow-all
141+
- PathPattern: manifest.json
142+
AllowedMethods:
143+
- HEAD
144+
- GET
145+
CachedMethods:
146+
- GET
147+
- HEAD
148+
Compress: true
149+
DefaultTTL: 86400
150+
ForwardedValues:
151+
QueryString: false
152+
Cookies:
153+
Forward: none
154+
MaxTTL: 31536000
155+
MinTTL: 0
156+
TargetOriginId: s3-static-public
157+
ViewerProtocolPolicy: allow-all
158+
- PathPattern: favicon.ico
159+
AllowedMethods:
160+
- HEAD
161+
- GET
162+
CachedMethods:
163+
- GET
164+
- HEAD
165+
Compress: true
166+
DefaultTTL: 86400
167+
ForwardedValues:
168+
QueryString: false
169+
Cookies:
170+
Forward: none
171+
MaxTTL: 31536000
172+
MinTTL: 0
173+
TargetOriginId: s3-static-public
174+
ViewerProtocolPolicy: allow-all
175+
- PathPattern: service-worker.js
176+
AllowedMethods:
177+
- HEAD
178+
- GET
179+
CachedMethods:
180+
- GET
181+
- HEAD
182+
Compress: true
183+
DefaultTTL: 86400
184+
ForwardedValues:
185+
QueryString: false
186+
Cookies:
187+
Forward: none
188+
MaxTTL: 31536000
189+
MinTTL: 0
190+
TargetOriginId: s3-static-public
191+
ViewerProtocolPolicy: allow-all
192+
- PathPattern: static/*
193+
AllowedMethods:
194+
- HEAD
195+
- GET
196+
CachedMethods:
197+
- GET
198+
- HEAD
199+
Compress: true
200+
DefaultTTL: 86400
201+
ForwardedValues:
202+
QueryString: false
203+
Cookies:
204+
Forward: none
205+
MaxTTL: 31536000
206+
MinTTL: 0
207+
TargetOriginId: s3-static-root
208+
ViewerProtocolPolicy: allow-all
209+
- PathPattern: _next/data/*
210+
AllowedMethods:
211+
- HEAD
212+
- GET
213+
CachedMethods:
214+
- GET
215+
- HEAD
216+
Compress: true
217+
DefaultTTL: 0
218+
ForwardedValues:
219+
QueryString: true
220+
Headers:
221+
- Accept-Language
222+
- Cloudfront-Viewer-Country
223+
Cookies:
224+
Forward: all
225+
MaxTTL: 0
226+
MinTTL: 0
227+
TargetOriginId: lambda-handler
228+
ViewerProtocolPolicy: allow-all
229+
- PathPattern: _next/*
230+
AllowedMethods:
231+
- HEAD
232+
- GET
233+
CachedMethods:
234+
- GET
235+
- HEAD
236+
Compress: true
237+
DefaultTTL: 86400
238+
ForwardedValues:
239+
QueryString: false
240+
Cookies:
241+
Forward: none
242+
MaxTTL: 31536000
243+
MinTTL: 0
244+
TargetOriginId: s3-static-root
245+
ViewerProtocolPolicy: allow-all
246+
Origins:
247+
- DomainName:
248+
Fn::Join:
249+
- ""
250+
- - Ref: StaticFilesBucket
251+
- .s3.
252+
- Ref: AWS::URLSuffix
253+
Id: s3-static-root
254+
S3OriginConfig:
255+
OriginAccessIdentity:
256+
Fn::Join:
257+
- ""
258+
- - origin-access-identity/cloudfront/
259+
- Ref: CloudfrontToBucketAccessIdentity
260+
- DomainName:
261+
Fn::Join:
262+
- ""
263+
- - Ref: StaticFilesBucket
264+
- .s3.
265+
- Ref: AWS::URLSuffix
266+
Id: s3-static-public
267+
OriginPath: /public
268+
S3OriginConfig:
269+
OriginAccessIdentity:
270+
Fn::Join:
271+
- ""
272+
- - origin-access-identity/cloudfront/
273+
- Ref: CloudfrontToBucketAccessIdentity
274+
- DomainName:
275+
Fn::Join:
276+
- ""
277+
- - Ref: ApiGatewayRestApi
278+
- .execute-api.${self:provider.region}.
279+
- Ref: AWS::URLSuffix
280+
OriginPath: /${opt:stage}
281+
Id: lambda-handler
282+
CustomOriginConfig:
283+
OriginProtocolPolicy: https-only
284+
OriginSSLProtocols:
285+
- TLSv1.2
286+
- TLSv1.1
287+
- TLSv1
288+
PriceClass: PriceClass_100
289+
ViewerCertificate:
290+
CloudFrontDefaultCertificate: "true"
291+
292+
plugins:
293+
- serverless-offline
294+
- lambda-nextjs-serverless-plugin
295+
```
296+
297+
3. Enable `standalone` flag in `next.config.js`
298+
299+
```js
300+
const nextConfig = {
301+
// ...,
302+
output: "standalone",
303+
};
304+
```
305+
306+
_The format above works for Next.js v12.2, for earlier versions the output needs to be enabled using the experimental flag._
307+
308+
## Roadmap
309+
310+
- [ ] Use the standalone output configuration for calling `NextServer`
311+
- [ ] Create resources automatically to reduce serverless.yml boilerplate
312+
- [ ] Remove dependency to aws-cli sync command
313+
- [ ] Assets uploading has a chicken-egg situation if it's the first deployment
314+
315+
### Feature parity
316+
317+
- [ ] Add support for the next/image component
318+
319+
## Credits
320+
321+
- Uses [`serverless-http`](https://www.npmjs.com/package/serverless-http) for the heavy lifting of converting the API Gateway to a Next.js req/res object (and the opposite).

package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "lambda-nextjs-serverless-plugin",
3+
"version": "1.0.0",
4+
"main": "src/index.js",
5+
"license": "MIT",
6+
"dependencies": {
7+
"serverless-http": "^3.0.1",
8+
"webpack": "^5.73.0"
9+
}
10+
}

0 commit comments

Comments
 (0)