The single-page-app
construct deploys single-page applications, for example React or VueJS applications
serverless plugin install -n serverless-lift
service: my-app
provider:
name: aws
constructs:
landing:
type: single-page-app
path: public
plugins:
- serverless-lift
On serverless deploy
, the public/
directory will be deployed as a public website.
Note: the first deployment takes 4 minutes. Next deployments only take seconds.
The website is served over HTTPS and cached all over the world via the CloudFront CDN.
On the first serverless deploy
, Lift creates:
- an S3 bucket
- a CloudFront CDN configured to serve the website from S3 over HTTPS, with caching at the edge
- CloudFront Functions to set security HTTP headers
Additionally, every time serverless deploy
runs, Lift:
- uploads all files from the configured directory to the S3 bucket
- invalidates the CloudFront cache so that the new version of the website is live
Note: the S3 bucket is entirely managed by Lift. Do not store or upload files to the bucket, they will be removed by Lift on the next deployment. Instead, create a separate bucket to store any extra file.
To deploy a React app, use the following configuration:
constructs:
react:
type: single-page-app
path: build
To deploy, run:
npm run build
serverless deploy
To deploy a Vue app, use the following configuration:
constructs:
vue:
type: single-page-app
path: dist
To deploy, run:
npm run build
serverless deploy
serverless deploy
deploys everything configured in serverless.yml
and uploads website files.
It is possible to skip the CloudFormation deployment and directly publish website changes via:
serverless <construct-name>:upload
# For example:
serverless landing:upload
This command only takes seconds: it directly uploads files to S3 and clears the CloudFront cache.
All single-page-app constructs expose the following variables:
cname
: the domain name of the resource, such asd111111abcdef8.cloudfront.net
This can be used to reference the bucket from Route53 configuration, for example:
constructs:
landing:
type: single-page-app
path: public
resources:
Resources:
Route53Record:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId: ZXXXXXXXXXXXXXXXXXXJ # Your HostedZoneId
Name: app.mydomain
Type: A
AliasTarget:
HostedZoneId: Z2FDTNDATAQYW2 # Cloudfront Route53 HostedZoneId. This does not change.
DNSName: ${construct:landing.cname}
How it works: the ${construct:landing.cname}
variable will automatically be replaced with a CloudFormation reference to the CloudFront Distribution.
assetsBucketName
: the S3 assets bucketname
This can be used to configure a S3 bucket policy for example:
constructs:
landing:
type: single-page-app
# ...
resources:
Resources:
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: ${construct:landing.assetsBucketName}
# ...
constructs:
landing:
type: single-page-app
path: public
The path
option should point to the local directory containing the single page application. Use path: .
to upload the content of the current directory.
All files in that directory will be deployed and made available publicly.
When using a JavaScript bundler (for example when working with Webpack, VueJS, React, etc.), upload the compiled files. For example this could be the dist/
directory.
constructs:
landing:
# ...
domain: mywebsite.com
# ARN of an ACM certificate for the domain, registered in us-east-1
certificate: arn:aws:acm:us-east-1:123456615250:certificate/0a28e63d-d3a9-4578-9f8b-14347bfe8123
The configuration above will activate the custom domain mywebsite.com
on CloudFront, using the provided HTTPS certificate.
After running serverless deploy
(or serverless info
), you should see the following output in the terminal:
landing:
url: https://mywebsite.com
cname: s13hocjp.cloudfront.net
Create a CNAME DNS entry that points your domain to the xxx.cloudfront.net
domain. After a few minutes/hours, the domain should be available.
To create the HTTPS certificate:
- Open the ACM Console in the
us-east-1
region (CDN certificates must be in us-east-1, regardless of where your application is hosted) - Click "Request a new certificate", add your domain name and click "Next"
- Choose a domain validation method:
- Domain validation will require you to add CNAME entries to your DNS configuration
- Email validation will require you to click a link in an email sent to
admin@your-domain.com
After the certificate is created and validated, you should see the ARN of the certificate.
It is possible to set up multiple domains:
constructs:
landing:
# ...
domain:
- mywebsite.com
- app.mywebsite.com
It is sometimes necessary to redirect one or several domains to a single one. A common example is to redirect the root domain to the www
version.
constructs:
website:
# ...
domain:
- www.mywebsite.com
- mywebsite.com
redirectToMainDomain: true
The first domain in the list will be considered the main domain. In this case, mywebsite.com
will redirect to www.mywebsite.com
.
By default, as recommended for security reasons, the single page application cannot be embedded in an iframe.
To allow embedding the website in an iframe, set it up explicitly:
constructs:
landing:
# ...
security:
allowIframe: true
You can specify an extensions
property on the single-page-app
construct to extend the underlying CloudFormation resources. In the exemple below, the CloudFront Distribution CloudFormation resource generated by the landing
single-page-app construct will be extended with the new Comment: Landing distribution
CloudFormation property.
constructs:
landing:
type: single-page-app
path: public
extensions:
distribution:
Properties:
Comment: Landing distribution
Extension key | CloudFormation resource | CloudFormation documentation |
---|---|---|
distribution | AWS::CloudFront::Distribution | Link |
bucket | AWS::S3::Bucket | Link |
Feel like a common extension pattern should be implemented as part of the construct configuration? Open a GitHub issue.