I am going to show you how to properly release ReactJS for production. I show you how to drastically reduce the deploy time when it comes to ReactJS Release CICD for azure devops Pipeline and GitHub actions.
React is a JavaScript library that helps you make UI in in a very nice way. Though, to like and enjoy it you need to first really understand how it works. Sooner or later you are going to have your Ahaaa moment and from that point of time it is going to be your favorite JavaScript library. But when it comes to releasing the project it seems that many people did not have their Ahaaa moment yet! I have seen things! And I have seen false beliefs and superstitions about react!
Let me just make it clear we are talking about create react app and not react native. So with that in your mind let’s explore the react Release Pipeline and a CICD process of it.
How to build properly a ReactJS SPA project
Weirdly enough, I see most of those that are doing it wrong, are at least aware of the build script commands. This commands is shipped with react, but for some reason either they are totally not using it or they think they are using it (and they are A LOT)!
By the way, If you want to follow along please make simple react project:
npx create-react-app my-app
If you look at the package.json file you should find the script section like this:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
It is hard to miss! And you probably noticed when you run this command, it creates a directory called build. If you don’t have the time to read the rest of this article please just take this with you : “build directory is all you need on the production server, it is a static javascript and it is very lightweight! “
Seriously that is it! believe me! no node_modules folder needed but let me clarify more:
Do I need NodeJS runtime for my react SPA?
Here is the myth #1 : You should use NodeJs as backend production server. The short answer is no, long answer is it depend (and rarely). Basically there are 2 ways of running your react SPA apps. First one is like any other normal JavaScript, in a very normal html file; This is static and by far is the most used case. You know you are using this method when you have ReactDOM.render
() method in your index.js (or ts)
The second one is called hydration. Arguably, when you choose react you should not really need hydration, but for hydration to work you need a NodeJS server.
Please keep in mind that for development purposes you need NPM , and NodeJs.
Should I Always use React Hydration
Why ?
Myth #2 : You should always use Hydration for your react. Answer is obviously no! Hydration is mostly useful in case of multi-page applications like blog or web-shops; for more please read Single Page Application (SPA) vs Multi Page Application (MPA). hydration is also useful if you want your starting page rendered on the server instead of client, but this in no way means that it is always going to be faster! Using hydration, you can also cache the whole page as a static file but if you read my discussion on page above, I mentioned there is really no point for that in a SPA.
How hydrate my react application ?
Basically in your index.js (or ts) instead of using :
ReactDOM.render(element, container[, callback])
you are going to use :
ReactDOM.hydrate(element, container[, callback])
You see they are very similar, and easy to switch to one and other. But it seems react documentation is missing to mention that you need a NodeJS server for hydration to work. Of course it mentions that a hydrated react uses ReactDOMServer
, so we should know that it needs a NodeJS server to work.
Should I use Hydrations
At the first glance, It seems like a good Idea to hydrate our react all the time and get all the benefits right? but it is not. When you put your architect hat on, you should always tell yourself “right tool for the job“. But If you have a multi page application a SPA library is not the best tool.
How To Release ReactJS App Properly
Well, so far we discussed about the build folder and mentioned all you need in for your application to run is in this folder we also stated that you don’t need NodeJs for your application to run. So when you are creating the artefact, make it of the build folder only and not the whole codebase.
You can Also deploy it as a front end for a dotnet or Java VMC project or similar, and run it using the same server that runs your java or dotnet project. Another Idea is to dockerize your frontend and run it using a simple server like nginx.
As it content of the build folder are only a javascript library, you can have it as part of a page too, and combine react with a server generated html page. All I am saying is the content of the build folder is a self contained javascript like any other javascript library you might include in your page.
Speed up the deployment
When you only copy the content of the build folder you basically skip the node_modules that makes your artefact really small and makes the process of deployment really fast.
The big mistake I see many people do is that they deploy the whole root folder with the node_modules. Then they use a NodeJS server to run the app using npm start.
Of course it is going to work but it will not be very efficient to run a react application as you are running it in development mood with all development overheads. So if your deployment takes like half an hour you know you are doing it wrong!
Build and create an artefact on GitHub
I make you a sample action workflow for GitHub, but hope you learned the essence of that all the discussions and you can apply it in your case.
name: Build and deploy React app to Azure Web App on GitHub
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node.js version
uses: actions/setup-node@v3
with:
node-version: "14.x"
- name: build the artifact
shell: bash
run: |
npm ci
npm run build
- name: Upload artifact for deployment job
uses: actions/upload-artifact@v3
with:
name: react-app
#LOOK CAREFULLY HERE
path: build/*
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: "Production"
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
steps:
- name: Download artifact from build job
uses: actions/download-artifact@v3
with:
name: react-app
- name: "Deploy to Azure Web App"
id: deploy-to-webapp
uses: azure/webapps-deploy@v3
with:
app-name: "statistics-react-app"
slot-name: "Production"
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_XXXXXXXXX }}
package: .
Note that we used Publish profile to authenticate to azure, there is a batter way of integration with azure resources using federated access thorough OICD to learn more please read: GitHub Federated integration: Azure Key Vault & ACR- Example
Leave a Reply