How to deploy node js app with react to heroku - javascript

I trying deploy my MERN app to heroku.
After build success on heroku doesn't see a API routes:
Steps:
On localhost I run concurrently node server and client (create-react-app).
Server on port 5000 and client on port 3000.
After this I fetch from API routes /hotels Array with items and connect it to Redux store and display it.
Properly behavior:
Localhost: works fine
Heroku: broken (didn't connect with API)
This is my server.js file:
const express = require('express');
const path = require('path');
const app = express();
const http = require('http');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cookieSession = require('cookie-session');
const passport = require('passport');
const morgan = require('morgan');
const keys = require('./API/config/keys');
//######### MODELS #########
require('./API/models/Users');
//######### SERVICES #########
require('./API/services/passport');
//######### MONGODB CONNECT #########
mongoose.connect(MONGO_CONNECT);
//######### ROUTES #########
const hotelsRoutes = require('./API/routes/hotels');
const countRoutes = require('./API/routes/count');
const topRoutes = require('./API/routes/top');
// Use routes
app.use('/hotels', hotelsRoutes);
app.use('/count', countRoutes);
app.use('/top', topRoutes);
app.use(morgan('dev'));
app.use('/uploads', express.static('uploads'));
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use(
cookieSession({
maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days
keys: [keys.cookieKey]
})
);
app.use(passport.initialize());
app.use(passport.session());
require('./API/routes/authRoutes')(app);
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
const port = process.env.PORT || 5000;
const server = http.createServer(app);
server.listen(port);
Package.json (server):
{
"name": "root-react-hotel-app",
"version": "0.1.0",
"main": "server.js",
"scripts": {
"client": "cd client && yarn start",
"start": "node server.js",
"start-api": "nodemon server.js",
"dev": "concurrently \"yarn start-api\" \"yarn client\"",
"build": "cd client && npm install && yarn build"
},
"devDependencies": {
//
},
"dependencies": {
//
}
}
Package.json (client):
{
"name": "client-react-hotel-app",
"version": "0.1.0",
"private": true,
"proxy": {
"/auth/google": {
"target": "http://localhost:5000"
},
"/api/*": {
"target": "http://localhost:5000"
},
"/*": {
"target": "http://localhost:5000"
}
},
"dependencies": {
// Here are dependencies
},
"scripts": {
"build-css": "node-sass-chokidar src/ -o src/",
"watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
"start-js": "react-scripts start",
"start": "npm-run-all -p watch-css start-js",
"build-js": "react-scripts build",
"build": "npm-run-all build-css build-js",
"eject": "react-scripts eject",
"compile:sass": "node-sass src/css/styles.scss src/css/styles.css -w",
"generate:doc": "sassdoc src/css/abstracts/_mixins.scss",
"test": "cross-env NODE_ENV=test jest --config=jest.config.json",
"test-coverage": "cross-env NODE_ENV=test jest --coverage --config=jest.config.json",
"test-ci": "cross-env NODE_ENV=test jest --config=jest.config.json --coverage && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js"
},
"devDependencies": {
// Here are devDependencies
}
}
Also trying with static.json file and Procfile:
{
"root": "client/build/",
"setupFiles": [
"<rootDir>/client/src/setupTests.js"
]
}
Anyone can help?

Since your express server is serving both your react bundle and your api routes, in:
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
You need to protect your api routes in the 'app.get' when deploying to heroku (production mode). You can use a simple regex in order to serve all routes to your react bundle except '/api' (or whatever your api endpoint looks like, /API in your case above). It works running locally because you are running your api and react app on separate ports, not the same server.
Usually something like:
if (process.env.NODE_ENV === 'production') {
app.get(/^\/(?!api).*/, (req, res) => { // don't serve react app to api routes
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
};

Related

With Vue app, when serving client from within the server directory and hosting my app, I'm unable to fetch data getting JS enabled error

EDIT: To be clear, this only happening when i'm trying to host the app. Works PERFECT during local environment testing..
When trying to fetch data from my backend getting an error in Chrome saying that JS is not enabled. (IT IS) so that is not the issue..
Thinking there may be an issue with my package.json maybe if the commands are incorrect for use on the host machine? Have tried Render & Heroku same issues.
I had tried to run the commands within my local environment and the app works flawlessly fetching data as intended. Only when hosting the app do I not get any data back from the server when making API call from the front end, instead get JS not enabled error in the Network tab and no errors on Front End that I can see..
Hosted app to see network error: https://elf-invasion.herokuapp.com/
File Structure:
/root
 |- config.js
 |- server.js
 |- package.json + package-lock.json
 |- client/
  |- vue.config.json
  |- ... (rest of dist, src, node_modules, public etc.)
 |- models/
  |- Elf.js + HighScore.js
 |- routes/
  |- api/
   |- elf.js + highScore.js
config.js
module.exports = {
hostUrl: process.env.HOST_URL,
mongoURI: process.env.MONGO_URI,
PORT: process.env.PORT || 3000,
};
server.js
const express = require("express");
const app = express();
const port = 3000;
const mongoose = require("mongoose");
const { PORT, mongoURI } = require("./config.js");
// routes
const Player = require("./routes/api/player");
const Elf = require("./routes/api/elf");
const HighScore = require("./routes/api/highScore");
// cors is a middleware that allows us to make requests from our frontend to our backend
const cors = require("cors");
// morgan is a middleware that logs all requests to the console
const morgan = require("morgan");
// body-parser is a middleware that allows us to access the body of a request
const bodyParser = require("body-parser");
const path = require("path");
app.use(cors());
// use tiny to log only the request method and the status code
app.use(morgan("tiny"));
app.use(bodyParser.json());
// chek if we are in production
if (process.env.NODE_ENV === "production") {
// check if we are in production mode
app.use(express.static("client/dist"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "dist", "index.html"));
});
}
// test if server is running and connected to mongoDB
app.get("/", (req, res) => {
res.send("Hello World!");
});
// app.get("/", (req, res) => {
// res.send("Hello World!");
// });
// use routes
app.use("/api/", Player);
app.use("/api/", Elf);
app.use("/api/", HighScore);
mongoose
.connect(mongoURI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useUnifiedTopology: true,
})
.then(() => console.log("MongoDB connected..."))
.then(() => {
// log uri to console
console.log(`MongoDB connected to ${mongoURI}`);
})
.catch((err) => console.log(err));
app.listen(PORT, () => {
console.log(`Example app listening at ${PORT}`);
});
package.json
{
"name": "week1",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"server": "nodemon server.js --ignore 'client/'",
"client": "npm run serve --prefix client",
"dev": "concurrently \"npm run server\" \"npm run client\"",
"start": "node server.js",
"build": "npm install --prefix client && npm run build --prefix client"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.20.1",
"bootstrap": "^5.2.3",
"cors": "^2.8.5",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"mongoose": "^6.7.5",
"morgan": "^1.10.0",
"portal-vue": "^2.1.7"
},
"devDependencies": {
"concurrently": "^7.6.0",
"nodemon": "^2.0.20"
}
}

