Nuxt.js 2 – how to access hook instance in server middleware

Issue

Let me preface this by saying that this is an area of Nuxt I have literally zero experience in and there seems to be very few resources about it online, even Nuxt’s docs are lacking. So feel free to correct any incorrect assumptions I make in this post.

I’m running a websocket listener in a hook in a module and a regular Express api server in a server-middleware. On their own they seem to be working without issue, but what I can’t seem to get right is accessing the websocket listener in one of the api endpoints, so that if the api gets hit I can notify the clients subscribed to the ws. Let me show you.

Here’s my websocket listener hook module:

// @/modules/ws.js

const WebSocket = require('ws')
const wss = new WebSocket.Server({ noServer: true })

wss.on('connection', ws => {
  console.log('client connected', wss.clients.size)

  ws.on('message', data => {
    console.log('received:', data)
    data = JSON.parse(data)

    if(data.type === 'connection') {
      ws.clientId = data.id
      return ws.send(JSON.stringify({ type: 'connection', status: 'success', id: ws.clientId }))
    }
  })
})

export default function () {
  this.nuxt.hook('listen', server => {
    server.on('upgrade', (request, socket, head) => {
      wss.handleUpgrade(request, socket, head, ws => {
        wss.emit('connection', ws)
      })
    })
  })
}

And then here’s my api server:

// @/server-middleware/index.js

const express = require('express')
const app = express()

app.post('/test-route', (req, res) => {
  console.log('connection received')
  // here I'd now like to access wss to notify subscribed clients
  res.json({ status: 'success' })
})

module.exports = app

And then wiring it all up in nuxt.config.js

...
modules: ['@/modules/ws'],
serverMiddleware: ['@/server-middleware/index'],
...

Firstly, I’m worried that I’m going about this all the wrong way and that I should somehow be sticking the api server into modules/ws.js then everything should be accessible right there, but I have no idea how to take over Express, such that it still works, so if you have advice here, I’d super appreciate it.

Short of that, I’d just like to access the wss object that was instantiated in modules/ws.js in server-middleware/index.js because then theoretically I should still be able to push messages to subscribed clients, right? But how do I do that? I tried straight requireing the exported default function from ws.js, but that seems to just return the function and not the wss instance. I also tried looking at the this.nuxt object in the middleware, same as in the hook module, but that just returns undefined.

So now I’m out of things to try, and with how foreign all of this is to me, I can’t even conceive of anything else that might be remotely related. Any advice about any of this will be greatly appreciated.

Nuxt.js version 2.15.7, FWIW

Solution

One possible way is to separate the WebSocket server into a different file to import for later use.

Example:

// @/modules/ws/wss.js

const WebSocket = require('ws')
const wss = new WebSocket.Server({ noServer: true })

wss.on('connection', ws => {
  ...
})

module.exports = {
  handleUpgrade (request, socket, head) {
    wss.handleUpgrade(request, socket, head, ws => {
      wss.emit('connection', ws)
    })
  },

  getActiveClients () {
    return [...wss.clients].filter(
      client => client.readyState === WebSocket.OPEN
    )
  }
}
// @/modules/ws/index.js

const wss = require('./wss')

export default function () {
  this.nuxt.hook('listen', server => {
    server.on('upgrade', wss.handleUpgrade)
  })
}

Then use it in your server middleware:

// @/server-middleware/index.js

const express = require('express')
const wss = require('../modules/ws/wss')

const app = express()

app.get('/broadcast', (req, res) => {
  for (let client of wss.getActiveClients()) {
    client.send('broadcast!')
  }

  res.json({ status: 'success' })
})

module.exports = app

Answered By – User 28

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published