skip to Main Content

I am trying to rewrite NodeJS modules(constant xxx = require(‘yyy’)) into es6 format. I tried to export the router using export syntax in es6 but the following error always popped up:

      throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
            ^

TypeError: Router.use() requires a middleware function but got a Module
    at Function.use (C:Usersblognode_modulesexpresslibrouterindex.js:469:13)
    at Function.<anonymous> (C:Usersblognode_modulesexpresslibapplication.js:227:21)
    at Array.forEach (<anonymous>)
    at Function.use (C:Usersblognode_modulesexpresslibapplication.js:224:7)
    at file:///C:/Users/blog/server.js:20:5
    at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
    at async loadESM (node:internal/process/esm_loader:28:7)
    at async handleMainPromise (node:internal/modules/run_main:113:12)

I am sure that my es6 syntax should be correct:

export default router;

The code may be related to this error is as below:

route/article.js

import express from 'express'
import * as Article from './../models/article.js';
const router = express.Router()

router.get('/new', (req, res) => {
  res.render('article/new', { article: new Article() })
})

router.get('/edit/:id', async (req, res) => {
  const article = await Article.findById(req.params.id)
  res.render('article/edit', { article: article })
})

router.get('/:slug', async (req, res) => {
  const article = await Article.findOne({ slug: req.params.slug })
  if (article == null) res.redirect('/')
  res.render('article/show', { article: article })
})

router.post('/', async (req, res, next) => {
  req.article = new Article()
  next()
}, saveArticleAndRedirect('new'))

router.put('/:id', async (req, res, next) => {
  req.article = await Article.findById(req.params.id)
  next()
}, saveArticleAndRedirect('edit'))

router.delete('/:id', async (req, res) => {
  await Article.findByIdAndDelete(req.params.id)
  res.redirect('/')
})

function saveArticleAndRedirect(path) {
  return async (req, res) => {
    let article = req.article
    article.title = req.body.title
    article.description = req.body.description
    article.markdown = req.body.markdown
    try {
      article = await article.save()
      res.redirect(`/article/${article.slug}`)
    } catch (e) {
      res.render(`article/${path}`, { article: article })
    }
  }
}

export default router;

Other code that may be related:

models/article.js

import mongoose from 'mongoose'
import {marked} from 'marked'
import slugify from 'slugify'
import createDomPurify from 'dompurify'
import { JSDOM }  from 'jsdom'
const dompurify = createDomPurify(new JSDOM().window)

const articleSchema = new mongoose.Schema({
 title:{
    type: String,
    required: true
 },
 description: {
    type: String
 },
 markdown: {
    type: String,
    required: true
 },
 createdAt: {
    type: Date,
    default: Date.now
 },
 slug: {
   type: String,
   required: true,
   unique: true
 },
 sanitizedHTML: {
   type: String, 
   required: true
 }
})

articleSchema.pre('validate', function(next) {
   if(this.title) {
      this.slug = slugify(this.title, {lower: true, strict:true})
   }
   if(this.markdown){
    
      this.sanitizedHTML = DomPurify.sanitize(marked.parse(this.markdown))
         
      }
      else{
         console.log("Error")
      }
   next()
})

export const Article = mongoose.model('Article', articleSchema);

server.js:

import express from 'express'
import mongoose from 'mongoose'
import * as Article from './models/article.js';
import * as articleRouter from './route/article.js';
import methodOverride from 'method-override'
const app = express()


mongoose.connect('mongodb://localhost:27017/', {})

app.set('view engine', 'ejs')
app.use(express.urlencoded({ extended: false }))
app.use(methodOverride('_method'))

app.get('/', async (req, res) => {
  const article = await Article.find().sort({ createdAt: 'desc' })
  res.render('article/index', { article: article })
})

app.use('/article', articleRouter)

app.listen(3000)

The file structure is as below:

enter image description here

================================================

Update

Thank you for Mike’s suggestion, but still, another error popped up:

file:///C:/Users/blog/server.js:16
  const article = await Article.find().sort({ createdAt: 'desc' })
                                ^

TypeError: Article.find is not a function
    at file:///C:/Users/blog/server.js:16:33
    at Layer.handle [as handle_request] (C:Usersblognode_modulesexpresslibrouterlayer.js:95:5)
    at next (C:Usersblognode_modulesexpresslibrouterroute.js:149:13)
    at Route.dispatch (C:Usersblognode_modulesexpresslibrouterroute.js:119:3)
    at Layer.handle [as handle_request] (C:Usersblognode_modulesexpresslibrouterlayer.js:95:5)
    at C:Usersblognode_modulesexpresslibrouterindex.js:284:15
    at Function.process_params (C:Usersblognode_modulesexpresslibrouterindex.js:346:12)
    at next (C:Usersblognode_modulesexpresslibrouterindex.js:280:10)
    at methodOverride (C:Usersblognode_modulesmethod-overrideindex.js:65:14)
    at Layer.handle [as handle_request] (C:Usersblognode_modulesexpresslibrouterlayer.js:95:5)

2

Answers


  1. The problem is with your import * as articleRouter from './route/article.js';.

    Your article.js file exports nothing other than a default export (router). This is why you’re catching this error.

    You could also, instead, try use-ing articleRouter.default, if you want to keep import * as..., but that’s obviously a bad practice.

    import express from 'express'
    import mongoose from 'mongoose'
    import * as Article from './models/article.js';
    import articleRouter from './route/article.js';
    import methodOverride from 'method-override'
    const app = express()
    
    
    mongoose.connect('mongodb://localhost:27017/', {})
    
    app.set('view engine', 'ejs')
    app.use(express.urlencoded({ extended: false }))
    app.use(methodOverride('_method'))
    
    app.get('/', async (req, res) => {
      const article = await Article.find().sort({ createdAt: 'desc' })
      res.render('article/index', { article: article })
    })
    
    app.use('/article', articleRouter)
    
    app.listen(3000)
    
    Login or Signup to reply.
  2. When transitioning to ES6 syntax for Node.js modules, it’s important to align the export and import statements correctly to avoid common pitfalls, especially with frameworks like Express. The error message you encountered, "Router.use() requires a middleware function but got a Module," typically arises when the import does not correctly match the exported entity, particularly when dealing with default and named exports.

    In your case, the issue lies in the way the router is imported in your server.js file. ES6 introduces two main ways to export modules: default exports and named exports. Default exports are used when a module exports a single entity, like a class or a function. Named exports are useful when a module exports multiple entities.

    For your router module, you’ve used a default export:

    export default router;
    

    However, when importing this router into your server configuration, the syntax used seems to treat it as if it were a named export:

    import * as articleRouter from './route/article.js';
    

    This syntax attempts to import all exports from the specified module as an object, which is not what you want for a default export. Instead, you should directly import the default export without the * as syntax:

    import articleRouter from './route/article.js';
    

    This change tells JavaScript to import the default export from ./route/article.js directly into articleRouter, allowing you to use it as intended with app.use(‘/article’, articleRouter).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search