serving react files with express - reactjs

This is my first time serving react files with express.js. The build has been run and the server is listening, but I cant figure out why the components aren't being injected into the html file. Instead it's rendering just the html template.
Here is a picture of my build folder:
build folder structure
Here is my index.js file from my server folder:
const express = require('express');
const morgan = require('morgan');
const path = require('path');
const app = express();
app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method
:url HTTP/:http-version" :status :res[content-length] :response-time
ms'))
app.use(express.static(path.resolve(__dirname, '..', 'build')))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname,'..', 'build', 'index.html'))
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}!`);
});
this what I see in the console:
served page console
Any help would greatly be appreciated.

This question is still unanswered and Im facing the same question. I have deployed the default react app to a build-directory and am hoping to serve the files through Express.
The browser actually received the deployed file BUT it shows me a blank page.
Any ideas?
Using a simple Express server:
const express = require("express");
const path = require("path");
const app = express();
app.use(express.static(".\build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, ".", "build", "index.html"));
});
app.listen(8081, () => {
console.log(App listening on port 8081!);
});

See the following link
react-express-boilerplate
Add the following code to index.html file
<script src="src="/js/main.33e13313.js""></script>
main.33e13313.js is a file that packages js with webpack.
Your package.json file will be set as follow:
"scripts": {
"clean": "rm -rf build public/bundle.js",
"build": "babel server --out-dir build && webpack",
"start": "NODE_ENV=production supervisor ./build/main.js",
"development": "NODE_ENV=development node ./build/main.js"
},
You will use npm run build to run.
You can use babel to change es6 to es5. this is build tool.
You can use webpack to package JavaScript files. packagig is bundles JavaScript files into one file. this is packaging tool.

Related

React application hosted on GCP using Docker only opens when i type the URL folowed by "//" double slash

So basically i have deployed a react application on docker using express to serve my build folders. But the after i deployed the application only opens when i follow the url with "//".
I have set the homepage property of package.json to "."
The main js chunk will not load if i just type the application URL . It will load only if the application url is followed by double slash for example https://example.com//
Can any one please make me understand why might this behavior occur? Following is the code for the server.js
const path = require("path");
const express = require("express");
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, "..", "build")));
app.use(express.static("public"));
app.use((req, res, next) => {
res.sendFile(path.join(__dirname, "..", "build", "index.html"));
});
app.listen(PORT, () => {
console.log(`Server started on PORT ${PORT}`);
});
Dockerfile
FROM node:16 AS ui-build
WORKDIR /usr/src/app/
COPY . .
RUN npm install && npm run build
EXPOSE 3000
ENV PORT 3000
ENTRYPOINT ["node", "server/server.js"]
package.json
{
"name": "app",
"version": "0.1.0",
"homepage": ".",
"private": true,
"dependencies": {...
}

I would like to alter the way create-react-app builds my app

So I would like to make npm run build to produce local runnable files. Basically, I want it to build index.js with importing assets like ./static/js/chunk.js instead of /static/js/chunk.js. The client I am running this on does not have internet access so I want to serve the app from the file system.
Basically, I want to open index.html in the build folder with chrome and the app just work. Any ideas on how to do this?
Using simple node js and serve it as static is the best way because react router dom need url in the app.
const express = require("express");
const path = require("path");
const app = express();
app.use("/static", express.static());
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "frontend", "build", "index.html"));
});
app.listen(6000, () => console.log("Listening to port 6000"));
Next to node file index.js, or whatever you name it, make the folder called frontend. Inside it put your build from react so the node can serve index.html in port 6000

Having trouble deploying React-Express app to Heroku

I'm trying to deploy a MERN app (built with create react app) to Heroku, but whenever I try to access the app URL, it returns with a 404 error.
I've checked the Heroku error log, which has returned the following errors:
app[web.1]: ls: cannot access '/app/build/static/js/*.js': No such file or directory
Error injecting runtime env: bundle not found '/app/build/static/js/*.js'. See: https://github.com/mars/create-react-app-buildpack/blob/master/README.md#user-content-custom-bundle-location
I've structured my project so that it runs on two different servers: client side on localhost:3000, which proxies requests to express at localhost:5000.
I've run npm run build, set up static middleware, and tried to configure my api calls/routes correctly, but it still isn't working. Any suggestions as to why, and how I can fix it? Details as follows:
Project Structure
+client
|
+-build
+-static
+-css
+-js
+-media
+-node_modules
+-public
+-src
|
+-components
+-App.js
+-index.js
//server
+-models
+-node-modules
+-package-lock.json
+-package.json
+-server.js
Proxy (in package.json):
"proxy": "http://localhost:5000"
Heroku build scripts (in client/package.json):
"scripts": {
"start": "react-scripts start",
"heroku-postbuild": "cd client && npm install --only=dev && npm install && npm run build",
Server config:
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Listening on port ${port}`));
//Middleware
app.use(express.static(path.join(__dirname, 'client/build')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.urlencoded())
app.use(cors())
app.get('*', (req,res) =>{
res.sendFile(path.join(__dirname+'/client/build/index.html'));
});
Here's how I;ve structured my APIs. Note: I've removed the 'localhost:5000' from the URL of my axios requests:
API call from React component:
useEffect(() => {
axios.get('/api/all-reviews')
.then(review => {
setReviews(review.data)
})
.catch(err => {
console.log(err)
})
},[])
Corresponding express route
app.get('/api/all-reviews', (req,res) => {
Review.find()
.then((result) => {
res.send(result)
})
.catch(err => {
console.log(err)
})
})
You have two options,
#1 - make all urls relative, e.g. fetch('/api/all-reviews'), and have both the frontend and backend running on the same server. Serve the static build files from your backend (found in the build folder after running npm run build, assuming you are using create-react-app) using the express.static middleware.
Note that you can do this in production while still relying on a proxy in development using process.env.NODE_ENV. An example implementation would be
// put this at the end of your server.js file
if (process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, '../client/build')));
}
#2 - run the backend and frontend on different servers, and just adjust the path based on whether the code is running in development or production
Just as an example:
const prefix = process.env.NODE_ENV === 'production' ? "http://heroku_app_address" : "http://localhost:5000"
function getUrl(relativeUrl) {
return prefix + "/" + relativeUrl;
}
fetch(getUrl('api/all-reviews'));

