1

I have a site in express and am trying to convert it to use a routes.js file to clean things up. I am getting a TypeError, explained below. I have read this and this but I still can't figure it out. Currently the site works with the following lines:

const server = express()
    .set('view engine', 'ejs') // set up ejs for templating
    .use(flash()) // use connect-flash for flash messages stored in session
  .use((req, res) => res.render('../views/pages/indextimewithall.ejs', {stockSearched :"X",
                     activeStocks: [],
                    addingError:false}) )
  .listen(port);


const wss = new SocketServer({ server });

wss.on('connection', (ws) => {
  console.log('Client connected');
  ws.on('close', () => console.log('Client disconnected'));
});

setInterval(() => {
  wss.clients.forEach((client) => {
    client.send(new Date().toTimeString());
  });
}, 1000);

But when I change it to this:

const server = express()

.set('view engine', 'ejs') // set up ejs for templating
        .use(flash()) // use connect-flash for flash messages stored in session
      .listen(port);
    require('./app/routes.js')(server); 

    const wss = new SocketServer({ server });

    wss.on('connection', (ws) => {
      console.log('Client connected');
      ws.on('close', () => console.log('Client disconnected'));
    });

    setInterval(() => {
      wss.clients.forEach((client) => {
        client.send(new Date().toTimeString());
      });
    }, 1000);

..I get the TypeError: app.get is not a function

Here are the contents of routes.js file:

// app/routes.js
module.exports = function(app) {
    app.get('/', function(req, res) {
        var myStocks = require('./models/myStock'); 
        var showStocks = function(err, data){
            res.render('pages/indextimewithall.ejs', {
                     stockSearched :"X",
                    activeStocks: [],
                    addingError:false
                });
        }
        myStocks.find({isActive:true}).exec(showStocks);
    });
};

Thank you for any suggestions.

garson
  • 1,395
  • 3
  • 19
  • 45

1 Answers1

0

Your clean up is just fine (although the readability and maintainability is a big issue...). Here is a big gotcha for you:

app.listen method is not chainable, but app.use or app.METHOD series are. This means this method is not return itself at the end. Therefore, you will get app.get is undefined, because your server variable is not an express instance.

What you should do is break the chain, and defined as the following:

const app = express();
app.set('view engine', 'ejs');     // set up ejs for templating
app.use(flash());                  // use connect-flash for flash messages stored in session
require('./app/routes.js')(app);   // not recommended to clean up like this way though
app.listen(port);


const wss = new SocketServer({ server: app });
wss.on('connection', (ws) => {
  console.log('Client connected');
  ws.on('close', () => console.log('Client disconnected'));
});


setInterval(() => {
  wss.clients.forEach((client) => {
    client.send(new Date().toTimeString());
  });
}, 1000);

Note, in the above, I renamed your variable server as app. Just to follow the convention.

You can know if a method is chainable by running something like this:

const app = express();
console.log(app === app.use((req, res, next) => next)));  // true
console.log(app === app.listen(3000));  // false
Leo Li
  • 217
  • 4
  • 20
  • Thanks! For some reason now the setInterval() isn't working though (the action it's taking isn't appearing) any ideas why? – garson Apr 26 '18 at 04:14
  • That is because you load it from a separate file... If you load the module via ES6 `import/export`, then `setInterval` will working. The reason behind it is very complicated. For more information, you can google it. Here is a quick [reference](https://medium.com/the-node-js-collection/an-update-on-es6-modules-in-node-js-42c958b890c) on the status of implementing the ES6 module loading. And it is currently available in the experimental mode. – Leo Li Apr 26 '18 at 04:19
  • I believe you can still kick the function defined in `setInterval` working, and you will have to make some change to let it happened, but I'm not sure about the details to do it, you can give it a try. – Leo Li Apr 26 '18 at 04:23
  • 1
    Thank you, I got it to work by replacing app.listen(port) with const server = app.listen(port, () => console.log(`Listening on ${ port }`)); and then writing just 'server' instead of 'server: app' I really appreciate all your help! I am still learning the conventions around organization too - always trying to improve on that... – garson Apr 26 '18 at 04:27