Astro: Going to the edge

Published on: Sat Jan 14 2023

Series

Content

Introduction

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.

Architecture

Build output

When we integrate the custom adapter, we’ll have two outputs.

The outputs are:

  1. Client - These are your static assets (ie js , css , etc.)

  2. Server - This is your script for running the server

Illustration of Astro build assets mapped to AWS
Illustration of Astro build assets mapped to AWS

AWS architecture

There are two paths for our Lambda@Edge function:

  1. Perform Server-side rendering (SSR)
  2. Forward to S3 bucket
Illustration of AWS architecture with Astro
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.

Integrating the 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!

1. Install the adapter package

pnpm install @common-web/astro-lambda-edge -D

Note: You can use npm or yarn too

2. Update astro.config.mjs

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()
});

3. Add environment variable

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

4. Run the script to generate the lambda assets

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.

AWS Architecture

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.

1. Add S3 bucket for the Lambda assets

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"
}

2. Create the Lambda function

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.

3. Add function to Cloudfront distribution

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
    }
  }
}

4. Apply the infrastructure

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

5. Final step

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.

Trying it out

Now visit the Cloudfront url, and the site should now start performing server-rendering at the edge!

Illustration of Lambda@Edge end results
Illustration of Lambda@Edge end results

For reference, here is the repository of completed tutorial - Github: astro-lambda-edge-adapter-tutorial.

Conclusion

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!)


Enjoy the content ?

Then consider signing up to get notified when new content arrives!

Jerry Chang 2023. All rights reserved.