cdk-spa
Deploying Single Page Application (SPA) Website
[CDK Construct] cdk-spa
includes a construct CdkSpa
and an interface CdkSpaProps
to make deploying a Single Page Application (SPA) Website (React.js / Vue.js / Angular) to AWS S3 behind CloudFront CDN, Route53 DNS, AWS Certificate Manager SSL as easy as 5 lines of code.
The Architecture for CDK-SPA Websites supporting customer-specific subdomains:
- Customers access your application through a browser by entering their personal subdomain (for example, https://chatbot.job4u.io).
-
Amazon Route53
receives the request for the customer-specific subdomain and routes it to theAmazon CloudFront
Distribution. -
CloudFront
caches your web application from theAmazon S3
Bucket where it is stored. Note that theCloudFront Distribution
is configured with read-only permissions to access files inAmazon S3
. -
CloudFront
uses a TLS certificate provisioned inACM
to deliver the content from the nearest edge location.
Installation and Usage
✅ Typescript
npm install --save cdk-spa
import * as cdk from '@aws-cdk/core';
import { CdkSpa } from 'cdk-spa';
export class CdkStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
/** Deploying a Website to AWS S3 */
new CdkSpa(this, 'CDK-SPA Website')
.createSiteS3({
indexDoc: 'index.html',
websiteFolder: 'website'
});
/** Deploying a SPA-Website to AWS S3 behind CloudFront CDN */
new CdkSpa(this, 'CDK-SPA Website behind Cloudfront CDN')
.createSiteWithCloudfront({
indexDoc: 'index.html',
websiteFolder: '../frontend'
});
}
}
☑️ Python
pip install cdk-spa
from aws_cdk import core
from cdk-spa import CdkSpa
class PythonStack(core.Stack):
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
CdkSpa(self, 'CDK-SPA Website').create_site_s3(
index_doc='index.html',
website_folder='website'
)
CdkSpa(self, 'CDK-SPA Website behind Cloudfront CDN').create_site_with_cloudfront(
index_doc='index.html',
website_folder='../frontend'
)
Advanced Usage
Auto Deploy From Hosted Zone Name
If you purchased your domain through Route 53 and already have a Hosted Zone then just use the name to deploy your site behind Cloudfront. This handles the SSL cert and everything for you.
new CdkSpa(this, 'spaDeploy', { encryptBucket: true })
.createSiteFromHostedZone({
zoneName: 'dashboard.aws.oceansoft.io',
indexDoc: 'index.html',
websiteFolder: '../frontend/dist'
});
Custom Domain and SSL Certificates
You can also pass the ARN for an SSL certification and your alias routes to Cloudfront
import cdk = require('@aws-cdk/core');
import { CdkSpa } from 'cdk-spa';
export class CdkStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new CdkSpa(this, 'cfDeploy')
.createSiteWithCloudfront({
indexDoc: '../frontend/dist',
certificateARN: 'arn:...',
cfAliases: ['cdn.aws.oceansoft.io']
});
}
}
Encrypted S3 Bucket
Pass in one boolean to tell SPA Deploy to encrypt your website bucket
new CdkSpa(this, 'cfDeploy', {encryptBucket: true}).createBasicSite({
indexDoc: 'index.html',
websiteFolder: 'website'
});
Custom Origin Behaviors
Pass in an array of CloudFront Behaviors
new CdkSpa(this, 'cfDeploy').createSiteWithCloudfront({
indexDoc: 'index.html',
websiteFolder: 'website',
cfBehaviors: [
{
isDefaultBehavior: true,
allowedMethods: cf.CloudFrontAllowedMethods.ALL,
forwardedValues: {
queryString: true,
cookies: { forward: 'all' },
headers: ['*'],
},
},
{
pathPattern: '/virtual-path',
allowedMethods: cf.CloudFrontAllowedMethods.GET_HEAD,
cachedMethods: cf.CloudFrontAllowedCachedMethods.GET_HEAD,
},
],
});
Restrict Access to Known IPs
Pass in a boolean and an array of IP addresses and your site is locked down!
new CdkSpa(stack, 'spaDeploy', {
encryptBucket: true,
ipFilter: true,
ipList: ['1.1.1.1']
}).createBasicSite({
indexDoc: 'index.html',
websiteFolder: 'website'
})
Modifying S3 Bucket Created in Construct
An object is now returned containing relevant artifacts created if you need to make any further modifications:
- The S3 bucket is present for all of the methods
- When a CloudFront Web distribution is created it will be present in the return object
export interface CdkSpaProps {
readonly websiteBucket: s3.Bucket,
}
export interface CdkSpaPropsWithCloudFront extends CdkSpaProps {
readonly distribution: CloudFrontWebDistribution,
}
Project Directory
$CDK-Patterns/cdk/constructs/cdk-spa
├── lib
| └── index.ts
├── package.json
├── test
| └── cdk-spa.test.ts
├── README.md
├── jest.config.js
├── tsconfig.json
├── tsconfig.json.origin
└── website
└── index.html
💪 [Manually] Roll-Your-Own CDK-Construct
-
You may skip
Projen
and start your own CDK-Construct project.-
[x] Default TypeScript project:
# npm install -g aws-cdk # cdk --version cdk init lib --language=typescript
-
[x] Make sure your
package.json
has author, repository, and description filled out correctly -
[x] Initialize jsii by running
npx jsii-config
-
[x] Use jsii-config to add all language targets
-
[x] Add jsii and jsii-pacmak as dependencies
npm i --save-dev jsii jsii-pacmak
-
[x] Create a build and a package script that call jsii and jsii-pacmak respectively
-
[ ]
npm publish
to make your template available on the npm package registry.
npm login npm init --scope=oceansoft # npm publish npm publish --access public * [x] Build and Package JSII modules, then Release to NPM --> `CI-cdk-spa.yml`
npm run package npx -p jsii-release jsii-release-npm
-
-
Despite the fact that this is perfectly possible, we still strongly recommend that you use
Projen
as it handles all setup, configuration, and release scripting for you.
Useful commands
-
npm run build
compile typescript to js -
npm run watch
watch for changes and compile -
npm run test
perform the jest unit tests
✅ NPM Package:https://www.npmjs.com/package/cdk-spa
💰 https://github.com/OceanSoftIO/Serverless/cdk