Skip to content

Commit 2affd71

Browse files
committed
add cdk support
1 parent c52b9a1 commit 2affd71

File tree

4 files changed

+661
-71
lines changed

4 files changed

+661
-71
lines changed

README.md

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# adapter-lambda for SvelteKit
22

3-
An adapter to build a [SvelteKit](https://kit.svelte.dev/) app into a lambda ready for deployment with lambda proxy via the Serverless framework.
3+
An adapter to build a [SvelteKit](https://kit.svelte.dev/) app into a lambda ready for deployment with lambda proxy via the Serverless framework or CDK.
44

55
## Installation
66
```
77
npm install --save-dev @yarbsemaj/adapter-lambda
88
```
99
## Usage
1010

11-
In your `svelte.config.js` configure the adapter as bellow;
11+
In your `svelte.config.js` configure the adapter as below;
1212

1313
```js
1414
import preprocess from 'svelte-preprocess'; //Optional
@@ -26,14 +26,24 @@ const config = {
2626

2727
export default config;
2828
```
29+
30+
### For serverless
2931
Copy `serverless.yml` from the root of this repo to the root of your project, make sure to change the service name.
3032

3133
After building your app run `sls deploy` to deploy code to AWS using the build tool [serverless](https://www.serverless.com/).
3234

33-
Your app can then be accessed via the CloudFront distribution created as a part of the stack.
35+
### For CDK
36+
Copy `SvelteKitSite.ts` from the root of this repo into your project and add it to a CDK stack.
37+
38+
Deploy your stack using `cdk deploy --all`
39+
40+
An example project using cdk can be found [here](https://github.com/yarbsemaj/sveltekit-cdk-starter).
41+
42+
### Tada 🎉
43+
No matter how you deploy, your app can then be accessed via the CloudFront distribution created as a part of the stack.
3444

3545
## Static Assets and precompiled pages
36-
To server static assets and precompiled pages this adapter makes use of S3. In order to route traffic the correct destination a Lambda@edge fuction is used to perfrom a origin rewrite to redirect traffic to the S3 Bucket.
46+
To server static assets and precompiled pages, this adapter makes use of S3. In order to route traffic to the correct destination a Lambda@edge function is used to perform an origin rewrite to redirect traffic to the S3 Bucket.
3747

3848
## Infrastructure Diagram
3949
![Infra](https://github.com/yarbsemaj/sveltekit-adapter-lambda/blob/master/docs/assets/diagram.png?raw=true)
@@ -45,7 +55,7 @@ Please raise an issue on [Github](https://github.com/yarbsemaj/sveltekit-adapter
4555
## Versions
4656
| Adapter Version| Sveltekit Version |
4757
| ---------------| ----------------- |
48-
| 1.1.x | 1.22.0 (Official) |
58+
| 1.1.x - 1.2.x | 1.22.0 (Official) |
4959
| 1.x.x | 1.0.0 (Official) |
5060
| 0.12.x | 1.0.0-next.433 |
5161
| 0.11.x | 1.0.0-next.401 |

SvelteKitSite.ts

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import * as cdk from 'aws-cdk-lib';
2+
import { Duration } from 'aws-cdk-lib';
3+
import { CacheCookieBehavior, CacheHeaderBehavior, CacheQueryStringBehavior, OriginRequestCookieBehavior, OriginRequestHeaderBehavior, OriginRequestQueryStringBehavior, ViewerProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
4+
import { Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam';
5+
import { FunctionUrlAuthType } from 'aws-cdk-lib/aws-lambda';
6+
import { BlockPublicAccess, BucketAccessControl } from 'aws-cdk-lib/aws-s3';
7+
import { Construct } from 'constructs';
8+
import path from 'path'
9+
10+
const __dirname = process.cwd();
11+
12+
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
13+
14+
15+
export type SveltekitSiteProps = {
16+
lambdaProps?: PartialBy<Omit<cdk.aws_lambda.FunctionProps, 'code' | 'runtime' | 'handler'>, 'architecture' | 'timeout' | 'memorySize'>;
17+
cloudfrontProps?: Omit<cdk.aws_cloudfront.DistributionProps, 'defaultBehavior'> & {
18+
defaultBehavior: Omit<cdk.aws_cloudfront.BehaviorOptions, 'origin'>
19+
};
20+
}
21+
22+
export class SvelteKitSite extends Construct {
23+
public svelteLambda : cdk.aws_lambda.Function
24+
public cloudfrontDistribution: cdk.aws_cloudfront.Distribution
25+
constructor(scope: Construct, id: string, props?: SveltekitSiteProps) {
26+
super(scope, id);
27+
28+
const svelte = new cdk.aws_lambda.Function(this, `${id}-svelte-lambda`, {
29+
runtime: cdk.aws_lambda.Runtime.NODEJS_18_X,
30+
architecture: cdk.aws_lambda.Architecture.ARM_64,
31+
memorySize: 1024,
32+
timeout: Duration.seconds(10),
33+
handler: 'serverless.handler',
34+
code: cdk.aws_lambda.Code.fromAsset(path.join(__dirname, './build/server')),
35+
...props?.lambdaProps,
36+
});
37+
38+
const svelteURL = svelte.addFunctionUrl({ authType: FunctionUrlAuthType.NONE })
39+
40+
const edgeFunction = new cdk.aws_cloudfront.experimental.EdgeFunction(this, `${id}-svelte-lambda-edge`, {
41+
runtime: cdk.aws_lambda.Runtime.NODEJS_18_X,
42+
handler: 'router.handler',
43+
memorySize: 128,
44+
code: cdk.aws_lambda.Code.fromAsset(path.join(__dirname, './build/edge')),
45+
});
46+
47+
const staticAssets = new cdk.aws_s3.Bucket(this, `${id}-static-asset-bucket`, {
48+
blockPublicAccess: BlockPublicAccess.BLOCK_ACLS,
49+
accessControl: BucketAccessControl.BUCKET_OWNER_FULL_CONTROL,
50+
})
51+
52+
staticAssets.addToResourcePolicy(new PolicyStatement({
53+
actions: ['s3:GetObject'],
54+
effect: Effect.ALLOW,
55+
resources: [staticAssets.arnForObjects('*')],
56+
sid: 'PublicReadGetObject',
57+
principals: [new cdk.aws_iam.AnyPrincipal()]
58+
}))
59+
60+
const forwardHeaderFunction = new cdk.aws_cloudfront.Function(this, `${id}-forward-header-function`, {
61+
code: cdk.aws_cloudfront.FunctionCode.fromInline('function handler(event) { return event.request }'),
62+
});
63+
64+
new cdk.aws_s3_deployment.BucketDeployment(this, `${id}-deploy-prerender`, {
65+
sources: [cdk.aws_s3_deployment.Source.asset(path.join(__dirname, './build/prerendered'))],
66+
destinationBucket: staticAssets,
67+
prune: false,
68+
cacheControl: [
69+
cdk.aws_s3_deployment.CacheControl.maxAge(Duration.minutes(5)),
70+
],
71+
});
72+
73+
new cdk.aws_s3_deployment.BucketDeployment(this, `${id}-deploy-assets`, {
74+
sources: [cdk.aws_s3_deployment.Source.asset(path.join(__dirname, './build/assets/'))],
75+
destinationBucket: staticAssets,
76+
prune: false,
77+
cacheControl: [
78+
cdk.aws_s3_deployment.CacheControl.maxAge(Duration.days(365)),
79+
cdk.aws_s3_deployment.CacheControl.immutable(),
80+
],
81+
});
82+
83+
new cdk.aws_s3_deployment.BucketDeployment(this, `${id}-deploy-static`, {
84+
sources: [cdk.aws_s3_deployment.Source.asset(path.join(__dirname, './build/assets/_app'))],
85+
destinationBucket: staticAssets,
86+
destinationKeyPrefix: '_app',
87+
prune: false,
88+
cacheControl: [
89+
cdk.aws_s3_deployment.CacheControl.maxAge(Duration.days(365)),
90+
cdk.aws_s3_deployment.CacheControl.immutable(),
91+
],
92+
});
93+
94+
95+
const distribution = new cdk.aws_cloudfront.Distribution(this, `${id}-svelte-cloudfront`, {
96+
...props?.cloudfrontProps,
97+
defaultBehavior: {
98+
allowedMethods: cdk.aws_cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
99+
origin: new cdk.aws_cloudfront_origins.HttpOrigin(cdk.Fn.select(2, cdk.Fn.split('/', svelteURL.url)), {
100+
customHeaders: {
101+
's3-host': staticAssets.virtualHostedUrlForObject().replace('https://', '')
102+
}
103+
}),
104+
viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
105+
compress: true,
106+
originRequestPolicy: new cdk.aws_cloudfront.OriginRequestPolicy(this, `${id}-svelte-orp`, {
107+
cookieBehavior: OriginRequestCookieBehavior.all(),
108+
queryStringBehavior: OriginRequestQueryStringBehavior.all(),
109+
headerBehavior: OriginRequestHeaderBehavior.allowList('x-forwarded-host')
110+
}),
111+
cachePolicy: new cdk.aws_cloudfront.CachePolicy(this, `${id}-svelte-cp`, {
112+
cookieBehavior: CacheCookieBehavior.all(),
113+
queryStringBehavior: CacheQueryStringBehavior.all(),
114+
headerBehavior: CacheHeaderBehavior.allowList('x-forwarded-host'),
115+
enableAcceptEncodingBrotli: true,
116+
enableAcceptEncodingGzip: true
117+
}),
118+
...props?.cloudfrontProps?.defaultBehavior,
119+
edgeLambdas: [
120+
{
121+
functionVersion: edgeFunction.currentVersion,
122+
eventType: cdk.aws_cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST,
123+
},
124+
...(props?.cloudfrontProps?.defaultBehavior?.edgeLambdas || [])
125+
],
126+
functionAssociations: [{
127+
function: forwardHeaderFunction,
128+
eventType: cdk.aws_cloudfront.FunctionEventType.VIEWER_REQUEST,
129+
},
130+
...(props?.cloudfrontProps?.defaultBehavior?.functionAssociations || [])
131+
],
132+
},
133+
});
134+
135+
this.svelteLambda = svelte
136+
this.cloudfrontDistribution = distribution
137+
}
138+
}

0 commit comments

Comments
 (0)