@threeleafsoftware/serverless-spa-plugin v1.0.2
Serverless SPA Plugin
A plugin for Serverless Framework, to simplify deploying Single Page Application using S3 and CloudFront.
Based on the official example, with some important tweaks:
- Configurable app source directory
- Configurable stack output name to indicate the distribution id
Instalation
Install the package with NPM or Yarn.
NPM:
npm install --save-dev @threeleafsoftware/serverless-spa-pluginYarn:
yarn add --dev @threeleafsoftware/serverless-spa-pluginSetup
Then register it in your serverless.yml file, as a plugin:
plugins:
- @threeleafsoftware/serverless-spa-pluginSet plugin variables:
custom:
spa:
appDir: dist
appBucket: my.app.com
distributionIdOutputKey: WebAppCloudFrontDistributionIdFinally, add appropriately-named resources (Origin Access Control, Bucket, BucketPolicy and Distribution) and Outputs:
service: 'my-webapp'
frameworkVersion: '3'
plugins:
- serverless-spa-plugin
provider:
name: 'aws'
...
custom:
spa:
appDir: dist
appBucket: my.webapp.com
distributionIdOutputKey: WebAppCloudFrontDistributionId
resources:
Resources:
WebAppCloudFrontOriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Description: Origin Access Control to WebApp bucket
Name: WebAppOAC
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
WebAppS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.spa.appBucket}
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: index.html
WebAppS3BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket:
Ref: WebAppS3Bucket
PolicyDocument:
Statement:
- Sid: AllowCloudFrontServicePrincipalReadOnly
Action:
- 's3:GetObject'
Effect: Allow
Resource:
Fn::Join:
- ''
- - 'arn:aws:s3:::'
- Ref: WebAppS3Bucket
- /*
Principal:
Service: "cloudfront.amazonaws.com"
Condition:
StringEquals:
"aws:SourceArn":
- Fn::Join:
- ''
- - 'arn:aws:cloudfront::'
- Ref: AWS::AccountId
- ':distribution/'
- Ref: WebAppCloudFrontDistribution
WebAppCloudFrontDistribution:
Type: AWS::CloudFront::Distribution
DependsOn:
- WebAppS3Bucket
- WebAppCloudFrontOriginAccessControl
Properties:
DistributionConfig:
Aliases:
- ${self:custom.spa.appBucket}
ViewerCertificate:
CloudFrontDefaultCertificate: 'true'
Origins:
- DomainName: ${self:custom.spa.appBucket}.s3.amazonaws.com
Id: WebApp
OriginAccessControlId: !Ref WebAppCloudFrontOriginAccessControl
S3OriginConfig:
OriginAccessIdentity: ''
Enabled: 'true'
DefaultRootObject: index.html
CustomErrorResponses:
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
DefaultCacheBehavior:
AllowedMethods:
- DELETE
- GET
- HEAD
- OPTIONS
- PATCH
- POST
- PUT
TargetOriginId: WebApp
ForwardedValues:
QueryString: 'false'
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
Outputs:
WebAppCloudFrontDistributionId:
Description: 'Cloudfront distribution ID'
Value:
Fn::GetAtt:
- WebAppCloudFrontDistribution
- IdDeploy
Warning: Whenever you making changes to CloudFront resource in serverless.yml the deployment might take a while e.g 20 minutes.
In order to deploy the Single Page Application you need to setup the infrastructure first by running
serverless deployThe expected result should be similar to:
Serverless: Packaging service…
Serverless: Uploading CloudFormation file to S3…
Serverless: Uploading service .zip file to S3…
Serverless: Updating Stack…
Serverless: Checking Stack update progress…
...........................
Serverless: Stack update finished…
Service Information
service: serverless-simple-http-endpoint
stage: dev
region: us-east-1
api keys:
None
endpoints:
None
functions:
NoneAfter this step your S3 bucket and CloudFront distribution is setup. Now you need to upload your static file e.g. index.html and app.js to S3. You can do this by running
serverless syncToS3The expected result should be similar to
Serverless: upload: dist/index.html to s3://my.webapp.com/index.html
Serverless: upload: dist/app.js to s3://my.webapp.com/app.js
Serverless: Successfully synced to the S3 bucketNow you just need to figure out the deployed URL. You can use the AWS Console UI or run
sls domainInfoThe expected result should be similar to
Serverless: Web App Domain: dyj5gf0t6nqke.cloudfront.netVisit the printed domain domain and navigate on the web site. It should automatically redirect you to HTTPS and visiting /about will not result in an error with the status code 404, but rather serves the index.html and renders the about page.
Re-deploying
If you make changes to your Single Page Application you might need to invalidate CloudFront's cache to make sure new files are served. Meaning, run:
serverless syncToS3To sync your files and then:
serverless invalidateCloudFrontCache