JSPM

  • Created
  • Published
  • Downloads 5528
  • Score
    100M100P100Q122054F
  • License MIT

Build your frontend apps during CDK deployment!

Package Exports

  • deploy-time-build
  • deploy-time-build/lib/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (deploy-time-build) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Deploy-time Build

AWS CDK L3 construct that enables you to build apps during deploy time, aiming to resolve a few problems when we deploy frontend apps from CDK.

architecture

Usage

Install from npm:

npm i deploy-time-build

Build Node.js apps

Use the following code to build Node.js apps like React frontend:

import { NodejsBuild } from 'deploy-time-build';

declare const api: apigateway.RestApi;
declare const destinationBucket: s3.IBucket;
declare const distribution: cloudfront.IDistribution;
new NodejsBuild(this, 'ExampleBuild', {
    assets: [
        {
            path: 'example-app',
            exclude: ['dist', 'node_modules'],
        },
    ],
    destinationBucket,
    distribution,
    outputSourceDirectory: 'dist',
    buildCommands: ['npm ci', 'npm run build'],
    buildEnvironment: {
        VITE_API_ENDPOINT: api.url,
    },
});

Note that it is possible to pass environment variable VITE_API_ENDPOINT: api.url to the construct, which is resolved on deploy time, and injected to the build environment (a vite process in this case.) The resulting build artifacts will be deployed to destinationBucket using a s3-deployment.BucketDeployment construct.

You can specify multiple input assets by assets property. These assets are extracted to respective sub directories. For example, assume you specified assets like the following:

assets: [
    {
        // directory containing source code and package.json
        path: 'example-app',
        exclude: ['dist', 'node_modules'],
        commands: ['npm install'],
    },
    {
        // directory that is also required for the build
        path: 'module1',
    },
],

Then, the extracted directories will be located as the following:

.                         # a temporary directory (automatically created)
├── example-app           # extracted example-app assets
│   ├── src/              # dist or node_modules directories are excluded even if they exist locally.
│   ├── package.json      # npm install will be executed since its specified in `commands` property.
│   └── package-lock.json
└── module1               # extracted module1 assets

You can also override the path where assets are extracted by extractPath property for each asset.

Please also check the example directory for a complete example.

Allowing access from the build environment to other AWS resources

Since NodejsBuild construct implements iam.IGrantable interface, you can use grant* method of other constructs to allow access from the build environment.

declare const someBucket: s3.IBucket;
declare const build: NodejsBuild;
someBucket.grantReadWrite(build);

You can also use iam.Grant class to allow any actions and resources.

declare const build: NodejsBuild;
iam.Grant.addToPrincipal({ grantee: build, actions: ['s3:ListBucket'], resources:['*'] })

Build SOCI index for a container image

Seekable OCI (SOCI) is a way to help start tasks faster for Amazon ECS tasks on Fargate 1.4.0. You can build and push a SOCI index to use the feature by the following CDK code:

import { SociIndexBuild } from 'deploy-time-build;

const asset = new DockerImageAsset(this, 'Image', { directory: 'example-image' });
new SociIndexBuild(this, 'Index', { imageTag: asset.assetHash, repository: asset.repository });
// or using a utility method
SociIndexBuild.fromDockerImageAsset(this, 'Index2', asset);

// Use the asset for ECS Fargate tasks
import { AssetImage } from 'aws-cdk-lib/aws-ecs';
const assetImage = AssetImage.fromDockerImageAsset(asset);

The below image is the architecture for SociIndexBuild construct. We currently use soci-wrapper to build and push SOCI indices.

soci-architecture

Motivation - why do we need the NodejsBuild construct?

I talked about why this construct can be useful in some situations at CDK Day 2023. See the recording or slides below:

Recording | Slides

Considerations

Since this construct builds your frontend apps every time you deploy the stack and there is any change in input assets (and currently there's even no build cache in the Lambda function!), the time a deployment takes tends to be longer (e.g. a few minutes even for the simple app in example directory.) This might results in worse developer experience if you want to deploy changes frequently (imagine cdk watch deployment always re-build your frontend app).

To mitigate this issue, you can separate the stack for frontend construct from other stacks especially for a dev environment. Another solution would be to set a fixed string as an asset hash, and avoid builds on every deployment.

      assets: [
        {
          path: '../frontend',
          exclude: ['node_modules', 'dist'],
          commands: ['npm ci'],
          // Set a fixed string as a asset hash to prevent deploying changes.
          // This can be useful for an environment you use to develop locally.
          assetHash: 'frontend_asset',
        },
      ],

Development

Commands for maintainers:

# run test locally
yarn tsc -p tsconfig.dev.json
yarn integ-runner
yarn integ-runner --update-on-failed