my react app works locally but fails to deploy on heroku

works locally when i npm run start but fails on heroku. the only error i get on the logs is " This app may not specify any way to start a node process". ive tried changed the scripts. and ive tried to use the create react app documentation. ive also implemented the "https://github.com/mars/create-react-app-buildpack.git" build pack to the project
my file structer
//client
|
+-node modules
+ public
+-src
+-package-lock
+-package.json
//node_modules
//server
|
+-models
+-server.js
+-routes
+-Controllers
+-middlewares
+-config
+-env
+-gitignore
+-nodemon.json
+-package-lock.json
+-package.json
My main package.json scripts
"scripts": {
"start": "npm run start:dev",
"start:prod": "node server/server.js",
"start:dev": "concurrently \"nodemon --ignore 'client/*'\" \"npm run client\"",
"client": "cd client && npm run start",
"seed": "node server/scripts/seedDB.js",
"install": "cd client && npm install",
"build": "cd client && npm run build",
"heroku-postbuild": "npm run build"
},
my server.js
require('dotenv').config();
const express = require('express');
const morgan = require('morgan');
const session = require('express-session');
const MongoStore = require('connect-mongo')(session);
const dbConnection = require('./config/connection');
const passport = require('./config/passport');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 8090;
// Middlewares
app.use(morgan('dev'));
app.use(express.urlencoded({extended: false}));
app.use(express.json());
app.use('/', express.static(path.join(__dirname, '../client/build')));
// Passport
app.use(passport.initialize());
app.use(passport.session()); // will call the deserializeUser
app.use(session({
secret: 'my_secret', // process.env.AUTH_SECRET,
store: new MongoStore({ mongooseConnection: dbConnection }),
resave: false,
saveUninitialized: false
}));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '../client/build/'))
});
// Add Auth and API routes
app.use('/auth', require('./routes/authRoutes'));
app.use('/api', require('./routes/apiRoutes'));
// If no routes are hit, send the React app
app.use(function(req, res) {
res.sendFile(path.join(__dirname, '../../client/build/index.html'));
});
// Error handler
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500);
})
app.listen(PORT, () => {
console.log(`App listening on PORT: ${PORT}`);
});
It seems like you haven't added a Procfile. If not in the root directory of your node API add a file called Procfile with no extensions i.e .js. Once you have made the file add the following line :
web: npm run start.

