Error while deploying react js and node app to aws - node.js

I want to deploy my app to aws, i search and i found alot of tutorials i try each one and i get this error on the browser:
Cannot GET /
I figure maybe that my problem is from my nodeJS server code.
This is my server.js code hope you guys can help me thanks.
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const passport = require('passport');
const path = require('path');
const cors = require('cors');
//Api routes
const users = require('./routes/api/usuario');
const alumno = require('./routes/api/alumno');
const personal = require('./routes/api/personal');
const zonas = require('./routes/api/zonas');
const sepomex = require('./routes/api/sepomex');
const app = express();
app.use(cors());
//Body parser middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
//Db config
const db = process.env.NODE_ENV === "production" ? require('./config/keys').mongoURIProd : require('./config/keys').mongoURIDev;
//connect to mongo DB
mongoose
.connect(db, { useNewUrlParser: true })
.then(() => console.log('MongoDB Connected'))
.catch(err => console.log(err));
//passport middleware
app.use(passport.initialize());
//passport config
require('./config/passport')(passport);
//Use routes
app.use('/api/usuario', users);
app.use('/api/alumno', alumno);
app.use('/api/personal', personal);
app.use('/api/zonas', zonas);
app.use('/api/sepomex', sepomex);
//serve static assets to production
if (process.env.NODE_ENV === "production") {
//static folder
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;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
I have deployed my app on heroku and works fine.

If you are deploying to EC2 instance then you need to specify IP address in app.listen to be 0.0.0.0, by default it is set to localhost which is not what you want if you want the app to be reachable from outside.
You should change your code to
app.listen(port, '0.0.0.0', () => {
console.log(`Server running on port ${port}`);
});

Related

Mongo DB not connecting to NodeJS after Heroku deployment

I've a MERN app (Mongo Express React Node) that works locally, and connects to my MongoDB database, getting data.
The React front-end works after I deploy it to Heroku, but Nodejs won't connect to MongoDB on Heroku.
The environment variables like MONGO_URI stored as Heroku config variables, works perfectly fine, yet it just won't connect to my MongoDB.
The Heroku logs shows the error message: DISCONNECTED FROM MONGO DB from my server.js file.
How can I solve this?
server.js file
const express = require("express");
const dotenv = require("dotenv");
const cookieParser = require("cookie-parser");
const mongoose = require("mongoose");
const cors = require("cors");
const path = require("path");
dotenv.config();
const authRouter = require("./routes/auth");
const blogRouter = require("./routes/blog");
const userRouter = require("./routes/user");
const app = express();
app.use(express.json());
app.use(cookieParser());
app.use(cors());
app.use("/api/auth", authRouter);
app.use("/api/user", userRouter);
app.use("/api/blog", blogRouter);
if(process.env.NODE_ENV === "production"){
app.use(express.static("client/build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
});
}
const connect = () => {
mongoose
.connect(process.env.MONGO_URL,
{useNewUrlParser: true,
useUnifiedTopology: true,
useNewUrlParser: true})
.then(() => {
console.log("CONNECTED TO THE MONGO DB");
})
.catch((err) => {
console.log(err);
mongoose.disconnect(() => {
console.log("DISCONNECTED FROM MONGO DB");
});
})
};
app.listen(process.env.PORT || 8000, () => {
connect();
console.log("MONGO_URL", process.env.MONGO_URL);
console.log("PASSCODE", process.env.PASSCODE);
console.log(`LISTENING ON PORT ${process.env.PORT}`);
})
Your environment variable to connect to MongoDB database has to be MONGO_URI, not MONGO_URL.
Otherwise it won't work.

Why is my heroku app loading resources too long even after using gzip compression?

I have a MEAN stack app hosted in Heroku. In my Express server, I use gzip (via compression middleware).
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const cors = require('cors');
const passport = require('passport');
const adminpassport = require('passport');
const mongoose = require('mongoose');
const config = require('./config/database');
// Connect to DB
mongoose.connect(config.database);
mongoose.connection.on('connected',()=>{
console.log('Connected to database '+config.database);
});
mongoose.connection.on('error',(err)=>{
console.log('DB Error '+err);
});
const compression = require('compression');
const app = express();
// Static Folder
app.use(express.static(path.join(__dirname, 'public')));
app.use(compression());
// Body Parser Middleware
app.use(bodyParser.json());
...
app.use(function(req, res) {
res.sendFile(path.join(__dirname, '/public', 'index.html'));
});
// Index Route
app.get('/', (req, res)=>{
res.send('Invalid enpoint');
});
app.listen(port, ()=>{
console.log("Server started on port "+port);
});
The problem is that the Angular main.js file (that is orginally 3.2mb, compressed to 575kb) is still seemingly being download as if it's still the uncompressed size. Here's an image of the load times:
I know my internet connection is fine (around 20mbps). Is there anything I'm missing? Is there something wrong in my implementation of gzip? Or even my Heroku dyno? This app is currently on the hobby dyno. I did change it to the professional one but didnt notice any difference.
I'm not sure what is your environment, but you can try this, is completely functional for me.
// Get dependencies
const express = require('express');
const path = require('path');
const http = require('http');
const bodyParser = require('body-parser');
const compression = require('compression');
const runApp = async() => {
const app = express();
app.use(compression({
filter: function (req, res) {
return (/json|text|javascript|css|font|svg/).test(res.getHeader('Content-Type'));
},
level: 9
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.get('*', (req, res) => {
console.log('Front end called');
res.sendFile(path.join(__dirname, 'public/index.html'));
});
/**
* Get port from environment and store in Express.
*/
const port = process.env.PORT || '8081';
app.set('port', port);
/**
* Create HTTP server.
*/
const server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port, () => console.log(`API running on localhost:${port}`));
};
runApp();

Heroku only displaying backend of MERN app. How can I fix this?

I've finished working on my first MERN app. It works locally and it was 'successfully built' on Heroku but all that is displayed is the backend-data retrieved for the '/' route from MongoDB.
I've looked at a couple of resources that discuss deploying MERN stack apps to Heroku here:
1. https://www.freecodecamp.org/forum/t/solved-deployment-problem-showing-backend/280178
2. https://www.freecodecamp.org/news/how-to-deploy-a-react-app-with-an-express-server-on-heroku-32244fe5a250/
I've tried integrating these posts with my code but to no avail. I'm not sure how to use the path middleware in tandem with my three existing routes ('/', '/authors', and '/books') and ultimately how that results in the build for index.html. I'm not sure if it makes any difference but I'm using parceljs to build the frontend.
Edit: Added screenshot of folder layout to show where dist folder is located within the project
Below is my server.js file:
if (process.env.NODE_ENV !== "production") {
require("dotenv").config();
}
const express = require("express");
const app = express();
const cors = require("cors");
const path = require("path");
// Middleware
app.use(express.urlencoded({ limit: "10mb", extended: true }));
app.use(express.json({ limit: "10mb" }));
app.use(cors());
// Connect to Mongoose
const mongoose = require("mongoose");
mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
});
const db = mongoose.connection;
db.on("error", err => console.error(err));
db.once("open", () => console.log("Connected to Mongoose"));
// Define routes
const indexRouter = require("./routes/index");
const authorRouter = require("./routes/authors");
const bookRouter = require("./routes/books");
// Utilize routes
app.use("/", indexRouter);
app.use("/authors", authorRouter);
app.use("/books", bookRouter);
app.listen(process.env.PORT || 3000);
Can you try this code, if your app is in production express will serve static assets and it will redirect user to index.html if user comes to routes other than api routes(by providing app.get('*', ...))
server.js
...
app.use("/books", bookRouter);
if(process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, '/client/dist')))
app.get('*', (req,res) => {
res.sendFile(path.join(__dirname, '/client/dist', 'index.html'))
})
}

