Find out how to Deploy React App to S3 and CloudFront


If you need to deploy a React App to AWS S3 and AWS CloudFront, then you possibly can observe this information.

The next answer creates a React App and deploys it to S3 and CloudFront utilizing the shopper’s CLI.
It additionally chains instructions so {that a} React construct, S3 sync and CloudFront invalidation can happen with a single command.

Code accessible at GitHub

Goal Structure

Create a listing for the appliance:

mkdir deploy_react && cd $_

Code language: Bash (bash)

Create the React App utilizing create-react-app from npx:

npx create-react-app sample-react-app

Code language: Bash (bash)

(Non-obligatory) Open the undertaking in VS Code:

code .

Code language: Bash (bash)

Change listing and run the app:

cd sample-react-app<br>npm begin

Code language: Bash (bash)

Now we have to set up react-router-dom in order that we are able to change routes between pages in our React app.

npm i react-router-dom

Code language: Bash (bash)

As soon as that is executed, we are able to edit our code earlier than shifting onto the deployment steps.

Open the App.js file beneath the src listing and exchange all of the code within the file with the next:

import './App.css'; import React from "react"; import { BrowserRouter as Router, Routes, Route, Hyperlink } from "react-router-dom"; const Dwelling = () => { return <h2>Dwelling</h2> } const About = () => { return <h2>About</h2> } perform App() { return ( <div className="App"> <Router> <div> <nav> <ul> <li> <Hyperlink to="/">Dwelling</Hyperlink> </li> <li> <Hyperlink to="/about">About</Hyperlink> </li> </ul> </nav> <div className="content material"> <Routes> <Route path="/about" component={<About />} /> <Route path="/" component={<Dwelling />} /> </Routes> </div> </div> </Router> </div> ); } export default App;

Code language: JavaScript (javascript)

Open the App.css file as exchange it with the next:

ul { padding: ; } li { show:inline; padding: 10px; } .content material { padding: 10px; }

Code language: CSS (css)

If we run the React app with npm begin, we’ll now see the next:

If we click on on About within the navigation, the web page modifications and reveals the About part.

Head over to the S3 console and create a brand new bucket.
Give it a singular bucket title and click on Create bucket.

We now have a brand new bucket, with nothing inside.

Head over to CloudFront and create a distribution:

Choose the Origin area, which would be the newly created S3 bucket.
Specify a Identify. Observe that it’s going to create one for you from the Origin area by default if you happen to don’t specify one your self.

For S3 bucket entry, Select Sure use OAI, create a brand new OAI and choose Sure for the Bucket coverage Replace.

Beneath Default cache habits, choose Redirect HTTP to HTTPS.

Beneath Settings, specify the Default root object to be index.html

Depart all different fields as is and click on Create distribution.

You’ll now see a distribution being created for you.

Observe that it will take a few minutes to prepare,

Within the package deal.json file, beneath src/, find the next scripts strains:

"scripts": { "begin": "react-scripts begin", "construct": "react-scripts construct", "check": "react-scripts check", "eject": "react-scripts eject" },

Code language: JSON / JSON with Feedback (json)

Right here we’ll add some extra choices:
We are going to add a brand new script referred to as deploy-to-s3 and it’ll run the next command:
aws s3 sync construct/ s3://<your_s3_bucket_name>

Observe that you would be able to additionally specify an AWS_PROFILE right here as follows if wanted:
aws s3 sync construct/ s3://<your_s3_bucket_name> --profile <profile_name>

Replace the scripts part to look as under, however change your individual S3 bucket title inplace:

"scripts": { "begin": "react-scripts begin", "construct": "react-scripts construct", "deploy-to-s3": "aws s3 sync construct/ s3://sample-react-app-123654789", "check": "react-scripts check", "eject": "react-scripts eject" },

Code language: JSON / JSON with Feedback (json)

Now we have to create a construct of our React app, in order that we are able to push it’s contents to S3.
To do that, run the next command:
npm run construct

Then deploy it to S3 as follows:
npm run deploy-to-s3

Now if we glance within the S3 console, we are able to see the recordsdata that had been deloyed:

We now must setup the CloudFront pages, which we’ll do by the CloudFront console.

Beneath the CloudFront distribution, click on Create customized error response.
We do that as a result of React is a Single Web page Software (SPA) and no bodily recordsdata exist on the server for the totally different Routes that we now have specified. They’re all dynamic.
For instance, /about doesn’t exist as a logical path on the drive, or server. So as a substitute, will probably be a 404 Not Discoveredwhen referred to as upon. So due to this fact, we’ll inform CloudFront that for all 404 Not Discovered paths, we wish index.html to deal with them.
Do not forget that index.html is the trail for the place React initializes.

To this finish, create a 404 Not Discovered customized error response, that factors to our /index.html file, with a standing of 200 OK:

Additionally create a 403 Forbidden customized error response, that factors to our /index.html file, with a standing of 200 OK:

As soon as each have been created, the Error pages ought to have two (2) entries as follows:

If we don’t create these, then we’ll get the AccessDenied error when making an attempt to entry any of the Routes we specified within the React app, which appear like this:

Now as a substitute, we are able to see the precise Route itself:

Everytime we replace the CloudFront distribution, by deploying new recordsdata to S3, we have to Invalidate the recordsdata.

Head over to the package deal.json file from earlier than and add one other command beneath the one we simply added:
It’s going to look one thing like this:

aws cloudfront create-invalidation --distribution-id <distribution_id> --paths '/*' --profile <profile_name>

