Page reload or pasting url gives 404 with MERN stack - reactjs

I am building a simple website that uses MERN stack running on apache.
There is a proxy (& reverse proxy) settings on /api to route to ip:port/api
At some point in the last couple of months, any page refresh or pasting urls causes a 404. I cannot identify what causes this.
It is using client side routing (based and it was working. It is still working on localhost only breaks on the server.
Now when I put the old code that used to work on the server, it breaks the same way. This suggests that a change in the environment is causing/contributing.
One developer I was working added this piece of code to try to address it.
if (process.env.NODE_ENV === "production") {
// Set static folder
app.use(express.static("client/build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
});
}
It doesn't seem to have any effect even if I remove the if condition. I did a little test.
I added an image with name 'register'
If I go to my website and click on register it works
If I visit domain/register, it is showing the image, so even with the code snippet above it is treating it as a request for static file and not letting it pass on and resolve to the index.html
About the server
Ubuntu with Apache with proxy on /api to node server
Uses a self signed certificate but it breaks on http or https.
This seems to be a common problem. If anyone has seen this before or can give pointers on where to debug this, I would appreciate it.

Trying this code worked for me. And refer this for the difference between path.resolve and path.join
if (process.env.NODE_ENV === 'production') {
const root = path.join(__dirname, 'client', 'build');
app.use(express.static(root));
app.get('*', (req, res) => {
res.sendFile('index.html', { root });
})
}

Related

live reload when running express with CRA

I have my create react app setup similar to this setup. https://www.newline.co/fullstack-react/articles/using-create-react-app-with-a-server/
All is working great so far.
when I'm running on localhost:3000 i'm seeing hot reloading as CRA dev server is taking care of that for me.
Now when I run my app using my express server localhost:8081 i'm loading my html file and assets from CRA build folder which obviously means I'm only going to get the built files.
What i'd like to do is when running in port localhost:8081 I can get a reload of development changed files and not just the static build files.
The reason for this is let's say I'm using an authentication setup where I need to check if user is logged in before I allow the * route to proceed otherwise redirect to another route in express. I want to be able to check for this when working in development.
If I run the dev server localhost:3000 then I no longer get the route change loading my html files from express. Only the api call would work from express.
Here is my setup in express:
const express = require("express");
const path = require("path");
const PORT = process.env.PORT || "8081";
const app = express();
const indexPath = path.join(__dirname, "../build/index.html");
app.use(express.static(path.resolve(__dirname, "../build"), { index: false }));
app.get("/test", (req, res) => {
res.json({ message: "welcome to backend" });
});
app.get("*", (req, res) => {
console.log("sending index.html");
res.sendFile(indexPath);
});
app.listen(PORT, () => console.log(`listing on port ${PORT}`));
This express route will only work when using in localhost:8081 which is getting the build files.
app.get("*", (req, res) => {
console.log("sending index.html");
res.sendFile(indexPath);
});
But this never runs when working in dev server localhost:3000 so I can not do any authentication on this route when working in development mode. This would mean to test this I would have to keep rebuilding the build folder which is crazy.
I'm running my client in one terminal and my server in another. I also restarted both multiple times. The proxy as I said works in my package file for the /test route when called using fetch .
This a similar unanswered question I found:
create-react-app + nodejs (express) server

how to deploy an express/react to apache

I have a project that has a react app inside the express server. I would like to deploy it to my own CentOS/Apache server. How i can i do this? I've done some google and seen AWS things, and i just doesn't seem like it needs to be that complicated. I really just want it to run on my server so i can show other people and do testing. I do have a spare computer to create another nginx server if needed (or whatever else you guys reccomend).
Ive also added this code to my server.js file. which aparently isnt enough. Thanks for all help!
if(process.env.NODE_ENV === 'production'){
//SET STATIC FOLDER
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(_dirname, 'client', 'build', 'index.html'));
})
}

Shopify App Proxy - How to include my asset files in the request response | React / JS / Heroku