Node.js - Specifying URL in Heroku yields internal server error, running locally works fine

I'm having some issues with my application after it's been deployed to heroku. When I specify the URL, or refresh the browser on a page OTHER than the homepage I am getting an "Internal Server error" and the page doesn't load. However when I click the links which naviagte me to those pages from the home page it works fine. When I run the server locally it does not give me this error.
Based on my research this is probably an error on the server side. Here is my code:
Node.js backend
const express = require("express");
const bodyParser = require("body-parser");
const passport = require("passport");
const users = require("./routes/api/users");
const actions = require("./routes/api/dbActions");
const app = express();
// Bodyparser middleware
app.use(
bodyParser.urlencoded({
extended: false
})
);
app.use(bodyParser.json());
// Passport middleware
app.use(passport.initialize());
// Passport config
require("./config/passport")(passport);
// Routes
app.use("/api/users", users);
app.use("/api/dbActions", actions);
// Serve 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'));
});
}
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server running on port ${port} !`));
Any idea why this might be happening?
Thanks!!
In my server.js file I included the following:
const path = require('path');
Which seems to have worked for me.

Vue + Express app on heroku not using the SPA in server/public folder

My app is running on heroku and the routes send me JSON files, but what I need is to use the SPA that is in my ./server/public folder as index.html.
When I open the heroku app it send me the JSON file that is sent from the "/" route, but I need it to use the Vue SPA, because of what I did in my front-end client if for some reason you go to a route that doesn't exists it does redirect me to my "/forum" route with the front-end client, but any other route that exists will not work, it will keep sending the JSON of that route.
app/server.js
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const expressValidator = require("express-validator");
const flash = require('connect-flash');
const mongoose = require('mongoose');
const cors = require("cors");
const config = require("./config/database");
if(process.env.NODE_ENV !== "production") require('dotenv').config();
mongoose.connect(config.database, { useNewUrlParser: true, useFindAndModify: false });
let db = mongoose.connection;
db.once("open", () => {
console.log("Connected to MongoDB Atlas");
});
db.on("error", (err) => {
console.log(err);
});
const app = express();
//Body-parser
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
app.use(expressValidator());
app.use(flash());
app.use(cors());
require("./passport")
//Routes
const home = require("./routes/home.js");
const forum = require('./routes/forum.js');
const ranking = require('./routes/ranking.js');
const profile = require('./routes/profile.js');
// Routing
app.use("/", home);
app.use("/forum", forum);
app.use("/profile", profile);
app.use("/ranking", ranking);
// Handle production build
if (process.env.NODE_ENV === "production") {
app.use(express.static(__dirname + '/public/'));
app.get(/.*/, (req, res) => { res.sendFile(__dirname + '/public/index.html') });
}
// PORT
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server listening on port ${port}`)
});
If you are splitting the frontend and the backend with Vue and Express, you should probably build and host the Vue part statically and then have your Express running on Heroku.
Here is a guide on how to deploy your express app, and then you build and deploy your static Vue page, here are the docs for deploying Vue.

Resources