React app (via create-react-app) with Express backend in single Azure app?

I have a React front-end app with an express backend that’s working locally as a proxy API server.

In my local dev environment, the React fonr-end is running on port 3001, with the Express server running on port 3000.

In my package.json, I have the proxy set up:

"proxy": "http://localhost:3000",...

The app is deployed via an Azure pipeline, which builds the app and the server, zips them up, and copies the artefacts to an Azure domain.

In the Azure app’s Configuration, I have the following Startup Command:

node server & npx serve -s

This should (in theory) start the Express server (which is set to listen on port 3000) and server the front-end. The front-end is indeed accessible, but when it tries to make a call to the api via a simple fetch request, it’s returning the HTML of the React app instead of a JSON response. This indicates to me that it’s not actually exposing the Express port to the front end.

Is it actually possible to server the Express server and the frontend as part of the same container?

Answer

It turns out that this approach – while it was the wrong one – was in fact working, but Azure App Services will only expose a single port. In this case, we could either expose the React front end via npx serve -s OR expose the api by setting the PORT variable to 3000. Both were running, but only one could be reachable.

The solution was to serve the React front-end via the Express server:

const path = require('path');
const { response } = require('express');
const express = require('express');
const request = require('request');
const app = express();

app.use(express.json());

app.use(express.static(path.join(__dirname, '../')));

app.use('/api', function (req, res, next) {
    // API function calls here
    ...
});

app.get('*', function(req, res, next) {
    res.sendFile(path.join(__dirname, '../index.html'));
});

app.set('port', 3000);

app.listen(app.get('port'), () => {
    console.log('Proxy server listening on port ' + app.get('port'));
});

And set the PORT container variable to 3000.