MEVN stack unable to deploy - node.js

I have a project where I try to locally and on Heroku run a MEVN application. Both are not working at the moment.
I have my server.js file in the main folder. Then inside the 'client' folder is the Vue 3 project. Inside there I have run npm run build which created a dist folder containing the index.html file.
When I run both locally and on Heroku I can go to '/api/users' and the JSON is shown in the browser. But when I navigate to '/'
I have tried changing the public in the server.js to dist but this did not fix the problem.
I get the following error: Error: ENOENT: no such file or directory, stat /Users/stephen/Documents/stephen/project/client/build/index.html
My server.js file looks like this:
const express = require("express");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
const path = require("path");
const cors = require("cors");
const app = express();
//Bodyparser Middleware
app.use(bodyParser.json());
app.enable("trust proxy");
app.use(cors());
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", '*');
res.header("Access-Control-Allow-Credentials", true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header("Access-Control-Allow-Headers", 'Origin,X-Requested-With,Content-Type,Accept,content-type,application/json');
next();
});
//DB Config
const db = require("./config/keys").mongoURI;
//Connect to Mongo
mongoose
.connect(db, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => console.log("MongoDB Connected"))
.catch((error) => console.log(error));
app.get('/api/users', (req, res) => {
res.json({ user: 'test' })
})
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '/client/build/index.html'));
});
const port = process.env.PORT || 3000;
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"));
});
}
app.listen(port, () => console.log("Server starter on port " + port));

Related

How do I make req.body.password not equal to undefined?

In my html I have,
<input name="password" type="password" required class="form-control" id="exampleInputPassword1">
and in my node I have,
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const urlencodedParser = bodyParser.urlencoded({ extended: false })
app.get('/login.html', (req, res) => {
res.sendFile('./login.html', {root: __dirname});
})
app.post('/login', urlencodedParser, (req,res)=>{
req.body.password
})
but, the req.body.password is undefined or empty. How do I make it actually grab what the user is inputting? It does not work for any of them but, I just used password as an example. All the packages were downloaded correctly.
Thanks.
I used the following code:
const express = require("express");
const bcrypt = require("bcrypt");
const bodyParser = require("body-parser");
const app = express();
const jsonParser = express.json();
const urlencodedParser = bodyParser.urlencoded({ extended: false });
// CHANGE THIS TO DATABASE LATER OF USERS
const users = [];
//listen for requests
app.listen(3000);
app.use(express.static(__dirname + "/public"));
app.get("/index.html", (req, res) => {
res.sendFile("./index.html", { root: __dirname });
});
app.get("/login.html", (req, res) => {
res.sendFile("./login.html", { root: __dirname });
});
app.post("/login", jsonParser, (req, res) => {
console.log("Hello");
console.log(req.body.password);
res.json(req.body.password);
});
app.get("/signup.html", (req, res) => {
res.sendFile("./signup.html", { root: __dirname });
});
app.post("/signup", urlencodedParser, (req, res) => {});
app.use((req, res) => {
res.sendFile("./404.html", { root: __dirname });
});
And when I send a POST request to the /login path using the following payload:
{
"password": "Check for Stack Overflow"
}
I get this on the console:
$ node app
Error: ENOENT: no such file or directory, stat '/root/404.html'
Hello
Check for Stack Overflow
I use the following end point: http://2886795314-3000-ollie08.environments.katacoda.com/
And I used POSTMan and got this right now:
Previous Answer...
You have to use res object to send something. For example, to send a JSON structure, you can do:
res.json(req.body.password)
So your code will be:
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const urlencodedParser = bodyParser.urlencoded({ extended: false });
app.get("/login.html", (req, res) => {
res.sendFile("./login.html", { root: __dirname });
});
app.post("/login", urlencodedParser, (req, res) => {
res.json(req.body.password);
});
Also I could see that you are not using a .listen or export of your modules. You may as well need to listen it to a port to run! So use:
app.listen(3000, () => {
console.log("Server started in port 3000!");
});
At the end. So your complete file looks like:
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const urlencodedParser = bodyParser.urlencoded({ extended: false });
app.get("/login.html", (req, res) => {
res.sendFile("./login.html", { root: __dirname });
});
app.post("/login", urlencodedParser, (req, res) => {
res.json(req.body.password);
});
app.listen(3000, () => {
console.log("Server started in port 3000!");
});
Also, please consider reading Express "Hello World" example. It has the best example in the easiest way possible from the original documentation.
req.body.password is kind of like a variable. It 'returns' it's value, but you're not doing anything with what it returns.
It's not clear what you mean with return. If you want to log something to a console, you can do that:
console.log(req.body.password);

Compiling EJS to Static Files Guide?

