Published on: Sat Jan 14 2023
In this tutorial, we’re going to build on our existing site by adding server-side rendering at the edge.
We’ll be go through the process on how to integrate the Lambda@Edge adapter - @common-web/astro-lambda-edge.
Ultimately, this will allow us to dynamically change the content while maintaining the performance since it will be much closer to the users!
Before we start building, let’s do a review of the architecture.
When we integrate the custom adapter, we’ll have two outputs.
The outputs are:
Client - These are your static assets (ie js
, css
, etc.)
Server - This is your script for running the server
Illustration of Astro build assets mapped to AWS
There are two paths for our Lambda@Edge function:
Illustration of AWS architecture with Astro
💡 How Does it Work ?
Within the adapter package, determine what action to take (forward to S3 or perform SSR) based on the file extension of the the request.
If you interested in learning more about how I went about building this adapter be sure to check out my article - Astro: Building the Lambda@Edge Adapter.
Ok... Now that we have a good high level overview of what needs to be done — Let’s actually build this thing!
⚡️ Important:
To streamline the process and remove boilerplate code, please use Jareechang/astro-lambda-edge-starter!
pnpm install @common-web/astro-lambda-edge -D
Note: You can use npm
or yarn
too
Make the following changes:
import { defineConfig } from 'astro/config';
import tailwind from '@astrojs/tailwind';
import react from '@astrojs/react';
import lambdaEdgeAdapter from '@common-web/astro-lambda-edge';
// https://astro.build/config
export default defineConfig({
integrations: [tailwind(), react()],
output: 'server',
vite: {
build: {
target: ['node16.0.0'],
manifest: true,
}
},
output: 'server',
adapter: lambdaEdgeAdapter()
});
Run the following:
touch .env
Add the unsplash credentials:
UNSPLASH_API_KEY=<api-key>
Note: This will allow the Astro site to render images on the page
Under your root, run the following:
./scripts/generate-lambda-assets.sh
This is mostly just installing, building, and packaging everything into a zip file.
After completing the process, you should see a main.zip
file appear in your project directory.
⚠️ Important:Make sure the zip file is under 50 Mb. This is the size limit for lambda zip files.
You can check by running du -sh ./main.zip.
Now that we have our main.zip
, it is time to incoporate these assets into our AWS Architecture.
If you want a review, be sure to re-visit the visual above - Architecture - Build Output.
This bucket will be where we keep our main.zip
file.
# infra/main.tf
resource "aws_s3_bucket" "lambda_bucket" {
bucket = "${local.s3_lambda_assets_id}-123423"
}
We’ll be using a local lambda module to create the Lambda@edge function.
# infra/main.tf
module "lambda_edge_rendering" {
source = "./modules/lambda"
code_src = "../main.zip"
bucket_id = aws_s3_bucket.lambda_bucket.id
timeout = local.default_lambda_timeout
function_name = "Edge-rendering-function"
runtime = "nodejs16.x"
handler = "dist/server/entry.handler"
publish = true
alias_name = "edge-rendering-dev"
alias_description = "Alias for edge rendering function"
}
❗️Note:Notice how we are referencing main.zip in code_src and the handler is referencing an handler method exported from the build.
The "event type" that we will be using is the origin-request
.
This means Cloudfront will run this function before it proceeds to our origin server.
# infra/main.tf
resource "aws_cloudfront_distribution" "cf_distribution" {
# Other code are omitted for brevity
default_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = local.s3_origin_id
viewer_protocol_policy = "redirect-to-https"
min_ttl = local.min_ttl
default_ttl = local.default_ttl
max_ttl = local.max_ttl
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
lambda_function_association {
event_type = "origin-request"
lambda_arn = module.lambda_edge_rendering.lambda[0].qualified_arn
include_body = true
}
}
}
Now that we have all our definitions in Terraform, all that is left is to generate it.
Run the following:
export AWS_ACCESS_KEY_ID=<your-key>
export AWS_SECRET_ACCESS_KEY=<your-secret>
export AWS_DEFAULT_REGION=us-east-1
terraform init
terraform plan
terraform apply -auto-approve
There is one more thing we need to do.
Remember the other S3 bucket ?
In our architecture, our Cloudfront distribution will use this S3 bucket as the origin server.
So, that means we’ll need to upload our site assets to the S3 bucket.
Run the following:
aws s3 sync ./dist/client s3://astro-static-site-123423
Note: Make sure you change the S3 bucket name in this script if you’ve changed it in terraform.
Now visit the Cloudfront url, and the site should now start performing server-rendering at the edge!
Illustration of Lambda@Edge end results
For reference, here is the repository of completed tutorial - Github: astro-lambda-edge-adapter-tutorial.
There you have it!
That’s a quick tutorial on how to use the Astro lambda@Edge adapter - @common-web/astro-lambda-edge.
Got questions or feedback ? Feel free to reach out to me!
If you found this helpful or learned something new, please do share this article with a friend or co-worker 🙏❤️ (Thanks!)
Then consider signing up to get notified when new content arrives!