3

So, the following code works in development and fails when running in a production environment, with the error TypeError: Router.use() requires middleware function but got a Object. I must have tried this about a hundred different ways by now all with the same result. Works in dev, not in prod.

/server/routes.js

'use strict';

export class AppRoutes
{
    constructor(app)
    {
        this.app = app;

        return function initialize(app)
        {
            app.use('/mail', require('./api/mail'));
        }
    }
}

/server/app.js

var app = express();
import { AppRoutes } from './routes';
let router = new AppRoutes();
router(app);

// start the server here

// Expose app
export default app;

Again, working in dev, broken when the ES6 is transpiled and the app is run in production. Thanks in advance for any thoughts on the matter.

update

The error is thrown on line 458 of /node_modules/express/lib/router/index.js. This is what is being passed to Router.use():

{ default: 
   { [Function: router]
     params: {},
     _params: [],
     caseSensitive: undefined,
     mergeParams: undefined,
     strict: undefined,
     stack: [ [Object], [Object] ] 
    } 
}

Here are the versions of the dependencies I think are relevant to the error (same in prod as in dev):

node v0.12.2

And from my package.json:

{
    "express": "^4.13.3",
    "babel-runtime": "^5.8.20",
    "grunt-babel": "^6.0.0"
},
"devDependencies": {
    "babel-core": "^5.8.34",
    "babel-preset-es2015": "^6.1.18",
    "babel-preset-stage-0": "^6.1.18"
}
Justin
  • 1,341
  • 11
  • 24
  • Why does your constructor take an `app` argument (that you don't pass) and then the initialize function also takes an `app` argument rather than using the instance variable? Pick one or the other and use it consistently. At best, this is confusing design. At worst, it's easy to make programming mistakes that way. – jfriend00 Nov 16 '15 at 01:29
  • One obvious question is to describe all the versions of everything that is installed in both dev and production. It would also be useful to see exactly which line of code your error occurs on and to see what exactly is being passed to `Router.use()`. – jfriend00 Nov 16 '15 at 01:31
  • The short answer to your question is "because I'm just shooting blindly at this point". I'll get that info for you and update my question in a bit. – Justin Nov 16 '15 at 01:40
  • Ha. I found the culprit. It was in a routing file that wasn't in the call stack in the console. This line from `/server/api/mail/index.js`: `export default router` (`router` being `express.Router()`). Your suggestion led me there, so I'd be happy to accept it as an answer if you want to post it. Also, I'd love to know how I'm failing to understand ES6 exports :) – Justin Nov 16 '15 at 01:59

1 Answers1

4

This is happened because Babel has changed default export behavior in 6.0.

Now if you want to get default export, you should implicitly do it:

app.use('/mail', require('./api/mail').default);

You can see the answer about motivation of this change in another question

Also, keep all babel-* packages at the same major version. 6.0 presets will not work with 5.8 babel-core.

Zac Anger
  • 6,983
  • 2
  • 15
  • 42
just-boris
  • 9,468
  • 5
  • 48
  • 84
  • Sorry it took me a while to reply. I've been messing around with getting versions in order. The problem is not in my `AppRoutes` class, but in the routes module for the /mail endpoint. I haven't been able to export a function unless I actually name a function and use `module.exports` to export it. I think I'm failing to understand something fundamental about es6 exports and Express routing. – Justin Nov 20 '15 at 19:04
  • Babel has changed `module.exports` attitude since 6th version. Look at the related question about the details and solutions: http://stackoverflow.com/questions/33505992/babel-6-changes-how-it-exports-default – just-boris Nov 20 '15 at 23:05
  • You're right, of course. Not sure why I didn't grasp that on my first read. Thanks. – Justin Nov 20 '15 at 23:28