0
votes

I'm creating a Next.js web app....

In my app.js file inside the server folder I have the following code:

const express = require("express");
const next = require("next");

const expressValidator = require("express-validator");
const mongoose = require("mongoose");
const passport = require("passport");
const mongoSessionStore = require("connect-mongo");
const session = require("express-session");

/* Loads all variables from .env file to "process.env" */
// npm instsall dotenv
// require("dotenv").config();

require("./models/Listing");
require("./models/User");

const routes = require("./routes");

const dev = process.env.NODE_ENV !== "production";
const port = process.env.PORT || 3000;
const ROOT_URL = dev ? `http://localhost:${port}` : process.env.PRODUCTION_URL;
const app = next({ dev });
const handle = app.getRequestHandler();

const mongooseOptions = {
    useNewUrlParser: true,
    useCreateIndex: true,
    useFindAndModify: false,
    useUnifiedTopology: true
};

mongoose
    .connect(
        process.env.MONGODB_URI,
        mongooseOptions
    )
    .then(() => console.log("DB connected"));

mongoose.connection.on("error", err => {
    console.log(`DB connection error: ${err.message}`);
});

app.prepare().then(() => {
    const server = express();

    if(!dev) {
        /* Helmet helps secure our app by setting various HTTP headers */
        server.use(helmet());
        /* Compression gives us gzip compression */
        server.use(compression());
    }

    /* Body Parser built-in to Express as of version 4.16 */
    server.use(express.json());

    /* Express Validator will validate form data sent to the backend */
    // server.use(expressValidator());

    /* apply routes from the "routes" folder */
    server.use("/", routes);

    /* give all Next.js's requests to Next.js server */
    server.get("/_next/*", (req, res) => {
        handle(req, res);
    });

    server.get("/static/*", (req, res) => {
        handle(req, res);
    });

    const MongoStore = mongoSessionStore(session);
    const sessionConfig = {
        name: "next-connect.sid",
        // secret used for using signed cookies w/ the session
        secret: process.env.SESSION_SECRET,
        store: new MongoStore({
          mongooseConnection: mongoose.connection,
          ttl: 14 * 24 * 60 * 60 // save session for 14 days
        }),
        // forces the session to be saved back to the store
        resave: false,
        // don't save unmodified sessions
        saveUninitialized: false,
        cookie: {
          httpOnly: true,
          maxAge: 1000 * 60 * 60 * 24 * 14 // expires in 14 days
        }
      };

    if (!dev) {
    sessionConfig.cookie.secure = true; // serve secure cookies in production environment
    server.set("trust proxy", 1); // trust first proxy
    }

    /* Apply our session configuration to express-session */
    server.use(session(sessionConfig));

    /* Add passport middleware to set passport up */
    server.use(passport.initialize());
    server.use(passport.session());

    server.use((req, res, next) => {
        /* custom middleware to put our user data (from passport) on the req.user so we can access it as such anywhere in our app */
        res.locals.user = req.user || null;
        next();
    });


    server.get("*", (req, res) => {
        handle(req, res);
    });
        
    server.listen(port, err => {
        if (err) throw err;
        console.log(`Server listening on ${ROOT_URL}`);
    });
    
})

For some reason I am getting the following error when I run the above code:

UnhandledPromiseRejectionWarning: TypeError: Class constructor MongoStore cannot be invoked without 'new'

The line that seems to be producing that error seems to be:

const MongoStore = mongoSessionStore(session);

What is causing this and how can I solve this?

4
have you tried const MongoStore = new mongoSessionStore(session); - Niraeth

4 Answers

0
votes

Looks like 'mongoSessionStore' is a Class Constructor.
A Class has instructions on how to make a new Object for the session. That happens in a Constructor.

Maybe if you just put the word 'new' before mongoSessionStore it will work?
That way Mongo will make a new Object for the Session that starts.

0
votes

So as it turns out the code I was copying was using connect-mongo ^2.0.1 but that connect-mongo I have in the package.json was ^4.4.0

So I needed to change the code suitable from the original version to the new version....and this is what I got at the end:

const sessionConfig = {
        name: "next-connect.sid",
        // secret used for using signed cookies w/ the session
        secret: process.env.SESSION_SECRET,
        resave: false,
        saveUninitialized: false,
        store: MongoStore.create({
            mongoUrl: process.env.MONGODB_URI,
            mongooseConnection: mongoose.connection,
            ttl: 14 * 24 * 60 * 60 // save session for 14 days
        }),

        cookie: {
            httpOnly: true,
            maxAge: 1000 * 60 * 60 * 24 * 14 // expires in 14 days
        }
    }

    if (!dev) {
        sessionConfig.cookie.secure = true; // serve secure cookies in production environment
        server.set("trust proxy", 1); // trust first proxy
    }


    /* Apply our session configuration to express-session */
    server.use(session(sessionConfig));

and so far I think it is working properly...

0
votes

Maybe it's because you're using connect-mongo@v4, you can try to use npm i [email protected] --save to solve this problem.

0
votes

I had same issue in my application because I had updated connect-mongo to latest version (4.1). I fixed the issue by uninstalling existing connect-mongo package and re-installed version 3.1.2. either you can simply install version by typing following command:

npm install [email protected]

or you copy the following command and paste in your .json file after that type command npm install to change the version:

"connect-mongo": "^3.1.2",