Why Does My ReactJS App Run Locally But Not In Azure? - node.js

I have a ReactJS app that connects to json-server as a fake API.
I have deployed it to Azure using VSCode and the F1 Free Linux tier.
When I run it locally with npm start everything works.
"scripts": {
"start": "npm-run-all --parallel mock web",
"web": "cross-env PORT=8080 react-scripts start",
"mock": "node index.js"
},
The index.js contains the json-server config etc as it is a bit more than json-server --watch db.json
I am using the package npm-run-all to run json-server and the react app at the same time.
This works fine locally but when I try to deploy it to Azure the container fails to start:
INFO - Starting container for site
INFO - docker run -d -p 7307:8080 --name demo_0_8cd -e WEBSITE_SITE_NAME=demo -e WEBSITE_AUTH_ENABLED=False -e WEBSITE_ROLE_INSTANCE_ID=0 -e WEBSITE_HOSTNAME=demo.azurewebsites.net -e WEBSITE_INSTANCE_ID=8fe4512f9f -e HTTP_LOGGING_ENABLED=1 appsvc/node:12-lts_20200918.1
INFO - Initiating warmup request to container demo_0_8cd for site demo
ERROR - Container demo_0_8cd for site demo has exited, failing site start
ERROR - Container demo_0_8cd didn't respond to HTTP pings on port: 8080, failing site start. See container logs for debugging.
INFO - Stopping site demo because it failed during startup.
I can't see much in the container logs to debug this.
I also can't tell what command Azure is using to start since all it says in the logs is docker run.
Is it calling npm start? (see EDIT - tldr: yes)
Why is it working locally but not in Azure?
Why is it not responding to the ping?
Is it something to do with this being a React app instead of "just" a node app?
EDIT:
The docker container that this tutorial generates has scripts in /opt/startup.
The templated one is /opt/startup/init_container.sh and this contains:
STARTUP_COMMAND_PATH="/opt/startup/startup.sh"
STARTUPCOMMAND=$(cat $STARTUP_COMMAND_PATH)
echo "Running $STARTUPCOMMAND"
$STARTUP_COMMAND_PATH
The /opt/startup/startup.sh contains
# Enter the source directory to make sure the script runs where the user expects
cd "/home/site/wwwroot"
npm start
The start script in the package.json for the demo app has "start": "node ./bin/www"
Which then has:
var http = require('http');
var server = http.createServer(app);
server.listen(port);
So the key thing here is that it does npm start to run which then creates a nodejs server to serve the application on port 8080.
The npm start in my application ends up calling react-scripts start, which uses the WebpackDevServer
Whilst you shouldn't use the dev server for production, does that also mean you can't use it on a server for some reason?
This is just a test/demo to familiarise myself with Azure and not production.

The end result is that npm run is running the WebpackDevServer.
This isn't designed for production so we need to have another way of running on Azure.
Changing the Azure webapp Startup command to npx serve -l 8080 build will run the ReactJS application in Azure.
NB: This answer explains how to run it, but not why.
See this other question for why.

Related

How to deploy React Native web app using Expo in Node JS Azure - App Service

When I deploy the application in Azure with Visual Studio Code, I get the following error stack:
2020-10-28T20:34:32.249Z INFO - Initiating warmup request to container appdemo_xxxxxx for site appdemo_xxxxxx 2020-10-28T20:34:37.841Z ERROR - Container appdemo_xxxxxx for site appdemo_xxxxxx has exited, failing site start 2020-10-28T20:34:37.844Z ERROR - Container appdemo_xxxxxx didn't respond to HTTP pings on port: 8080, failing site start. See container logs for debugging. 2020-10-28T20:34:37.874Z INFO - Stopping site appdemo_xxxxxx because it failed during startup.
The Plan de App Service is a SO Linux.
If I change start in package.json to "node index.js" work fine, but if I use this, not work:
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject",
"test": "jest --watchAll"
},
I have created the variables in Configuration -> App Settings PORT = 8080 and WEBSITES_PORT = 80
What am I doing wrong?
I found the solution for this error:
Export the project from the VS terminal: expo build:web --no-pwa
Transfer it using FTP to Azure
Ready!
Remove the PORT setting and change your WEBSITES_PORT to 8080. The start command should be picked up from your "start" script in your package.json. If that isn't working, you can try setting npm expo start as a start-up command under Application Settings blade in the portal or use Azure CLI command az webapp config set --resource-group <resource-group-name> --name <app-name> --startup-file "npm expo start". Also make sure your expo dependencies are being installed correctly. You should be able to verify in your deployment logs. If not, you can customize a pre-startup batch command to run your necessary npm install command.

