How to deploy reactJS app with json-server - node.js

I have actually deployed my React-app in the following way:-
ran the command: npm run build
Already had db.json file with dummy data.
Context, when I run
json-server --watch db.json -p 3001 -d 2000
the entire react-app works on the localhost
installed json-server using npm
created a server.js file
const jsonServer = require('json-server');
const server = jsonServer.create();
const router = jsonServer.router('db.json');
const middlewares = jsonServer.defaults();
const port = process.env.PORT || 3001;
server.use(middlewares);
server.use(router);
server.listen(port);
created the app on heroku and pushed it to heroku master
The website for some reason only works when I run node server.js on my local-machine and it is making requests to my localport.
if that command isn't running the react-app cannot do the axios request to the DB.
I don't know what went wrong.
I used the following tutorial for this: https://github.com/jesperorb/json-server-heroku
My suspicions are that in my code I have created a basUrl.js file in which
export const baseUrl = 'http://localhost:3001/';
How should I change this to fix my problem?
Thanks for your help.

You should link your react folder built with the server (server.js), to do that add:
const express = require('express');
const path = require('path');
app.use(express.static(path.join(__dirname, 'build')));
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
'build' is your react app's folder created after npm run build into your react app folder.
You have to install path and express modules if not.
And, You should get your json-server database in 'get' function, to use it with a specific url like: /db, just like this:
app.use('/db', middlewares, router);
But you should put /db before /* to not to open database with url /.
So, the result (server.js) will be:
const jsonServer = require('json-server');
const app = jsonServer.create();
const path = require('path');
const express = require('express');
const middlewares = jsonServer.defaults();
const router = jsonServer.router('db.json');
const port = process.env.PORT || 3001;
app.use('/db', middlewares, router);
app.use(express.static(path.join(__dirname, 'build')));
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
server.listen(port);

I have Heroku running on my JSON server too. You need to correct your API path to be your resource name, for example;
If your resource name in your API is 'blogs';
{
"blogs": [
{
"postTitle": "My First Blog",
then your api path will be;
https://xxxx.herokuapp.com/blogs
OR
export const baseUrl = 'https://xxxx.herokuapp.com/blogs';
You shouldn't need to specify a port, but if you do it will be port 4000, which Heroku uses.

Related

Deploying from Local Host to Heroku (Axios Request setup)

I have a react & node.js app that passes data from a form on the client side to server side via an axios POST request and receives a response. I'm trying to set this up on Heroku. On my local system it works perfectly but I can't seem to get it functional on Heroku. It renders the react app but errors on the axios request when the form is submitted which returns error 500 at /api:
const response = await axios.post('/api', poem);
In my local system I was able to use:
const response = await axios.post('https://localhost:3001/api', poem);
... but obviously this won't work in Heroku. Locally the react app would run on https://localhost:3000/ and the server on https://localhost:3001/. All my research says it should work with just the '/api' because it will default to https://my-app.herokuapp.com/api but I get an internal server error at that https://my-app.herokuapp.com/api.
My server.js file looks like this:
// server.js
const PORT = process.env.PORT || 3001;
const express = require("express");
//const cors = require("cors");
const axios = require("axios");
const fetch = require('node-fetch');
const path = require('path');
require('dotenv').config();
const app = express();
app.use(express.static(__dirname + '/'));
if (process.env.NODE_ENV === 'production') {
app.use(express.static('build'));
app.get('*', (req, res) => {
res.sendFile(path.join('build', 'index.html'));
});
}
And here is my file structure: file structure.

How to send css files with express js

I am having a hard time sending css files with express. The way my project is structured is I have a src folder and inside the src folder is the app.js for the express code as well as another folder titled "public". Inside of this public folder I have an experience.html page as well as an experience.css page. I can only get the html to render on the page and cannot get the css styling to show up. Attached is my code for the app.js page.
const express = require('express');
const app = express ();
const port = process.env.Port || 3000;
app.get('/experience', (req, res) => {
res.sendFile(__dirname+'/public/experience.html');
})
app.use(express.static('/public/experience.css'))
app.listen(port);
Just using middleware is enough, you don't need dedicated get routes to the files unless you want to mask some of the filenames.
This should work for your case
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.listen(3000);
You can access them on http://localhost:3000/experience.html, http://localhost:3000/experience.css
You can use the Express static middleware with the path to the public folder.
Once you do that, you can expose a route to the files (or) you can access at localhost:9900
//Import modules
const express = require("express");
const path = require("path");
// Define PORT for HTTP Server
const PORT = 9900;
// Initialize Express
const app = express();
app.use(express.static(path.join(__dirname, "public")));
app.listen(PORT, (err) => {
console.log(`Your dog server is up and running!`);
});

Not able to prepare my MERN app for deployment

I have never deployed a MERN app to production before. This is going to be my first attempt and I am planning to deploy the app to digital ocean.
So, I have prepared my MERN app for deployment by following the instructions in a Udemy course. My app structure is as follows:
The following are the main changes that I have made to my application:
Because there will be no server created by create-react-app in production, I have written the production routing logic inside server/index.js that essentially says that for any routes not managed by app.use("/api/users", userRoutes) & app.use("/api/download", downloadRoutes), the backend server will server the index.html file inside the client/build folder, which I have created by running the command: npm run build.
server/index.js
const express = require("express");
const path = require("path");
const dotenv = require("dotenv");
const colors = require("colors");
const connectDB = require("./config/db");
const {
notFound,
globalErrorHandler,
} = require("./middleware/errorMiddleware");
const userRoutes = require("./routes/userRoutes");
const downloadRoutes = require("./routes/downloadRoutes");
dotenv.config();
connectDB();
const app = express();
app.use(express.json());
app.use("/api/users", userRoutes);
app.use("/api/download", downloadRoutes);
// Routing logic in production
if (process.env.NODE_ENV === "production") {
app.use(express.static(path.join(__dirname, "/client/build")));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
});
}
app.use(notFound);
app.use(globalErrorHandler);
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`.yellow.bold);
});
I have changed the process.env.NODE_ENV to production inside the .env file.
After the above-mentioned changes, when I run "npm start" (starts only the backend server) (not "npm run dev" that concurrently starts both the frontend and backend server) and visit http://localhost:5000, I should see my app. Instead, I see the following error.
What am I doing wrong?
As you can see in the error message, Express is looking for an index.html inside server/client/build which does not exist. Fix the path.
app.use(express.static(path.join(__dirname, '../client/build')))
You need to move your entire client folder inside the server and then add the following in the index.js file of the server:
if (process.env.NODE_ENV === "production") {
app.use(express.static("front/build"));
const path = require('path')
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, 'front', 'build',
'index.html'))
})
}
Make sure to run npm run build first.

Adding angular build "dist" file to node js server.js

I'm trying to deploy my MEAN stack app to heroku. I successfully committed the app but I can't seem to connect my ng build "dist" file to my server.js file.
here is my server.js code where i'm trying to add the file:
var distDir = __dirname + "/dist/";
app.use(express.static(distDir));
Try this:
const path = require('path');
const express = require('express');
const app = express();
// Serve static files
app.use(express.static(__dirname + '/outputPath'));
// Send all requests to index.html
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname + '/outputPath/index.html'));
});
// default Heroku port
app.listen(process.env.PORT || 5000)
Where outputPath is the value of your outputPath in your angular.json file (projects -> architect -> build -> options -> outputPath).

Why can't I view my home page like I can on a local host

I am trying to upload my website on digital ocean using express, node and react. I can view my website on localhost:3000 but when I run nodemon on the publicip:3000 all I see is /root/website/src/index.html displayed on the page. Here is the server.js file
const express = require('express');
const app = express();
//Set port
const PORT = process.env.PORT || 3000;
//Import path
const path = require('path');
//Static files
app.use(express.static('build'));
//Server will use index.html
app.get('/*', (req, res) => {
res.send(path.join(__dirname + '/src/index.html'));
});
app.listen(PORT, () => {
console.log('Listening on port ${PORT}');
});
If you are using res.send() then it will send the path of the file. And path.join should contain the values separated with commas as it takes the values as string array.
Try this
If you want the actual file to send.
res.sendFile(path.join(__dirname ,"src/index.html"));

Resources