Simulating AWS CDK bucket deployment on localhost with Yulin

AWS CDK has a bucket deployment feature which automatically copies files from a local filesystem directory to an S3 Bucket during CDK deployment.

You can simulate this behaviour for tests and local development with the Yulin AWS simulator npm package.

A minimal CDK setup might look like this:

import * as cdk from "aws-cdk-lib";
import * as s3 from "aws-cdk-lib/aws-s3";
import * as s3deploy from "aws-cdk-lib/aws-s3-deployment";

const app = new cdk.App();

const stack = new cdk.Stack(app, "FooStack");

const bucket = new s3.Bucket(stack, "SiteBucket", {
  bucketName: "foo-bucket",
  websiteIndexDocument: "index.html",
});

new s3deploy.BucketDeployment(stack, "DeploySite", {
  sources: [s3deploy.Source.asset("path/to/public")],
  destinationBucket: bucket,
  prune: true,
});

app.synth();

The s3deploy.BucketDeployment resource sets up the automatic creation of S3 Objects based on the contents of a directory on the local filesystem.

Running cdk synth on that CDK app produces a CloudFormation output JSON template file under the cdk.out directory. You can deploy that template into a simulated AWS environment with Yulin:

import { SimAws } from "@kensio/yulin";

const simAws = new SimAws();

await simAws
  .cloudFormation()
  .deployTemplateFile("cdk.out/FooStack.template.json");

That automatically interprets the AWS::S3::Bucket and Custom::CDKBucketDeployment resources in the output template from CDK. The files in the specified path/to/public directory now exist as Objects in the simulated S3 Bucket, and can be served from the simulated S3 static website hosting.

A fuller example including a localhost server:

import { SimAws } from "@kensio/yulin";
import { serveSimAws } from "@kensio/yulin/serve";

const simAws = new SimAws();
const srv = await serveSimAws({ simAws });

try {
  await simAws
    .cloudFormation()
    .deployTemplateFile("cdk.out/FooStack.template.json");

  const response = await fetch(
    `http://foo-bucket.s3-website.us-east-1.sim-aws.localhost:${srv.port}/`,
  );

  console.log(response.status);
  console.log(await response.text());
} finally {
  srv.close();
}

Tech mentioned