BIG EDIT SINCE I DID SOME MORE RESEARCH
I'm trying to deploy my first Nodejs/React App on a Cloud-Server using Plesk.
That's what I tried first: I created an .httaccess file with the following contents.
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
Problem with this was, that I didn't have access to express app.js anymore, since react's index.html file handles everything. So the alternative is to route accordingly out of app.js from express. I have found the following approach and trie to implement it.
Approch:
/api/app.js
app.use('/result', resultRouter);
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
My implementation:
var createError = require('http-errors');
var express = require('express');
const cors = require('cors');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
require('dotenv').config();
var helmet = require('helmet');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var resultRouter = require('./routes/result');
var app = express();
app.use(helmet());
app.use(cors());
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
next();
});
//Set up mongoose connection
var mongoose = require('mongoose');
var mongoDB = 'MYMONGODBURL';
mongoose.connect(mongoDB, { useNewUrlParser: true, useUnifiedTopology: true });
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use('/result', resultRouter);
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function (req, res) {
res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
});
app.get('*', function (req, res) {
res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
});
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
While I am sure this is the correct solution in general, I fail to implement it. The app.js file lays in the api folder. Before uploading it to Plesk, I insert the build folder from react inside. So app.js
and the build
folder are on the same level of the directory.
After the upload via git, I have both the document root as well as the application root set to configurator/api. Configurator is just an empty folder I set up beforehand.
If I set document root to configurator/api/build, the starting page of my react index.html file gets displayed. But routing to any other react component doesnt work.
What do I do wrong here? Also I have enabled "browsing for a domain", but still get a 504 Gateway Timeout Error.
I hope someone can point me in the right direction or has some input as to where I should look next.
Thanks in advance
So I know my question is on a real beginner level and in hindsight, I didn't give enough info for someone to help me out here. But I found a solution, that hopefully helps other beginners that are stuck at this point. So I write to share what I learned in the process and also to reflect on it.
Basically there are two ways to get react/express running on Plesk. Both solutions are viable, but tackle different prerequesites.
Solution 1: You want to render a static site via react, that doesnt perform any backend-requests to nodejs.
In this case, you run Çıpm run build
in your react-folder and put the newly created build folder inside your express folder. Inside the build folder, create a .htaccess file with the following content:
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
I think doing it this way, you don't even need nodejs. But I haven't tried it out. Anyway. Upload the folder (let's call it api) to Plesk via git and set document root to api/build, while application root is just api.
Solution 2: You want to render static react, but you perform backend-requests to express for some business logic or database-requests at any point.
As in solution 1, create the build folder and move it into the api folder. The build folder is everything you need from React for your app to work at the end. In the api folder, create a new Javascript file on the root level. Name it server.js. Inside put the following code:
const app = require('./app');
const http = require('http');
http.createServer(app).listen(process.env.PORT);
As I understood, this starts your server in the first place and without you'll get a 504 Timeout-Error.
Second, you need to tell nodejs, that it redirects to react's index.html file, whenever you hit a route, that is not defined in express. For this, open your app.js file. Go right under the last of your express routes and insert the following:
app.use('/result', resultRouter);
// ^ above is the last route of my express app.
// below tells your server to redirect all other routes to index.html from React
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function (req, res) {
res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
});
app.get('*', function (req, res) {
res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
});
After modifying and uploading to Plesk, set both your document root and your application root from the Plesk-Nodejs application to api (or whatever your root-folder is). Then, set the application starting file to server.js. Everything should work now.
Here are some obstacles I had on the way and you might face also.