Code language: Bash (bash)

You don’t must specify the --profile argument, except it is advisable.

We will get the Distribution ID from CloudFront itself:

Replace this new part as follows, keep in mind to interchange your --distribution-id:

"scripts": { "begin": "react-scripts begin", "construct": "react-scripts construct", "deploy-to-s3": "aws s3 sync construct/ s3://sample-react-app-123654789", "invalidate-cloudfront": "aws cloudfront create-invalidation --distribution-id EIAUK8JFBCT6S -- paths '/*'", "check": "react-scripts check", "eject": "react-scripts eject" },

Code language: JSON / JSON with Feedback (json)

In the event you run that step alone, you’re going to get a verification as follows:

{ "Location": "", "Invalidation": { "Id": "I17X51041BLJHR", "Standing": "InProgress", "CreateTime": "2022-08-17T18:16:56.890000+00:00", "InvalidationBatch": { "Paths": { "Amount": 1, "Gadgets": [ "/*" ] }, "CallerReference": "cli-1660760215-662979" } } }

Code language: JSON / JSON with Feedback (json)

Now that we now have each the steps we’d like, let’s create an mixture command that may tie all the pieces collectively, in order that we solely must run a single command every time:

We are going to add the next script:

"deploy": "npm run construct && npm run deploy-to-s3 && npm run invalidate-cloudfront",

Code language: JSON / JSON with Feedback (json)

So as soon as we now have added it to the scripts block, it would all appear like this:

"scripts": { "begin": "react-scripts begin", "construct": "react-scripts construct", "deploy-to-s3": "aws s3 sync construct/ s3://sample-react-app-123654789", "invalidate-cloudfront": "aws cloudfront create-invalidation --distribution-id EIAUK8JFBCT6S --paths '/*'", "deploy": "npm run construct && npm run deploy-to-s3 && npm run invalidate-cloudfront", "check": "react-scripts check", "eject": "react-scripts eject" },

Code language: JSON / JSON with Feedback (json)

This now means we now have a single command to construct our React App, sync the recordsdata to S3, and invalidate the recordsdata in CloudFront, as a chained command.

If we take the present state of the deployed software on CloudFront, it appears to be like like this:

If we open the App.js file and create a brand new Route:

<Route path="/testing" component={<Testing />} />

Code language: HTML, XML (xml)

Which is added as follows:

<div className="content material"> <Routes> <Route path="/about" component={<About />} /> <Route path="/testing" component={<Testing />} /> <Route path="/" component={<Dwelling />} /> </Routes> </div>

Code language: HTML, XML (xml)

Then add a brand new part for Testing:

const Testing = () => { return <h2>Testing</h2> }

Code language: JavaScript (javascript)

Then add a brand new nav merchandise:

<li> <Hyperlink to="/testing">Testing</Hyperlink> </li>

Code language: HTML, XML (xml)

Now all we have to do to see the modifications deployed, is run the next command:

npm run deploy

This can cycle by our steps and produce the next output:

> [email protected] deploy > npm run construct && npm run deploy-to-s3 && npm run invalidate-cloudfront > [email protected] construct > react-scripts construct Creating an optimized manufacturing construct... Compiled efficiently. File sizes after gzip: 50.75 kB construct/static/js/major.95dbd789.js 1.79 kB construct/static/js/787.7c33f095.chunk.js 301 B construct/static/css/major.58e1094f.css The undertaking was constructed assuming it's hosted at /. You'll be able to management this with the homepage subject in your package deal.json. The construct folder is able to be deployed. Chances are you'll serve it with a static server: npm set up -g serve serve -s construct Discover out extra about deployment right here: https://cra.hyperlink/deployment > [email protected] deploy-to-s3 > aws s3 sync construct/ s3://sample-react-app-123654789 add: construct/asset-manifest.json to s3://sample-react-app-123654789/asset-manifest.json add: construct/static/js/ to s3://sample-react-app-123654789/static/js/ add: construct/index.html to s3://sample-react-app-123654789/index.html add: construct/robots.txt to s3://sample-react-app-123654789/robots.txt add: construct/manifest.json to s3://sample-react-app-123654789/manifest.json add: construct/static/js/787.7c33f095.chunk.js to s3://sample-react-app-123654789/static/js/787.7c33f095.chunk.js add: construct/favicon.ico to s3://sample-react-app-123654789/favicon.ico add: construct/static/css/ to s3://sample-react-app-123654789/static/css/ add: construct/static/css/major.58e1094f.css to s3://sample-react-app-123654789/static/css/major.58e1094f.css add: construct/logo512.png to s3://sample-react-app-123654789/logo512.png add: construct/logo192.png to s3://sample-react-app-123654789/logo192.png add: construct/static/js/major.95dbd789.js.LICENSE.txt to s3://sample-react-app-123654789/static/js/major.95dbd789.js.LICENSE.txt add: construct/static/js/major.95dbd789.js to s3://sample-react-app-123654789/static/js/major.95dbd789.js add: construct/static/js/ to s3://sample-react-app-123654789/static/js/ > [email protected] invalidate-cloudfront > aws cloudfront create-invalidation --distribution-id EIAUK8JFBCT6S --paths '/*'
Code language: plaintext (plaintext)

Now we are able to refresh the browser and we’ll see our new Route added and linked to our new TestingComponent as quickly because the CloudFront invalidations have accomplished.


Please enter your comment!
Please enter your name here