Create React App not reloading with Express in development - node.js

I created a basic react app with Create React App. I removed all default files and added this into index file.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class App extends Component {
constructor() {
super();
this.state = {};
}
async componentDidMount() {
const response = await fetch('/express_backend');
const json = await response.json();
this.setState({ data: json.express });
}
render(){
return (
<div>{this.state.data}</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
This app works. I can add some letters between divs and it reloads when saving. But when I add simple Express server the reloading stops. I also add "proxy": "http://localhost:5000/" into package.json inside CRA to connect server and client
Here is the server
const express = require('express');
const app = express();
const port = 5000;
app.listen(port, () => console.log(`Listening on port ${port}`));
// create a GET route
app.get('/express_backend', (req, res) => {
res.send({ express: 'YOUR EXPRESS BACKEND IS CONNECTED TO REACT' });
});
I restarted both Create react app and server in console but now when I add smth between divs in the component nothing is reloading. I guess webpack dev server starts working improperly.
How can I make reloading in CRA work and make request to express each time when I change smth in component?

When running create-react-app with express, you'll need to run your server.js express app in a separate node process than the react-js-app. Also, you'll need to specify the proxy in your package.json.
Utilize these commands in separate terminals:
node server.js
and in separate terminal:
npm start
Kudos to this tutorial: https://dev.to/loujaybee/using-create-react-app-with-express

Related

Jest and supertest: Test keep exceeding timeout

Hello I am a bit confused by this error I have encountered.
I am working on an Universal React App using Webpack 5 and Express.
I want to implement Jest support by using the React-testing-Library for the frontend (which work) and supertest for the backend (this is where I am blocked).
I am following this basic tutorial recommended by the jest doc himself in order to use jest on an node express environment.
But everytime I get this error:
thrown: "Exceeded timeout of 5000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
Here are my code:
server.js
import app from './app.js';
import { mongooseConnection, disconnectMongoDB } from "./routers/services/url/urlDB.js"; // we call mongooseConnect var to connect only once into the mongoDB database
const PORT = process.env.PORT || 8080;
// the server listen on the port set by node on localhost.
app.listen(PORT, () => {
console.log(
`Server listening on \x1b[42m\x1b[1mhttp://localhost:${PORT}\x1b[0m in \x1b[41m${process.env.NODE_ENV}\x1b[0m`,
);
});
// when when we shut down the app we execute a callback function before closing the server
process.on('exit', function() {
disconnectMongoDB();
});
app.js
import express from 'express';
import path from 'path';
import cors from 'cors';
import {envIsProduction, envIsDevelopment} from './envmode/envUtil.js';
import { enableHMR } from './reload/hotReload.js';
let app = express();
// if we have set the environnent on production then:
if (envIsProduction()) {
console.log(" _______________________________________ ");
console.log("| |");
console.log("| ( PRODUCTION ) |");
console.log("|_______________________________________|");
console.log(" ");
app.use(express.static(path.join(__dirname,'../client'))); // we serve static file like the bundle-app.js to the browser from the current directory where the server is executed and we move to the top root to access the file
}
else if (envIsDevelopment()) {
console.log(" _______________________________________ ");
console.log("| |");
console.log("| ( DEVELOPMENT ) |");
console.log("|_______________________________________|");
console.log(" ");
enableHMR(app); // we enable the Hot MPodule Reload on the frontend and the backend
}
app.use(cors());
app.use(express.urlencoded({extended:false}));
app.use(express.json());
//Hot reload!
//ALL server routes are in this module!
app.use((req, res, next) => {
require("./routers/routers")(req, res, next);
});
export default app;
routers.js
import renderPage from "./renderpage/renderPage.js";
import { serverRoutes, reactRouterRoutes, getReactRouterRoutesString } from "./routes.js";
import express from "express";
import routerLoginDB from "./request/routerLoginDB.js";
import routerSignupDB from "./request/routerSignupDB.js";
const router = express.Router();
// Put all your server routes in here
// When the user connect to the root of the server we send the page
router.get(serverRoutes.root, renderPage);
// When the user send a get request by the /click route a console.log and a respone is send.
router.get(serverRoutes.click, (req, res)=>{
res.status(200).send("Click");
});
// when this user want to login into his account, we ask for the routerLoginDB to handle it
router.post(serverRoutes.login,routerLoginDB);
// when this user want to signup into his account, we ask for the routerSignupDB to handle it
router.post(serverRoutes.signup, routerSignupDB);
// For all the routes that only react-router need to use, if we refresh on a nested route of the react-router from the client side then we redirect it to the root route "/"
router.get(reactRouterRoutes,(req,res) => {
res.redirect("/");
});
router.get("*", (req,res) =>{
res.status(404).send('page not found');
}); //For all other type of request excluding the one specified here, we send back a 404 page;
module.exports = router;
app.test.js
import request from '../utils/test-node-utils.js'
describe("Test the /click path", () => {
test("It should response the GET method", () => {
return request
.get("/click")
.expect(200);
});
});
and finally test-node-utils.js
import supertest from "supertest";
import app from "../serverside/app.js";
const request = supertest(app);
export default request;
Don't believe what the error say because I think it is more deep than that.
I have tried to increased the jest timeout value but it keep being stuck and reach the timeout limit.
I have done exactly like the tutorial say without using my project structure and it worked but when I try to implement the tutorial in my backend structure, it don't work with supertest.
I think it is related to my files or backend structure that make it don't work with the test.
Thanks in advance for your help
I've recently debugged a similar issue where my Jest tests would run successfully (or not) in my dev. environment but when I would try and package the app as a Docker image all my tests would time out.
It turned out that by commenting out the line which setup CORS, which for me I only turned on in production builds (should have been a clue), the tests started to run again when building the image.
...
const NODE_ENV = process.env.NODE_ENV;
const app = express();
NODE_ENV.toUpperCase() === 'PRODUCTION' && app.use(cors);
...
I mentioned this as I can see from your snippet above that you are also using the cors middleware and that, in your case, it's set all the time.
Perhaps not your issue, and you may want CORS in your tests for some reason, but try commenting it out and see if your tests run.

Proxy error: Could not proxy request /users from localhost:3000 to http://localhost:5000/

I am trying to create a simple react app with node/express for the backend. When I start my app I get this error:
Proxy error: Could not proxy request /users from localhost:3000 to http://localhost:5000/.
See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (ECONNREFUSED).
My front-end package.json looks like this
The front-end is pretty simple. fetchUserData() under useEffect() is what calls the backend.
import React, { useEffect, useState } from "react";
function App() {
let [userData, setUserData] = useState([{}]);
useEffect(() => {
const fetchUserData = async () => {
const response = await fetch(`/users`);
const data = await response.json();
setUserData(data);
};
fetchUserData();
}, []);
return (
<div>
<h1>Hello React World!</h1>
</div>
);
}
export default App;
The backend is pretty barebone as I just started this project. I have no problem getting the correct response if I just request http://localhost:5000/users directly from the browser or postman:
const express = require("express");
const app = express();
const port = process.env.PORT || 5000;
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.get("/users", (req, res) => {
console.log(req);
res.json({ users: ["Bob", "Sally"] });
});
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
The error message appears when I try to load the front end on http://localhost:3000 which should then fetch the backend resource. I look at the network tab of chrome and for some reason it is going to port 3000 instead of 5000:
I've tried the below but no luck:
Closing my app. Deleting package-lock.json and node_modules, reinstalling them.
Add '/' to the end of the string for the "proxy" setting in package.json
Replacing localhost with 127.0.0.1 in package.json
Tried adding "--ignore client" to dev script in server package.json
Tried adding "secure": false in client package.json
Edit 1: This issue is driving me crazy. If I remove the proxy from package.json, add cors to the server side, and use the absolute path of the endpoint instead of the relative path in my client-side fetch request, it works. But I would much rather use the relative path.
import React, { useEffect, useState } from "react";
function App() {
let [userData, setUserData] = useState([{}]);
useEffect(() => {
const fetchUserData = async () => {
const response = await fetch(`http://localhost:5000/users`);
const data = await response.json();
setUserData(data);
};
fetchUserData();
}, []);
return (
<div>
<h1>Hello React World!</h1>
</div>
);
}
export default App;
Just don't use 'localhost'. Put everything as 127.0.0.1
Font: hours trying every solution possible.
From trying to replicate your issue I think in your proxy you have "proxy": "http://localhost:5000/", but then you also pass a fetch request for "/users" which would lead to a "http://localhost:5000//users.
I would imagine that when you were trying to figure this out that the issue was that you didn't restart your React App after changing the package.json to include the Proxy, and then by the time you restarted the React App, you had already added the extra "/".
Also in your browser console.log when, no matter where your proxy is it will come up with http://localhost:3000 as the address rather than your actual endpoint - it can be a bit of a red herring
Hope it helps
I finally got it to work!
After a lot of experimenting, I realized that this was indeed an environment problem. That explains a lot since the many other suggestions I tried worked for other people but not for me.
What had happened was that my client-side was using wsl for the terminal yet my backend was using PowerShell. When I switched both to wsl it worked. Or when I switched both to Powershell it also worked.

React and Node app deployed on Azure web app shows JSON result instead of HTML page

I have a react app with node backend. I deployed it to Azure Web app , everything works fine.
When i open the url, i can see the application getting loaded and the data from the node app also getting fetched and displayed on the front end.
But when the user navigates to certain routes, it shows JSON which is served by the Node backend rather than a web page that should be displayed
Server.JS
import express from 'express';
import path from 'path'
import dotenv from "dotenv";
dotenv.config();
/* Create an Express application.*/
const app = express();
const __dirname = path.resolve();
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
routes.forEach(route => {
app[route.method](route.path, route.handler);
});
if (['production'].includes(process.env.NODE_ENV)) {
const root = path.join(__dirname,'..', 'client', 'build')
app.use(express.static(root));
console.log(root);
app.get("*", (req, res) => {
res.sendFile('index.html', { root });
})
}
const dBConnectionString = process.env.CON_STRING|| "";
const PORT = process.env.PORT || 8080;
db.connect(dBConnectionString)
.catch(err => {
console.error(err.stack);
process.exit(1)
})
.then(app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
}));
And the react app is deployed inside the wwwroot/site/client/build folder. I am using PM2 command as a startup command to run the app,
pm2 start ecosystem.config.js --no-daemon
and ecosystem.config.js
module.exports = {
apps: [{
name: "node",
script: "./server.js",
cwd: "/home/site/wwwroot/server/"
}
]
}
when i access this url https://web.azurewebsites.net/books/60ea9a3caffa68e153835489 it return a json where it should show a web page.
Should i run the the node app and react app in different ports? how to configure that in pm2?

How to Render a React App Using an Express Server in Node.js?

what i want to achieve is that i want to make a post request to the node server, and then extract the body from the post request then i want to render my react app (which contains routing) with the body i have extracted from the post request
i am using the following code in the server i created in my react app
import express from "express";
import fs from "fs";
import path from "path";
import React from "react";
import ReactDOMServer from "react-dom/server";
import App from "../src/App";
//import sasa from "../build/index.html"
const PORT = 8000;
const app = express();
app.use("^/$", (req, res, next) => {
fs.readFile(path.join(__dirname, "..", "build", "index.html"), "utf-8", (err, data) => {
if (err) {
console.log(err);
return res.status(500).send("Some error happened");
}
return res.send(
data.replace(
'<div id="root"></div>',
`<div id="root">${ReactDOMServer.renderToString(<App />)}</div>`
)
);
});
});
app.use(express.static(path.resolve(__dirname, '..', 'build')))
app.listen(PORT, () => {
console.log(`App launched on ${PORT}`);
});
and it gives me the following error
Error: Invariant failed: Browser history needs a DOM
at invariant (D:\finja\first2\node_modules\tiny-invariant\dist\tiny-invariant.cjs.js:13:11)
at Object.createHistory [as createBrowserHistory] (D:\finja\first2\node_modules\history\cjs\history.js:273:16)
at new BrowserRouter (D:\finja\first2\node_modules\react-router-dom\modules\BrowserRouter.js:11:13)
at processChild (D:\finja\first2\node_modules\react-dom\cjs\react-dom-server.node.development.js:3305:14)
at resolve (D:\finja\first2\node_modules\react-dom\cjs\react-dom-server.node.development.js:3270:5)
at ReactDOMServerRenderer.render (D:\finja\first2\node_modules\react-dom\cjs\react-dom-server.node.development.js:3753:22)
at ReactDOMServerRenderer.read (D:\finja\first2\node_modules\react-dom\cjs\react-dom-server.node.development.js:3690:29)
at Object.renderToString (D:\finja\first2\node_modules\react-dom\cjs\react-dom-server.node.development.js:4298:27)
at D:\finja\first2\server\/server.js:24:42
at FSReqCallback.readFileAfterClose [as oncomplete] (internal/fs/read_file_context.js:63:3)
[nodemon] app crashed - waiting for file changes before starting...
as your error code suggests needs a DOM, you'll need a Browser in order to use react, you cant just send a dynamic component like <App/> back, this approach would only work with something static like a plain html file.
I suggest serving React from another server (like localhost:3000), this tut might help you with that:
https://www.youtube.com/watch?v=19CcxzZHwuI
This detailed post about integrating express with React by freecodecamp might help link

Fetch data from nodejs to a reactjs component

I built my react app.
I have 2 main folders. The first folder contains my react-app and the second contains my nodejs server. In the first file i've created 2 pages and i want to fetch data from nodejs server to one of my page from react app.
//Here is my nodejs file
var express = require('express');
var app = express();
app.post('/', function (req, res) {
res.send('POST request to the homepage');
});
app.listen(4000, function () {
console.log('Example app listening on port 4000!');
});
//Here is my react page where i want to fetch data from nodejs
import React, { useState, useEffect } from 'react';
const Home = () => {
useEffect(async function () {
const url = 'http://localhost:4000/';
const response = await fetch(url);
const data = await response.json();
console.log(data)
});
return(
<div>
<h1>Home Page</h1>
<p>{data}</p>
</div>
)
}
export default Home;
In the future i want to get data also from a nosql database using nodejs, but now I can't pass data from one node js file into reactjs file. How to do this?

Resources