I am still learning Node.js. I created a server using express documentation and it worked before.
But now for a project I have imported some npm packages. like dotenv, http-errors, ejs and others. I created (.env) file and there decleared PORT=5000, import it in my (main.js) file and called app.listen function. So that, it can show my ejs template in the browser but when i hit http://localhost:5000 it just keeps loading but nothing appears. it's not giving any errors in the terminal either, it just keeps loading unless i press ctrl+c in my terminal.
main.js
const express = require("express");
const dotenv = require("dotenv");
const mongoose = require("mongoose");
const path = require("path");
const cookieParser = require("cookie-parser");
const { notFoundHandler, errorHandler } = require("./middlewares/common/errorHandler");
const app = express();
dotenv.config();
//database connection
mongoose.set("strictQuery", true);
mongoose.connect(process.env.MONGO_CONNECTION_STRING, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => console.log("Database Conntcted!"))
.catch(err => console.log(err));
app.use(express.json);
app.use(express.urlencoded({ extended: true }));
app.set("view engine", "ejs");
app.set('views', 'views');
app.use(express.static(path.join(__dirname, "public")));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(notFoundHandler);
//common error handler
app.use(errorHandler);
app.listen(process.env.PORT, () => {
console.log(`app is listing at port ${process.env.PORT}`);
});
my errorhandler.js
const createError = require("http-errors");
function notFoundHandler(req, res, next) {
next(createError(404, "CONTENT WAS NOT FOUND!"));
}
function errorHandler(err, req, res, next) {
res.render("error", {
title: "Error Page",
});
}
module.exports = {
notFoundHandler: notFoundHandler,
errorHandler,
};
error.ejs
my ejs file route ("./views/error.ejs")
<title><%= title %></title>
<body>
Alart!
</body>
.env file
PORT=5000
problem fixed! The problem was in my main file. There was a parentheses() missing.
it would be app.use(express.json());
Related
I managed my routing via a few routers, but something went wrong,
when i try to call a functton i get the error:
Error: No default engine was specified and no extension was provided.
I can't understand what could be my problem..
I would be greatfull if soembody can help
my code:
// index.js
const express = require("express");
const router = express.Router();
const userRouter = require("./userRouter");
const qeustionRouter = require("./questionRouter");
const questionToTestRouter = require("./questionToTestRouter");
const testRouter = require("./testRouter");
const subjectRouter = require("./subjectRouter");
/* GET home page. */
router.get("/", function (req, res, next) {
res.render("index", { title: "Express is run" });
});
router.get("/user",userRouter);
router.get("/qeustion",qeustionRouter);
router.get("/questionToTest",questionToTestRouter);
router.get("/test",testRouter);
router.get("/subject",subjectRouter);
module.exports = router;
another router for example:
// userRouter.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
router.post('/signUp', userController.signUp)
router.get('/login', userController.login)
router.delete('/deleteStudent', userController.deleteStudent)
router.delete('/deleteTeacher', userController.deleteTeacher)
router.get('/getAllUsers', userController.getAllUsers)
router.get('/getStudentsByTeacherId/:teacherId', userController.getStudentsByTeacherId)
router.get('/getTeachersByStudentId/:userId', userController.getTeachersByStudentId)
router.post('/updateUser', userController.updateUser)
module.exports = router
// app.js
var express = require("express");
var cors = require("cors")
const mongoose = require('mongoose');
//var path = require("path");
// var favicon = require("serve-favicon");
// var logger = require("morgan");
// var cookieParser = require("cookie-parser");
var bodyParser = require("body-parser");
var routes = require("./routes/index");
var app = express();
// view engine setup
// app.set("views", path.join(__dirname, "views"));
// app.set("view engine", "jade");
// // uncomment after placing your favicon in /public
// // app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
// app.use(logger("dev"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// app.use(cookieParser());
// app.use(express.static(path.join(__dirname, "public")));
app.use(cors());
app.use("/", routes);
//--------------------------------------
//listen to localhost
app.listen(4000, (req, res) => {
console.log("listening on port 4000");
})
//--------------------------------------
//connect to mongo//
const connectionParams = {
useNewUrlParser: true,
// useCreateIndex: true,
useUnifiedTopology: true
}
mongoose.connect(process.env.DB_CONNECT, connectionParams)
.then(() =>
console.log("connected to mongo"))
.catch((error) =>
console.log("error: " + error))
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error("Not Found");
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get("env") === "development") {
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render("error", {
message: err.message,
error: err,
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render("error", {
message: err.message,
error: {},
});
});
module.exports = app;
I think you need a view engine. I see you are defining "jade" as your view engine but it is commented out and it is not in the index.js
please make sure you installed jade package. You can check this by looking at your package.json file.
npm install jade --save
You need to define jade as your view engine (in the index.js) and your jade files must be stored inside the views folder. Inside index.js file, you can change all router keywords to app
const express = require ("express");
const app = express ();
app.set("view engine","jade")
And delete this: const router = express.Router();
And this folder must be placed at the root of your project (in other words, your index.js file and "views" folder should be at the same level). If you do it in this way, you wont need to define a path route.
I kindly advise you to use "ejs" as your view engine. It is more common than "jade". You can create ejs files easily, just like an html page.
And first start with a single route to test if your express framework is working. You can then gradually add up other routes. And please let me know if this answer helps, otherwise I will delete.
I am using ejs with express, and there is an error in my ejs code
SyntaxError: Unexpected token '.' in
.../views/pages/index.ejs while compiling ejs
If the above error is not helpful, you may want to try EJS-Lint:
https://github.com/RyanZim/EJS-Lint
And yep, that was a pretty unhelpful error, so I added ejs-lint to my server.js file:
const express = require('express');
const app = express();
const dotenv = require('dotenv');
const ejs = require('ejs');
const ejsLint = require('ejs-lint');
// setup configs
dotenv.config();
const config = process.env;
app.set('view engine', 'ejs');
// routes
app.get('/', function (req, res) {
try {
console.log('attempting to render');
res.render('pages/index');
} catch (e) {
console.log('Should get here'); // this line is never hit
}
});
// gotta get yourself connected
app.listen(config.port, () =>
console.log(`Example app listening at http://localhost:${config.port}`)
);
But the try/catch isn't working and it would be great if this was somehow integrated with express render.
My app is currently deployed online through Heroku but it is displaying the backend server rather than my Vue app.
Note: I have an if statement in app.js that serves the files only in production. I removed the if statement to see if the app would appear without environmental conditions. It did not work.
Also I have a minified Vue js folder called dist in my express directory.
Updated
The heroku method I am using is the Heroku Git Cli
$ cd my-project/
$ git init
$ heroku git:remote -a testingew
$ git add .
$ git commit -am "make it better"
$ git push heroku master
This is what I see, which is the backend response to the "/" route. The code is in app.js
app.js
The full code
const serveStatic = require("serve-static");
const path = require("path");
const express = require("express");
const app = express();
const userRoutes = require("./routes/user");
const budgetRoutes = require("./routes/budget");
const profileRoutes = require("./routes/profile");
require("dotenv/config");
const port = process.env.PORT || 3000;
const cors = require("cors");
const morgan = require("morgan");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const cookieParser = require("cookie-parser");
const sessions = require("express-session");
const MongoStore = require("connect-mongo")(sessions);
const passport = require("passport");
const passportSetup = require("./config/passport.js");
//Log when making request
app.use(morgan("combined"));
//Parse body for post request
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var corsOption = {
origin: true,
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
credentials: true
};
app.use(cors(corsOption));
app.use(
sessions({
secret: process.env.SESSION_COOKIEKEY,
saveUninitialized: false,
resave: false,
store: new MongoStore({
mongooseConnection: mongoose.connection
}),
cookie: {
// secure: true,
maxAge: 86400000
}
})
);
//Initialize passport
app.use(passport.initialize());
app.use(passport.session());
//Automatic route placer
app.use("/auth", userRoutes);
app.use("/api/budget", budgetRoutes);
app.use("/api/profile", profileRoutes);
app.get("/", (req, res) => {
res.send("App is on");
});
//404 error and pas to error handler
app.use((req, res, next) => {
const error = new Error("An error has occured");
error.status = 404;
next(error);
});
//Error handler
app.use((error, req, res, next) => {
//Respond Client
res.status(error.status || 500);
res.json({
error: {
message: error.message
}
});
console.log(error.message);
});
//Mongo connection
mongoose.connect(
process.env.DB_CONNECTION,
{
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false
},
() => console.log("connected to mongo atlas")
);
//Handle production
app.use(express.static(path.join(__dirname, "dist")));
// Redirect all requests to `index.html`
app.get("/*", (req, res) => {
res.sendFile(path.join(__dirname, "dist", "index.html"));
});
//Start app
app.listen(port, () => {
console.log(`Server is on port ${port}`);
});
Vue Router
Note: I am also using route navigation guards within components if that means anything
import Vue from "vue";
import VueRouter from "vue-router";
//import axios from "axios";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "login",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/Login.vue")
},
{
path: "/userprofile",
name: "userProfile",
component: () => import("../views/userProfile.vue"),
meta: {
requireAuth: true
}
},
{
path: "/budgetform",
name: "form",
component: () => import("../views/budgetForm.vue"),
meta: {
requireAuth: true
}
},
{
path: "/mybudget",
name: "myBudget",
component: () => import("../views/myBudget.vue"),
meta: {
requireAuth: true
}
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
File directory of Express
Hopefully this helps
EDIT
Based on your edit showing your Express app, you need to remove everything between
app.use("/api/profile", profileRoutes);
and Mongo. The app can't run if you do other things on the route instead. The "App is on" and error checking stuff is blocking your app. I don't think you mean to run the error on every route, but that's what's happening. I would suggest browsing some Express tutorials and starting from scratch to try to understand why that can't work.
ORIGINAL
Try to replace everything above app.listen with:
// Serve static assets
app.use(express.static(path.join(__dirname, 'dist')));
// Redirect all requests to `index.html`
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist', 'index.html'));
})
Your wildcard match was wrong, and would only match file paths that begin with a dot, path.join wasn't used correctly, there should be no slash literals. I changed some other syntax too. If this doesn't completely fix the issue, there are many possibilities for error that are beyond the scope of this question:
1) directory structure
2) .gitignore
3) vue-router
4) package.json start script
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'))
})
}
Though my rendering path is correct when I hit http://localhost:4444/admin/posts/create it shows some error like
Error: Failed to lookup view "/admin/posts/create" in views directory "D:\node practise\CMS\views"
app.js file is like
const express = require('express');
const app = express();
const path = require('path');
const exphbs = require('express-handlebars');
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/cms', { useNewUrlParser: true })
.then(db => {
console.log('MONGO CONNECTED!');
})
.catch(error => {
console.log('MONGO NOT CONNECTED!');
})
//making app to use static file
app.use(express.static(path.join(__dirname, 'public')));
//define template engine
app.set('view engine', 'handlebars');
//set default engine
app.engine('handlebars', exphbs({defaultLayout: 'home'}));
//load routes
const home = require("./routes/home/index");
const admin = require("./routes/admin/index");
const posts = require("./routes/admin/posts");
//use routes
app.use(home);
app.use("/admin", admin);
app.use("/admin/posts", posts);
//setting up server
app.listen(4444, () => {
console.log('Listening....');
});
I have posts.js that handles this route like
const express = require("express");
const router = express.Router();
router.all('/*', (req, res, next) => {
req.app.locals.layout = 'admin';
next();
})
router.get('/', (req, res) => {
res.send('It works!');
})
router.get('/create', (req, res) => {
res.render('/admin/posts/create');
})
module.exports = router;
And I have my views folder structure as
What may be the cause of error? When I try to send response it works but when I try to render the view it shows error.
Can you try res.render('admin/posts/create');?
If the view folders is set properly like this: app.set('views', './views'), you should be able to resolve simple view name like res.render('myview') under ./views folder