Service Worker not registered in Heroku - Angular PWA

I am trying to deploy an Angular PWA on Heroku, but I can't seem to figure it out.
The deployed app works great, however no service worker is registered according to LightHouse, therefore it is not a PWA.
Here is the process I am using to deploy :
Run ng build --prod in the angular project
Copy the dist/myapp folder next to my server.js file
Commit and push to heroku.
Before pushing, running npm run start or http-server dist/myapp works just fine locally, a service worker is registered and the app is installable.
Here is my start command in package.json and my post-deploy command in ecosystem.config.js:
"start": "pm2-runtime start ecosystem.config.js --env production"
'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env production',
Note: It uses node.js and express to load an Angular project using this method : app.use(express.static(path.join(__dirname, 'dist/myapp')));
Does anyone have an idea as to why it does not register a service worker on Heroku ?

How to deploy a react app in production over https?

I have a React App that works beautifully over HTTPS using a .env.production file containing:
HTTPS=true
SSL_CRT_FILE=/etc/ssl/certs/mycert.crt
SSL_KEY_FILE=/etc/ssl/private/mykey.key
the package.json file contains:
"scripts": {
"start": "env-cmd -f .env.production react-scripts start",
"build:production": "env-cmd -f .env.production react-scripts build"
}
when I do:
npm start
everything works, and I can access my server over HTTPS from anywhere. Now, this is the funny thing, now I do:
npm run build:production
which also works fine, and I get:
The build folder is ready to be deployed.
You may serve it with a static server:
serve -s build
Now, this is what fails:
1) When I use the serve command above, the environment variables in the .env.production file are not picked up! Why?
2) If I pass the environment variables manually as in:
HTTPS=true SSL_CRT_FILE=/etc/ssl/certs/mycert.crt SSL_KEY_FILE=/etc/ssl/private/mykey.key PORT=8580 serve -s build
Only the PORT variable seems to be picked up, but the server now runs on HTTP. Any ideas why?!
When you run npm start, a development server is started for you under the hood that is configured to pick up the SSL_CRT_FILE, SSL_KEY_FILE and HTTPS env vars automatically.
serve doesn't do that, you need to let it know with these CLI flags:
serve -s build --listen 8580 --ssl-cert "/etc/ssl/certs/mycert.crt" --ssl-key "/etc/ssl/private/mykey.key"

Customizing Azure's npm deployment script

Azure expects by default a start script with the format of node path/to/js/file.
Neither of those things fit my setup. I have a 'start:production' script which is comprised of a series of commands joined by &&.
For example:
"start:production": "npm run build && serve -s -p 3000 dist && npm run --prefix server start",
"build": "node build/build.js",
How can one customize default Azure scripts? I saw you can somehow download and edit the default configuration scripts.
It looks like you are using Azure Web App which runs on Microsoft IIS. If so, you have no need to config the start script in the package.json file, instead, add a web.config to /wwwroot directory and config the entrance file of your node.js app there. Default web.config used for node.js apps could be found here.
And your app can't listen on port 3000 on Azure Web App, you should use process.env.PORT for handling the named pipe port in Azure Web App, see Listen additional port Microsoft Azure Nodejs.
If you want to execute some build scripts after deploying the node.js app you can either use Custom Deployment Script or add postinstall script into package.json like below:
"scripts": {
"build": "node build/build.js",
"postinstall": "npm run build"
}

Can't find entry file when deploying node app to heroku

I'm trying to deploy my first node app to heroku. I have set up a Procfile with the following code
web: node ./app/server.js
but when I deploy to heroku and check the logs I see the error Error: Cannot find module '/app/server.js'.
On local it works fine. I have the following in my package.json nested under scripts
"start": "nodemon ./app/server.js
Nodemon is a utility that will monitor for any changes in your source and automatically restart your server. Perfect for development.
While using nodemon its better to maintain script commands for dev and production as follows:
"scripts": {
"start": "node ./app/server.js",
"dev": "nodemon ./app/server.js"
}
To determine how to start your app, The deployment server( Heroku) first looks for a Procfile. If no Procfile exists for a Node.js app, It will attempt to start a default web process via the start script in your package.json.
If you use nodemon in script, It'll internally try to run node server.js but in your case start file present in app/server.js. To avoid these issues it's better to use two separate script commands for dev and production. So that while running locally you can use npm dev command.

Resources