Serving SPA is a pain when especially it is a heavy traffic app. There are services like Netlify and Vercel, which tend to have ease in deployment using built-in Continuous Delivery methods, but they have a high price that increases based on traffic downloading that SPAs.
Moreover, when your entire stack is on AWS, then why not use SPA with S3? Why Not?
The downside is we have to set up everything from the ground up ourselves, but the final result will be automated and with a lot less money and a lot less hassle of maintaining different providers, i.e., AWS, Netlify, etc.
Here we will do the following:
- First, we will create an S3 bucket with setting for static web hosting
 - Then we will create a cloud front for the origin s3 bucket with settings to use the cloud front as the provider of SPA
 - Then will set up a CD using GitHub Actions so that next time your content goes to the public hassle-free.
 
Create an S3 bucket:
- Go to S3 in the AWS console, and click create bucket button
 - Select the bucket name, I will be using 
sulman-bucket-1 - select a region suitable to you, I will be using 
us-east-1 - In 
Object OwnershipselectACL enabledand selectObject Writerin Object Ownership - Unselect 
Block all public accessand confirm it by checking the acknowledgment below this block - Leave the rest of the settings as is and create the bucket.
 
Build SPA for Production to upload for the first time:
- build SPA for production that has to be manually uploaded for the first time
 - I use yarn, so I will call 
yarn build - This should create a 
distfolder - Click on upload in the S3 bucket, drag and drop the contents of the folder including 
index.htmlin the root of the bucket and upload them 
Change permissions of the bucket:
- go to the 
permissionstab inside the bucket in the S3 console - Edit policy in the 
Bucket Policysection - 
Enter the following in the text box
{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::sulman-bucket-1/*" }] } Click Edit in
Access Control List (ACL)select both checkboxes in
Everyone (public access)Save changes
Enable Static Web Hosting:
- Go to the 
Propertiestab and at the end of it there is theStatic Web Hostingsection - Enable static web hosting]
 - Hosting type → Host a static website
 - Index document → index.html
 - Error document → index.html (as we will be using SPA)
 - Save changes
 
Create Cloud Front Distribution:
- Go to Cloud Front in the AWS console and click the 
Create Distributionbutton. - Select in 
Origin Domainthe S3 bucket where the static site you just uploaded is. - In section the 
Default cache behavior→viewer→viewer protocol policy→ selectRedirect HTTP to HTTPS - In section the 
Default cache behavior→viewer→Allowed HTTP methods→ select all containing HTTP methods - In section 
Settings→Alternate Domain Name (CNAME) - optional→ Add Item and enter the domain path liketest.sulmanweb.com - In section 
Settings→Custom SSL certificate - optional→ Request certificate. This will open the request public certificate, and validate the domain by adding the CNAME provided in your DNS provider. - After the certificate is done, click on the refresh button and select certificate just created
 - In section 
Settings→Default root object - optionaland enterindex.html - Click Create Distribution
 
Add CloudFront as CNAME in DNS:
- After cloud front distribution is created, copy 
Distribution domain name - Create a CNAME in your DNS and paste the domain name
 
Error pages in Cloud Front:
- As we are using SPA then the problem of reloading the page in the cloud front gives an error, so we have to resolve that
 - In distribution, go to the 
Error Pagestab - Click on 
Create custom error page - select 
404in the HTTP status code - select 
Yesto Customise Error Response - Then enter 
/index.htmlin the response page path - and HTTP Response Code equal 
404 - create the page
 
GitHub Actions CD:
I am a great advocate of mono-repo, so my front-end is in folder
front
name: Deploy Front Production
on:
  push:
    branch: 'main'
    paths:
      - 'front/**'
jobs:
  deploy:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: 'front'
    steps:
      - uses: actions/checkout@v2
      - name: Cache modules
        uses: actions/cache@v1
        id: yarn-cache
        with:
          path: node_modules
          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
          restore-keys: ${{ runner.os }}-yarn-
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}
      - name: Setup Node.js environment
        uses: actions/setup-node@v3
        with:
          node-version: 16
      - name: Run a multi-line script
        run: |
          yarn
          yarn build
      - name: Deploy
        run: aws s3 sync ./dist s3://${{ secrets.AWS_BUCKET_FRONT }}
      - name: Invalidate CloudFront
        uses: chetan/invalidate-cloudfront-action@v2
        env:
          DISTRIBUTION: ${{ secrets.DISTRIBUTION_FRONT }}
          PATHS: "/index.html"
          AWS_REGION: "${{ secrets.AWS_REGION }}"
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- Create a folder in the root of repo 
.githuband in that folder another folderworkflows - Create in github.com secrets, So go in your repo → settings → Secrets → Actions
 - Create secrets with the name 
AWS_BUCKET_FRONTand the value of your bucket name - Another secret with the name 
DISTRIBUTION_FRONTand value of distribution ID in value - Also name 
AWS_REGIONand the value of the region of your bucket - name 
AWS_ACCESS_KEY_IDand value of your access key ID having permissions to S3 and Cloud Front - Lastly, name 
AWS_SECRET_ACCESS_KEYand the value of your secret key having the above permissions. - 
working_directoryis for the mono-repo folder where lies the code to SPA 
Here we first get the repo, then build SPA in the folder, then the first upload to the S3 bucket, and lastly invalidate the cloud front deployment so that it recognizes the current S3 code as new.
Now, when a code is pushed to the main branch, and it has changed in the front folder, then your changes will automatically be deployed to S3 and Cloud Front without any hassle.
Special thanks to the following people who helped me run my own distributions first:
Happy Coding!
              
    
Top comments (0)