Last active
January 16, 2025 14:21
-
-
Save antstanley/4bbc1683d248767e86df9e77063094ab to your computer and use it in GitHub Desktop.
Run SvelteKit in AWS Lambda - cdk stack, bundle script and SvelteKit config. Uses SvelteKit's Node.js adapter and Lambda Web Adapter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /bin/bash | |
# - Clear out the dist folder | |
# - Create new empty folder called svelteKit that will be bundled | |
# - Run 'vite build' to create production bundle | |
# - Create run.sh file to be invoked by Lambda using the Lambda Web Adapter | |
# - Change permissions on newly create run.sh file to allow execution | |
# - Create package.json file with { "type": "module" } property to ensure all js files use ESM | |
rm -rf dist | |
mkdir -vp dist/svelteKit | |
vite build | |
echo "Creating run.sh" | |
printf "#! /bin/bash\nnode index.js" > dist/svelteKit/run.sh | |
chmod +x dist/svelteKit/run.sh | |
echo "Creating package.json" | |
printf '{ "type": "module" }' > dist/svelteKit/package.json |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as cdk from "aws-cdk-lib"; | |
import { SvelteKitStack, SvelteKitStackProps } from "./svelteKitStack"; | |
import { SSLCertStack } from "./sslStack"; | |
const stackName = "myStack"; | |
const region = process.env.CDK_DEFAULT_REGION ?? process.env.AWS_REGION; | |
const account = process.env.CDK_DEFAULT_ACCOUNT ?? process.env.AWS_ACCOUNT; | |
const sslStackProps = { | |
env: { | |
region: "us-east-1", // Region MUST be us-east-1 for the SSL certificate | |
account, | |
}, | |
variables: { rootDomain: "yourdomain.com", subDomain: "www" }, | |
}; | |
const app = new cdk.App(); | |
const sslStack = new SSLCertStack(app, `${stackName}-ssl`, sslStackProps); | |
const svelteKitStackProps: SvelteKitStackProps = { | |
variables: { | |
domainName: "www.yourdomain.com", | |
lwaArn: `arn:aws:lambda:${region}:753240598075:layer:LambdaAdapterLayerX86:24`, | |
}, | |
crossRegionReferences: true, | |
stacks: { sslStack }, | |
env: { region, account }, | |
}; | |
new SvelteKitStack(app, stackName, svelteKitStackProps); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as cdk from 'aws-cdk-lib' | |
import * as acm from 'aws-cdk-lib/aws-certificatemanager' | |
import * as route53 from 'aws-cdk-lib/aws-route53' | |
import { Construct } from 'constructs' | |
interface SSLCertStackProps extends cdk.StackProps { | |
variables: { | |
rootDomain: string | |
subDomain?: string | |
} | |
} | |
export class SSLCertStack extends cdk.Stack { | |
public readonly certificate: acm.Certificate | |
public readonly rootDomain: string | |
public readonly subDomain?: string | |
constructor(scope: Construct, id: string, props: SSLCertStackProps) { | |
super(scope, id, props) | |
const { rootDomain, subDomain } = props.variables | |
const hasSubDomain = typeof subDomain === 'string' | |
const hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', { | |
domainName: rootDomain | |
}) | |
this.rootDomain = rootDomain | |
this.subDomain = subDomain | |
this.certificate = new acm.Certificate(this, 'Certificate', { | |
domainName: hasSubDomain ? `*.${rootDomain}` : rootDomain, | |
validation: acm.CertificateValidation.fromDns(hostedZone) | |
}) | |
new cdk.CfnOutput(this, 'CertificateArn', { | |
value: this.certificate.certificateArn | |
}) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import adapter from '@sveltejs/adapter-node' | |
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' | |
/** @type {import('@sveltejs/kit').Config}*/ | |
const config = { | |
kit: { | |
adapter: adapter({ | |
out: 'dist/svelteKit' | |
}) | |
}, | |
preprocess: sequence([vitePreprocess()]) | |
} | |
export default config |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as cdk from "aws-cdk-lib"; | |
import * as cloudfront from "aws-cdk-lib/aws-cloudfront"; | |
import * as origins from "aws-cdk-lib/aws-cloudfront-origins"; | |
import * as lambda from "aws-cdk-lib/aws-lambda"; | |
import * as logs from "aws-cdk-lib/aws-logs"; | |
import * as route53 from "aws-cdk-lib/aws-route53"; | |
import * as targets from "aws-cdk-lib/aws-route53-targets"; | |
import { Construct } from "constructs"; | |
import * as path from "node:path"; | |
import type { SSLCertStack } from "./sslStack"; | |
export interface SvelteKitStackProps extends cdk.StackProps { | |
variables: { | |
domainName: string; | |
environmentName: string; | |
lwaArn: string; // https://github.com/awslabs/aws-lambda-web-adapter | |
}; | |
stacks: { | |
sslStack: SSLCertStack; | |
}; | |
} | |
export class SvelteKitStack extends cdk.Stack { | |
constructor(scope: Construct, id: string, props: SvelteKitStackProps) { | |
super(scope, id, props); | |
const { lwaArn, domainName } = props.variables; | |
const { sslStack } = props.stacks; | |
const { stackName } = props; | |
// adding lambda layer https://github.com/awslabs/aws-lambda-web-adapter | |
const webAdapterLayer = lambda.LayerVersion.fromLayerVersionArn( | |
this, | |
"LambdaWebAdapter", | |
lwaArn, | |
); | |
const svelteKitFn = new lambda.Function(this, "SvelteKit", { | |
runtime: lambda.Runtime.NODEJS_20_X, | |
code: lambda.Code.fromAsset( | |
path.join(__dirname, "..", "dist", "svelteKit"), | |
), | |
handler: "run.sh", | |
timeout: cdk.Duration.seconds(29), | |
memorySize: 256, | |
layers: [webAdapterLayer], | |
logRetention: logs.RetentionDays.ONE_WEEK, | |
environment: { | |
AWS_LAMBDA_EXEC_WRAPPER: "/opt/bootstrap", | |
PORT: "8080", | |
ORIGIN: `https://${domainName}`, | |
}, | |
}); | |
const svelteKitFnUrl = svelteKitFn.addFunctionUrl({ | |
authType: lambda.FunctionUrlAuthType.NONE, | |
}); | |
const svelteKitOrigin = new origins.HttpOrigin( | |
cdk.Fn.select(2, cdk.Fn.split("/", svelteKitFnUrl.url)), | |
); | |
const cloudFront = new cloudfront.Distribution(this, "CloudFront", { | |
domainNames: [domainName], | |
certificate: sslStack.certificate, | |
defaultBehavior: { | |
origin: svelteKitOrigin, | |
allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS, | |
}, | |
}); | |
const hostedZone = route53.HostedZone.fromLookup( | |
this, | |
"cloudFrontHostedZone", | |
{ | |
domainName: sslStack.rootDomain, | |
}, | |
); | |
new route53.ARecord(this, "cloudFrontHostedZoneSiteRecord", { | |
recordName: domainName, | |
zone: hostedZone, | |
target: route53.RecordTarget.fromAlias( | |
new targets.CloudFrontTarget(cloudFront), | |
), | |
}); | |
new cdk.CfnOutput(this, "CloudFrontDomainName", { | |
value: cloudFront.domainName, | |
}); | |
new cdk.CfnOutput(this, "CustomDomainName", { | |
value: domainName, | |
exportName: `${stackName}-custom-domain`, | |
}); | |
new cdk.CfnOutput(this, "svelteKitFnArn", { | |
value: svelteKitFn.functionArn, | |
}); | |
new cdk.CfnOutput(this, "svelteKitFnUrl", { | |
value: svelteKitFnUrl.url, | |
exportName: `${stackName}-url`, | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment