I'm using react router and everything works fine in development, but the production build of the react app is not working when I visit some routes with more than one parameter for example http://localhost:3000/me/edit.
I tried deploying in netlify with the _redirects file, also with nginx and also with serve. None of the three options worked.
It seems to be requesting a file inside the static folder. I will attach two images so you can see what I'm refering to.
This is what I can see under Sources tab:
When I visit http://localhost:3000/me it works fine and this is what I can see on chrome:
When I visit http://localhost:3000/me/edit if leads to a blank page, and it seems to be requesting a file inside me > static > edit which obviously does not exist; and this is what I can see on chrome:
So, I could finally solve this, the problem was that routes with more than one parameter either static or dynamic (eg: /me/edit or /user/:id) were looking for a file inside a folder, in this case me or user which do not exist.
Here's how I solved it:
I created a folder called 'production' inside this folder I ran npm init, I pasted the entire build folder generated by react. Then I created a file called server.js (which is the entry point I specified). This file contains the following:
const express = require('express')
const path = require('path');
const cors = require('cors')
// Initializing express
const app = express()
// Initializing middleware to indicate express where to serve the static files from:
app.use(express.static(path.join(__dirname, 'build')));
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.use(cors())
const PORT = process.env.PORT || 4000
app.listen(PORT, () => console.log(`Server listening on port ${PORT} 🔥`))
In addition, I added this: <base href="/"> to my index.html file inside the build folder.
On the package.json I added the start script "start": "node server.js" and that's it, never was typing npm start so satisfactory 😂
The entire project now looks like this:
Related
My image is stored in the server folder and my react app folder is food
enter image description here
I wanted to call images from server(server>uploads>foods) folder to food(food>src>home). I was used back path like as (../) but it doesn't work.
So, how I can call images from the server folder to the food folder in react
How can I call image from outer folder of my react-app folder in react.js
I assume, you have to fetch image from server folder, which is your express.js application.
The images, CSS files, JavaScript files, and other files that the client downloads from the server are known as static files. These static files can be fetched with the use of the express framework and without the use of it.
you may have following directory tree:
server.js
package.json
package-lock.json
nodemodules
| -- *
uploads
-food
| -- demoImage.png
public
| -- index.html
Using the Express framework: Using the express framework its built-in middleware function express.static() can be used to serve static files.
Filename: server.js
// Requiring module
const express = require('express');
// Creating express object
const app = express();
// Defining port number
const PORT = 3000;
// Function to serve all static files
// inside public directory.
app.use(express.static('public'));
app.use('/images', express.static('images'));
// Server setup
app.listen(PORT, () => {
console.log(`Running server on PORT ${PORT}...`);
})
Steps to run the program:
Install express:
npm install express
Run the server.js file using the following command:
node server.js
Now you can access image from following url:
http://localhost:3000/images/demoImage.png
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
I'm trying to deploy my first React app on Heroku. I used simple json files for the backend.
Locally, everything runs good: my server is on localhost:8080, and frontend axios calls gets data from it like so:
axios.get(localhost:8080/bench).then( (response) => {
// my logic here
})
My deployment flow is:
to run a npm build and put everything in the build folder into the server end's public folder. Here's the entry-point file:
const path = require("path");
const publicPath = path.join(__dirname, "public");
console.log(publicPath);
app.use(express.static(publicPath));
app.get("*", (req, res) => {
res.sendFile(path.join(publicPath, "index.html"));
});
push to build artifacts to Heroku
Doing so, everything from the frontend part runs good on Heroku.
My concern is that I can't figure out what axios calls I should use for the frontend to get the data from the server. Is there anything I am missing?
Localhost only works on your machine. In your frontend, you'll need to change the axios url to point to the URL of your deployed server like so:
axios.get(`${YOUR_HEROKU_URL}`/bench)
I am trying to add ssl to my heroku server using certbot.
However, the issue I am finding is that I need to create a url to verify my domain -- which is the issue as I cannot seem to add both my server code as well as my client side code to the same heroku server (and get them to both run at the same time which I need to verify the domain..)
Try this:
Begin a certbot manual certificate: sudo certbot certonly --manual
Follow the prompts until you get to the part that says to make a file available at a specific like like yourdomain.tld/.well-known/acme-challenge/longstring123 Do not press Enter to Continue! Take note of both the URL and the "file" data it gives you.
In your server.js, add something like the following:
app.get('/.well-known/acme-challenge/your-long-url-string', function(req, res) {
res.status(200);
res.send('your-long-verification-file-data');
});
Make sure that this Express route handler is above the one you use for React.
I had a similar problem and spent hours trying to figure this out today. My problem was I kept getting a 404 error when trying to access .well-known/acme-challenge/{verification_file}.
The problem wasn't React or Heroku, the problem was that I was using serve -s build (package serve-handler) to serve my app, this is an static server and it won't let you fetch files without an extension. There might be a way to configure it, but I don't know how. Maybe setting headers... Anyhow, I tried files with .txt and it works, but without an extension it redirects to 404.
So instead removed my static server and added ExpressJS to serve the app instead.
To accomplish this:
Step 1
In your project folder run:
npm i express path
Step 2
Create a file in your project folder called server.js and add this code to it. This code will initialize and serve your project.
const express = require("express");
const path = require("path");
const app = express();
app.use(express.static(path.join(__dirname, "build")));
app.get("/*", function (req, res) {
res.sendFile(path.join(__dirname, "build", "index.html"));
});
app.listen(process.env.PORT || 80);
Step 3
If your package.json file under scripts make sure Heroku will initialize your project correctly when deployed:
"scripts": {
...
"start": "node server.js",
...
}
This should do it. Now your project is served by a dynamic server and it will delivery files without an extension. You can remove your serve package now if you aren't going to use it anymore.
Reading
Couple links that might be useful:
https://create-react-app.dev/docs/deployment/
https://expressjs.com/en/starter/hello-world.html
The Problem
I have successfully served the index.html file of my React app, but the index.js that replaces <root> in the html file
with my first React component is not triggering on ReactDOM.render.
How do I get the index.js file to start? If my understanding of serving a React app is skewed in certain ways, I would greatly
appreciate clarification.
Folder Structure
/ - contains all server-side files, including server.js
/client/ - contains all React files
/client/build/ - contains all production-ready client files
/client/build/index.html
/client/build/static/js/main.[hash].js - seems to be a minified version of index.js that contains the ReactDOM.render for
my React app
Current Deployment
I am using Facebook's create-react-app for the /client/ directory, including npm run build to automatically populate /client/build/
File Snippets
// server.js
let app = express();
app.use(express.static(path.join(__dirname, '../client/public')));
This successfully loads the default index.html provided by
create-react-app
// index.html
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
</body>
The above section of code may/may not be useful, but it is the default
html file that comes with create-react-app. Do I need to replace the
noscript tag with a script tag that references the minified index.js
file? I have attempted that, and nothing changed, but perhaps it is
because of incorrect relative path-making.
After trying many different things through trial/error, the solution is quite simple:
Serve the /client/build folder in the static call, like so:
app.use(express.static(path.join(__dirname, '../client/build')));
I had the same problem for a while and I would say that the solution that works is divided into 2 parts to avoid problems with the routers
Server the static from the CRA build (in your case the client/build)
const buildPath = path.normalize(path.join(__dirname, '../client/build'));
app.use(express.static(buildPath));
Set a final route (after all other routers in your server) to use the following:
const rootRouter = express.Router();
/*
* all your other routes go here
*/
rootRouter.get('(/*)?', async (req, res, next) => {
res.sendFile(path.join(buildPath, 'index.html'));
});
app.use(rootRouter);
//on your react app run
npm run build
//The insert the following code on your server
const path = require("path");
app.use(express.static(path.join(__dirname,"nameOfYourReactApp","build")))
//Replace nameOfYourReactApp with the name of your app
my project structure
project
-->client
back end(express)\
after using npn run build i found out that index.html in build was using wrong directory of css files or static instead of using
const path = require('path');
app.use(express.static(path.join(__dirname, '/client/build/')));
i know i also tried ../client...... but not working
so what i did is cut and paste static folder of build in root directory this image can give you the idea, and its working structure