I want to port my site to Netlify, which is a static website hosting. However, I have a ExpressJS server that uses EJS to render and route things and trying to put everything together without EJS is becoming a nightmare.
For example, server.js:
require('dotenv').config()
const express = require('express');
const app = express()
const PORT = process.env.PORT || 3000;
const path = require('path');
const panelRouter = require("./routes/panel.js")
app.set('view engine', 'ejs');
app.use("/assets", express.static(path.join(__dirname, 'views/assets')))
app.use("/panel", panelRouter)
function nocache(req, res, next) {
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
res.header('Expires', '-1');
res.header('Pragma', 'no-cache');
next();
}
app.get("/", (req, res) => {
res.render("login");
});
app.get("/robots.txt", nocache, (req, res) => {
res.sendFile(path.join(__dirname + '/robots.txt'));
});
app.listen(port=PORT, () => {
console.log(`Listening on: ${PORT}`)
})
and one of the routers im showing, panelRouter (panel.js)
const express = require('express')
const router = express.Router();
router.get("/", (req, res) => {
res.render("../views/panel/home")
})
router.get("/about", (req, res) => {
res.render("../views/panel/about")
})
router.get("/messages", (req, res) => {
res.render("../views/panel/messages")
})
router.get("/achievements", (req, res) => {
res.render("../views/panel/achievements")
})
router.get("/events", (req, res) => {
res.render("../views/panel/events")
})
router.get("/exec", (req, res) => {
res.render("../views/panel/exec/home_exec")
})
router.get("/erg_home", (req, res) => {
res.render("../views/panel/erg_home")
})
module.exports = router;
Does EJS have a way to compile everything to a folder that I can easily deploy to Netlify or other sites that only host static files?

"You need to enable JavaScript to run this app." error when deploying React/Express app to heroku

I've created a React and node/express based app and trying to deploy it on heroku. The deployment went well and my app is available here: https://sbansal-campaign-manager.herokuapp.com/
However, there is a problem in calling backend apis and loading data even though the requests return 200 response.
When I click Preview tab, however, it says: You need to enable JavaScript to run this app. which is incorrect. JS is enabled. I'm able to access the data on my local machine but not when I deploy the app on heroku. Sharing my server's configuration below:
const express = require("express");
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
// IMPORT MODELS
require('./models/Campaign');
const app = express();
mongoose.Promise = global.Promise;
mongoose.connect(
process.env.MONGODB_URI ||
`mongodb://<user>:<password>#ds145230.mlab.com:45230/sbansal-campaigns-db`
);
app.use(bodyParser.json());
//IMPORT ROUTES
require('./routes/CampaignRoutes')(app);
if (process.env.NODE_ENV === "production") {
app.use(express.static("client/build"));
const path = require("path");
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
});
}
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`app running on port ${PORT}`);
});
I'm new to deploying stuff on heroku. Please help figure out the issue.
Here is the full repo: https://github.com/saranshbansal/sbansal-campaign-manager
The reason why it works on your machine is because you're defining:
if (process.env.NODE_ENV === "production") {
...
}
When you deploy to Heroku, you're deploying the master branch and it will be running in production mode.
This code clearly states that you want to return the html page for all routes:
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
});
The most probable reason is that your index/server.js (Node App File) looks something like this:
// DEV and PRODCTION HANDLER
if (process.env.NODE_ENV === 'DEV') {
const morgan = require('morgan'),
cors = require('cors')
app.use(morgan('dev'),
cors({ origin: `${process.env.HOST_IP}:${process.env.CLIENT_PORT}` })
)
}
if (process.env.NODE_ENV === 'PROD') {
const { resolve } = require('path')
app.use(express.static(resolve(__dirname, '..', 'dist')))
app.use('*', (req, res) => {
res.sendFile(resolve(__dirname, '..', 'dist', 'index.html'))
})
}
// WEB APP ROUTES
app.use('/api/', require('./api/Home.controller'))
app.use('/api/user/', require('./api/User.controller'))
app.use('/api/user/dashboard/', require('./api/Dashboard.controller'))
app.use('/api/chatbot', require('./api/Chatbot.controller'))
app.use('/api/transactions', require('./api/Transactions.controller'))
Which is completely wrong, I was also getting the same error, while doing the research I found this question and after this, I also found the official recommended way to actually use the routes, which clearly suggests that a get route should be used that to server the react files.
Here's the link to doc:
https://create-react-app.dev/docs/deployment/#serving-apps-with-client-side-routing
What happening here is, that express is serving the response from //DEV and PRODUCTION HANDLER. There are 2 problems with the above-given code
//DEV and PRODUCTION Handler should use app.get('') instead of the app.use('') for serving the react HTML build file.
res.sendFile should be below all the other routes.
Here is also a very good blog by https://medium.com/#abdamin for deploying a MERN app: https://itnext.io/deploy-a-mongodb-expressjs-reactjs-nodejs-mern-stack-web-application-on-aws-ec2-2a0d8199a682
So finally, the correct code would look something like this:
// DEV and PRODCTION HANDLER
if (process.env.NODE_ENV === 'DEV') {
const morgan = require('morgan'),
cors = require('cors')
app.use(morgan('dev'),
cors({ origin: `${process.env.HOST_IP}:${process.env.CLIENT_PORT}` })
)
}
// WEB APP ROUTES
app.use('/api/', require('./api/Home.controller'))
app.use('/api/user/', require('./api/User.controller'))
app.use('/api/user/dashboard/', require('./api/Dashboard.controller'))
app.use('/api/chatbot', require('./api/Chatbot.controller'))
app.use('/api/transactions', require('./api/Transactions.controller'))
if (process.env.NODE_ENV === 'PROD') {
const { resolve } = require('path')
app.use(express.static(resolve(__dirname, '..', 'dist')))
app.get('*', (req, res) => {
res.sendFile(resolve(__dirname, '..', 'dist', 'index.html'))
})
}
You need to enable CORS in your server-side app.
Like bellow, or create your customized:
// Setup CORS
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With,
Content-Type, Accept, Authorization');
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
return res.status(200).json({});
}
next();
});