I'm building a Shopify App with React & Express, deployed via Heroku, which I'm trying to embed into my storefront using an Application Proxy.
When I finally load the proxied URL on my store - I get a blank screen and a bunch of 404's in the console for my .css and .js chunk files. The request was sent, authenticated, and my API's response is (200) - it just won't render anything.
Finally, after much research, I realized that Shopify has changed the path to these CSS and JS files to be my-store.myshopify.com/hash.chunk.js etc. instead of the reference to my Heroku server.
It appears this problem has been encountered before in this thread: Shopify app - how to include assets using an app-proxy with ruby on rails However, I can't seem to find a node/react/heroku equivalent to the Ruby solution presented here.
Any guidance or help would be greatly appreciated!
I begin by serving my React App through express with:
app.use(express.static(path.join(__dirname, 'client/build')));
and then when my proxy URL is hit I send back the index file within the client/build folder:
router.get('/proxy', (req, res) => {
res.set('Content-Type', 'application/liquid').sendFile(path.join(__dirname, '../client/build/index.html'));
});
I've managed to find a working solution to my problem after much trial and error.
The homepage in package.json is important. I had it set to just my Heroku address when it should actually be set to herokuaddress.com/YOURPROXYROUTE (i.e. /app/my-app)
Some additional middleware is required as well - for those interested I have the following routes set up to field requests from Shopify's app proxy.
This is set up above any of my route imports in server.js:
app.use(express.static(path.join(__dirname, 'client/build')));
and these routes are imported below that from a /shopify-routes.js file:
router.get('/proxy', (req, res) => {
res.set('Content-Type', 'application/liquid').sendFile(path.join(__dirname, '../client/build/index.html'));
});
router.get('/proxy/static/css/:file', (req, res) => {
res.set('Content-Type', 'text/css').sendFile(path.join(__dirname, `../client/build/static/css/${req.params.file}`));
});
router.get('/proxy/static/js/:file', (req, res) => {
res.set('Content-Type', 'text/javascript').sendFile(path.join(__dirname, `../client/build/static/js/${req.params.file}`));
});
Though this may be a bit heavy-handed, it has solved the problem and the app is loading within the Shopify storefront now.

React Routes not working on Server but work locally

I can go to the site index www.mysite.com and from there use the app navigation to go to www.mysite.com/login but I can't go directly to www.mysite.com/login as it gives a 404 message.
However this is working in localhost, where I can go straight to https://localhost:3000/login and it will load up the app with the login page route.
How can I get this to work on my Nginx server as-well?
You need to redirect all requests to index.html.
Refer to this for server configuration or you could redirect using server side like node or whatever server side you are using.
Try this in your server.js file
app.use("/users", require("./routes/users")); app.use("/groups", require("./routes/groups")); app.use(express.static(__dirname + "/client/build")); app.get("/*", (req, res) => { res.sendFile(path.join(__dirname, "client", "build", "index.html")); });

Simple password-protection for React app on Heroku

I have a simple React app, created with create-react-app, that I'd like to deploy to Heroku (or somewhere easy) and password-protect. The protection can be really simple—just a single password is fine.
I started looking into HTTP basic auth but didn't find an easy answer. The closest I found was in this post, but (a) I don't love the idea of having to eject my app, and (b) I couldn't get it working. I was hoping I could find a Heroku plugin, but no luck there either.
It wouldn't be too hard to write a component that wraps my app and requests a password before showing it. The problem is that it executes client-side. I want to store the correct password server-side (or a hash thereof), and have the app send password attempts up to the server.
Since create-react-app operates on top of Node, I'm hoping there's an easy way to tell it to execute and store certain things on the server, but maybe I'm wrong. Any suggestions?
This create-react-app buildpack seems to support http basic auth:
https://github.com/substantial/create-react-app-buildpack
https://elements.heroku.com/buildpacks/substantial/heroku-buildpack-static
I am assuming your intentions are wanting to protect the config vars in heroku so other people cannot access you database with your credentials.
The way I password protected my deployment to heroku, is to make a keys_prod.js file containing the Heroku config vars of my mLab database in my backend using express and mongoDB:
keys_prod.js file:
module.exports = {
mongoURI: process.env.MONGO_URI,
secretOrKey: process.env.SECRET_OR_KEY
};
keys.js file:
if (process.env.NODE_ENV === 'production') {
module.exports = require('./keys_prod');
} else {
module.exports = require('./keys_dev');
}
in my server.js file I added:
// DB Config
const db = require('./config/keys').mongoURI;
// Server static assets if in production
if (process.env.NODE_ENV === 'production') {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
This allows you to request the config vars you filled in heroku without including it in your repo.
If you use Node in backend you can use Passport Basic Auth
app.get('*', passport.authenticate('basic', { session: false }), (req, res) => {
res.sendFile(path.join(`${__dirname}/../build/index.html`))
})
Every time you access the page in browser, a popup will appear, asking you username and password.

Resources