Having trouble deploying an app to heroku through git

I am trying to create a simple node.js app on heroku. Here is my app.js:
console.log("Starting App")
const express = require('express')
const app = express()
const port = 3000
app.listen(process.env.PORT || port, () => console.log(`App listening on port ${port}!`))
app.get('/', (req,res) => {
res.sendFile(__dirname+'/public/index.html')
})
app.get('/style', (req,res) => {
res.sendFile(__dirname+'/public/main.css')
})
app.get('/script', (req,res) => {
res.sendFile(__dirname+'/public/script.js')
})
app.get('/changelog', (req,res) => {
res.sendFile(__dirname+'/public/changelog.txt')
})
here is my package.json file:
{
"name": "",
"version": "0.0.0",
"description": "",
"main": "/App.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.4"
}
}
and here is my Procfile:
web: node app.js
I am deploying this to heroku via github, and whenever I run the program it gives me an error, saying Cannot find module '/app/app.js.' I have made everything lowercase and removed forward slashes. I still get this error: Error: Cannot find module '/app/app.js' Can anyone help?
In package.json, change "main": "/App.js" to "main": "app.js"
make sure package.json is at the same level as app.js
If app.js is in another folder, make sure to provide the full path from directory holding the package.json file.

reactjs expressjs how to setup proxy? proxy doesn't work with localhost:3000, but works with localhost:3000/test