net::ERR_SSL_PROTOCOL_ERROR error after installing express-sslify to MERN project

Dear Awesome MERN developers,
I am facing this error after installing express-sslify
https://localhost:5000/api/users/auth net::ERR_SSL_PROTOCOL_ERROR
Request URL: https://localhost:5000/api/users/auth
Referrer Policy: no-referrer-when-downgrade
here is my server.js
const express = require('express');
const path = require('path');
const compression = require('compression');
const enforce = require('express-sslify');
if (process.env.NODE_ENV !== 'production') require('dotenv').config();
const app = express();
const connectMongoDB = require('./database/mongo-db');
const createSqlDB = require('./database/sql-db/create-db');
connectMongoDB();
createSqlDB();
app.use(compression()); // for gzipping (compression) on heruko
app.use(express.json({ extended: false }));
app.use(enforce.HTTPS({ trustProtoHeader: true })); // inforce HTTPS for security
app.use('/api/users', require('./routers/api/users'));
app.use('/api/contacts', require('./routers/api/contacts'));
app.use('/api/admin', require('./routers/api/admin'));
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'));
});
}
app.get('/service-worker.js', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'build', 'service-worker.js'));
});
app.listen(process.env.PORT, () =>
console.log(`Server started on port ${process.env.PORT}`)
);
any clue why this is happening ???

GET localhost:4200/api 404 (Not Found) after submit data

I download the https://github.com/SinghDigamber/Angular8MeanstackAngularMaterial
and deployed it.
But while I tried to save the data and review the data, i always get the
GET http://localhost:4200/api 404 (Not Found)
add data to db error picture
get data to db error picture
Angular v8.0.0
mongoDB v4.0.10
nodejs v12.2.0
//app.js
let express = require('express'),
path = require('path'),
mongoose = require('mongoose'),
cors = require('cors'),
bodyParser = require('body-parser'),
dataBaseConfig = require('./database/db');
// Connecting mongoDB
mongoose.Promise = global.Promise;
mongoose.connect(dataBaseConfig.db, {
useNewUrlParser: true
}).then(() => {
console.log('Database connected sucessfully ')
},
error => {
console.log('Could not connected to database : ' + error)
}
)
// Set up express js port
const studentRoute = require('./routes/student.route')
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cors());
// Setting up static directory
app.use(express.static(path.join(__dirname, 'dist/angular8-meanstack-angular-material')));
// RESTful API root
app.use('/api', studentRoute)
// PORT
const port = process.env.PORT || 8000;
app.listen(port, () => {
console.log('Connected to port ' + port)
})
// Find 404 and hand over to error handler
app.use((req, res, next) => {
next(createError(404));
});
// Index Route
app.get('/', (req, res) => {
res.send('invaild endpoint');
});
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/angular8-meanstack-angular-material/index.html'));
});
// error handler
app.use(function (err, req, res, next) {
console.error(err.message);
if (!err.statusCode) err.statusCode = 500;
res.status(err.statusCode).send(err.message);
});
I think you forgot to export get and post functions for your API routes.
you can create routes like this in studentRoute File.
var express = require('express');
var router = express.Router();
router.get('/', function (req, res, next) {
return "Hello World";
})
router.post('/', function (req, res, next) {
return "Hello World";
})
module.exports = router;````

Resources