Heroku redirect Next.js React client app http to https

I have an express server deployed on Heroku: https://server.mydomain.com
and a Next.js React app also deployed on Heroku: https://app.mydomain.com
Both have their SSL certificates automatically configured by Heroku, and when I visit the https domains, they work as expected.
The problem I have is that when I visit http://app.mydomain.com, it does not redirect to https://app.mydomain.com.
All the solutions I've found online point to forcing SSL on the server:
this popular question says to check for the x-forwarded-proto value:
/* At the top, with other redirect methods before other routes */
app.get('*',function(req,res,next){
if(req.headers['x-forwarded-proto']!='https')
res.redirect('https://app.mydomain.com'+req.url)
else
next() /* Continue to other routes if we're not redirecting */
})
and others suggest using a package like express-sslify or heroku-ssl-redirect.
These solutions work fine for the server requests, but loading a React client page does not necessarily trigger app.get(). Obviously, a React client can run independently of a server.
So the question is: How does someone force https for a subdomain Next.js React client app on Heroku? Without using express server methods?
I do this in one of my production applications.
We prepare the next app object and init an express server. This is done in the server.js file. You can read more about it in the docs about a custom server.
Next.js also has an example in their github in the examples folder about a custom express server. It's here.
const express = require('express');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app
.prepare()
.then(() => {
const server = express();
server.use((req, res, next) => {
const hostname = req.hostname === 'www.app.domain.com' ? 'app.domain.com' : req.hostname;
if (req.headers['x-forwarded-proto'] === 'http' || req.hostname === 'www.app.domain.com') {
res.redirect(301, `https://${hostname}${req.url}`);
return;
}
res.setHeader('strict-transport-security', 'max-age=31536000; includeSubDomains; preload');
next();
});
server.get('*', (req, res) => handle(req, res));
server.listen(
4242,
error => {
if (error) throw error;
console.error('Listening on port 4242');
}
);
})
.catch(error => {
console.error(error);
process.exit(1);
});
As for deploying to Heroku you should be able to just customize the npm start script to start nextjs like so:
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
Heroku also runs npm run build automatically so it should build the app for you.
Heroku does not currently "offer out of the box" functionality to force the use of https for node apps.
However, with the release of Nextjs v12 you can accomplish this without having to setup a custom server and use middleware instead.
See this answer for example code and advantages of middleware vs custom server.
I also published a npm package to handle this:
import sslRedirect from 'next-ssl-redirect-middleware';
export default sslRedirect({});

using express with create-react-app doesn't need to call app.get()?

I made a tiny web app and tried to deploy it by following the instruction of Official Tutorial. I ran npm run build successfully, then I copied the index.js from the tutorial and modified a little bit:
const express = require('express');
const path = require('path');
const app = express();
const auth = require('basic-auth'); // A
app.use(express.static('./build'));
app.get('/', function (req, res) {
const credentials = auth(req); // B
res.sendFile(path.join(__dirname, './build', 'index.html'));
});
app.listen(9000);
where line A and B are for checking authorization. When launching the server by node index.js, visiting localhost:9000 could receive the built index.html as expected. However, the line B was not processed at all. I had no idea what's going on, so I tried to remove the whole app.get call and launch the server again:
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static('./build'));
app.listen(9000);
Surprisingly, everything still worked normally when visiting localhost:9000. Is it the correct behavior?
P.S. I find a feasible workaround: Rename the build/index.html file as , says build/index2.html, and call
res.sendFile(path.join(__dirname, './build', 'index2.html'));
instead. Is the file index.html special to express?

Resources