Search code examples
javascriptnode.jsexpresses6-modules

Getting javascript ES modules to work in NodeJS app


I have an app.js file built using NodeJS and ExpressJS, which calls a routes.js file for URL handling, and that in turn references a controller.js file which renders my templates/views. I had multiple routes working with CommonJS, but when I tried to convert it all to ES Modules, I'm having problems.

The following code works with a route file with a single route. But, I can't get it to work with more than one route. It wants an export default for the single route, which does work, or gives me this error if I try multiple routes in a single route.js file: Route.get() requires a callback function but got a [object Undefined]. Maybe my syntax is off, maybe it's something else.

This is my working code, but it breaks when I try to add multiple routes...

Here's my app.js call to the routes file:

import shopRoutes from './routes/shop.js';
app.use(shopRoutes);

I'm calling the controller file from the routes file as such:

import express from 'express';
import * as shopController from '../controllers/shop.js';
const router = express.Router();
const shopIndex = router.get('/', shopController.getIndex);
// need to be able to use more routes like this, etc
// const shopIndex = router.get('/product', shopController.getProducts);
export default shopIndex;

And here's the related controller file:

export const getIndex = (req, res, next) => {
  res.render('shop/index', {
    pageTitle: 'Shop',
    path: '/',
  });
};
// need to be able to use more functions for template assignment
// export const getProducts = (req, res, next) => {
//  res.render('shop/product', {
//    pageTitle: 'Product',
//    path: '/product',
//  });
// };

export default getIndex;

How can I have more than one route in the routes file, which would call multiple controller functions, using ES6 Modules? Any and all help appreciated.


Solution

  • First, remove the default export from your controller file. You're already exporting getIndex as a named export and it doesn't really make sense to duplicate it as the default.

    Then, add whatever route handlers you want to your shop router and export it

    // controllers/shop.js
    
    export const getIndex = (req, res, next) => {
      // ...
    };
    
    export const getProducts = (req, res, next) => {
      // ...
    };
    
    // routes/shop.js
    
    import express from 'express';
    import * as shopController from '../controllers/shop';
    
    const router = express.Router();
    router.get('/', shopController.getIndex);
    router.get('/product', shopController.getProducts);
    
    export default router;
    
    // app.js
    
    import shopRouter from './routes/shop';
    
    app.use(shopRouter);
    

    I'm not a big fan of * imports and prefer being explicit...

    import { getIndex, getProducts } from '../controllers/shop';