If you’re like me, and you get tired of uploading your Angular transpiled output to S3 manually, you’ve probably were thinking, “I really need to automate this.”

I have by using NPM or Yarn and made a custom “deploy” script on package.json.  I use yarn mostly, but NPM works too.

The following are used to get this done:

  • Yarn Package Managers
  • AWS S3
  • AWS CloudFront
  • Angular CLI

Angular Build Process

Just to recap, and you may already be doing this, but I use the following command to make a final “dist” build of my Angular project:

ng build --prod

This will output a final, minified, and optimized build of your project.  In the past, I used to take the contents of this folder and drag/drop it into an S3 client app.  I’ll get into details on this part of the automation.

Create S3 Bucket

We’ll need an S3 bucket to store our transpiled outpout.  Create a new S3 bucket:

  • Log on to AWS Console.
  • Click on Services (top-right) after signing on.
  • Look for Scalable Storage in the Cloud (S3) and click to go to it.
  • Click: Create Bucket
  • Settings
    • Bucket name: Whatever you want.
    • US Region: Ensure you are consistent with a region.  I normally stick to us-west-2 (Oregon)
    • Next all the way until you’re at the “Create Bucket” button 🙂

Error Documents

Your new bucket is created, but we still need to an additional step in order for it to work on everyone’s browser.

  • Click your new bucket so you go right into it.
  • From the tabs above, click Properties.
  • Click: Static Webhosting
  • Click: Use this bucket to host a website
    • Index document: index.html
    • Error document: index.html

You’re probably wondering: “Why am I setting error document to ‘index.html’???”.  Because you’re utilizing a Single Page Application (SPA) framework and route returns all go to index.html 😉

Bucket Policy

We also need to ensure that the bucket policy is set.  Do the following so that your contents are publicly “read” available:

  • In your bucket properties, make sure you’re in the “Permissions” tab.
  • Click: Bucket Policy
  • It’s currently blank.  Copy the following and paste it into the box.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::BUCKETNAME/*"
        }
    ]
}

Type the name of your bucket in the BUCKETNAME as shown in green above.  From there, hit the save button.

CORS Configuration

Lastly, we need to set CORS to enable global read access to everyone on their browsers:

  • From the bucket’s Permissions tab, click “CORS Configuration.”
  • Nothing to do here OTHER than to: Click “Save”

That was strange to me as well, but I believe it wasn’t originally set unless manually “saved” by the administrator.

AWS CloudFront

What is AWS CloudFront?

CloudFront is a global “Content Delivery Network.”  They have servers all over the world and can help offload static assets to CloudFront so your application doesn’t have to serve them.

This greatly reduces the disk usage of your Git repositories and caches images/videos/PDFs/etc.

Create Distribution

To create a CloudFront distribution, do the following:

  • Click: Create Distribution
  • Under “Web”, click: Get Started
  • Settings
    • Origin Name: Choose your new S3 bucket.
    • Viewer Protocol Policy: Redirect to HTTP to HTTPS
    • Object Caching: Customize (Google SEO Recommendation)
      • Minimum TTL: 604800
      • Maximum TTL: 31557600
      • Default TTL: 604800
  • Click: Create Invalidation

Error Pages

Since your Angular app will be handling all routing, you need to designate the error pages to also point to index.html.  This is how to do this:

  • From your new CloudFront distribution, make sure you are in the “Error Pages” screen.
  • Click: Create Custom Error Response
  • Settings
    • HTTP Error Code: 403: Forbidden
    • Customize Error Response: Yes
      • Response Page Path: /index.html
      • HTTP Response Code: 200 OK
  • We need to create another for 404: Not Found.  Same settings as above, just choose “404: Not Found”

Local Development Environment Setup

Update: package.json

Add the following under the “scripts” directive of package.json:

"deploy": "ng build --prod && aws s3 rm s3://your-website --recursive && aws s3 cp ./dist s3://your-website --recursive && aws configure set preview.cloudfront true && aws cloudfront create-invalidation --distribution-id XXXXXXXXXXXXXX --paths '/*'"

Let’s break this down:

  • ng build –prod
    • Make a final build of your application.
  • aws s3 rm s3://your-website –recursive
    • Deletes all the stuff in your bucket.
  • aws s3 cp ./dist s3://your-website –recursive
    • Copies the final dist folder that was compiled on your computer and uploads it to your bucket.
  • aws configure set preview.cloudfront true
    • Enable experimental abilities (which is needed to utilize create-invalidation)
  • aws cloudfront create-invalidation –distribution-id XXXXXXXXXXXXXX –paths ‘/*’
    • This will create an invalidation on CloudFront.  Replace XXXXXXXXXXXXXX with your CloudFront ID specific to your CloudFront distribution.

Conclusion

That’s it my fellow devs.  All that’s left is to run the following:

yarn deploy

Watch the magic happen 😉

Happy coding 🙂

p.s. You should probably inject at the beginning “ng test” to run Unit Tests against your application.