Trying to work with reactjs (create-react-app) and now including expressjs. What I've done is
move my folder/* to folder/client/* (deleting node_modules)
cd folder/client/ and npm install to recreate the node_modules
*it works as before, the app renders well
cd folder and npm init
npm install express --save
write the folder/server.js
add the proxy settings in /folder/client/package.json
npm run start in /folder and in /folder/client
Then, I go to localhost:3000 and I get the reactjs app, without express anywhere. Then I go to localhost:8080 and I get the express result, which is indeed the same page as before but without being executed by react (nothing wrong here, I assume)
And then I go to localhost:3000/test and it gets proxied to express, where I see in the terminal the console.log of server.js
So I cannot proxy localhost:3000, but I can localhost:3000/whatever. What is wrong?
server.js
const express = require('express');
const path = require('path'); // haven't installed, should I?
const app = express();
app.use(express.static(path.join(__dirname, 'build'))); // of no use here
app.get('/ping', function (req, res) { // this one works
return res.send('pong');
});
// app.get('', function (req, res) { // doesn't work
// app.get('*', function (req, res) { // doesn't work
// app.get('.', function (req, res) { // doesn't work
// app.get('.*', function (req, res) { // doesn't work
// app.get('./', function (req, res) { // doesn't work
app.get('./*', function (req, res) { // doesn't work
console.log('hey') // never seen
res.sendFile(path.join(__dirname, 'client/src', 'index.html'));
});
app.get('/test', function (req, res) { // this one works
console.log('hey2') // I do see this when calling localhost:3000/test
res.sendFile(path.join(__dirname, 'client/src', 'index.html'));
});
app.listen(process.env.PORT || 8080);
package.json (/)
{
"name": "ouyea",
"version": "0.1.1",
"description": "This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"repository": {
"type": "git",
"url": "git+https://xxxx"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://xxxx"
},
"homepage": "https://xxxx",
"dependencies": {
"express": "^4.16.4"
}
}
package.json (/client)
{
"name": "client",
"version": "0.1.1",
"private": true,
"dependencies": {
"axios": "^0.18.0",
"googleapis": "^33.0.0",
"papaparse": "4.6.0",
"react": "^16.4.2",
"react-dom": "^16.4.2",
"react-scripts": "1.1.4",
"semantic-ui-css": "^2.4.0",
"semantic-ui-react": "^0.82.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"proxy": {
"": { // I know comments don't work, but I put them here for clarity, none of them worked
// "*": {
// ".": {
// "/": {
"target": "http://localhost:8080"
},
"/test": {
"target": "http://localhost:8080"
}
}
}
The purpose of the express server is to simply a) render the base HTML page from your dist folder, and b) supply data from endpoints that you set up as routes in Express which can be accessed by your React client application. There are apps (universal) that can render React pages from Express but that's not what you're doing here with create-react-app.

postman returning 404 for the node.js endpoint

I am trying to create a simple rest endpoint using node.js.
I am following the tutorial https://medium.freecodecamp.com/building-a-simple-node-js-api-in-under-30-minutes-a07ea9e390d2
the folder structure is notable/app/routes/ and the routes folder contains the index.js and note_routes.js files
I am able to run the command npm run dev, and the output shown is:
> notable#1.0.0 dev /Users/tejanandamuri/Desktop/notable
> nodemon server.js
[nodemon] 1.11.0
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node server.js`
We are live on 8000
after this. in the postman, when I try to call the http://localhost:8000/notes, it is returning 404 error with the response body Cannot POST /notes
Here are my files:
server.js:
const express = require('express');
const MongoClient = require('mongodb').MongoClient;
const bodyParser = require('body-parser');
const app = express();
const port = 8000;
require('./app/routes')(app, {});
app.listen(port, () => {
console.log('We are live on ' + port);
});
index.js:
// routes/index.js
const noteRoutes = require('./note_routes');
module.exports = function(app, db) {
noteRoutes(app, db);
// Other route groups could go here, in the future
};
note_routes.js
module.exports = function(app, db) {
app.post('/notes', (req, res) => {
// You'll create your note here.
res.send('Hello')
});
};
package.json:
{
"name": "notable",
"version": "1.0.0",
"description": "my first rest api",
"main": "server.js",
"dependencies": {
"body-parser": "^1.17.2",
"express": "^4.15.3",
"mongodb": "^2.2.28"
},
"devDependencies": {
"nodemon": "^1.11.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js",
"dev": "nodemon server.js"
},
"author": "venkata",
"license": "ISC"
}
Change line 6 in server.js to require('./routes/note_routes')(app, {});
This assumes your file tree looks something like this:
.
+--/node_modules // this contains a ton of sub-folders
+--/routes
+ +--index.js
+ +--note_routes.js
+--package.json
+--server.js

Categories