How to use custom consola instance with nuxt (probably esm/cjs issue)

pimlie
593
pimlie
commented 3 months ago

Although the docs say that consola is a global object, I cant get it too work correctly it seems. I have narrowed it down to module.exports which are cached.

<summary>A basic example is this</summary>

// run as <file>.js
const { Consola, FancyReporter } = require('consola')

consola = new Consola({
  level: 4,
  reporters: [ new FancyReporter ],
  types: {
    warn: {
      level: 2,
      color: 'blue'
    },
  }
})

global.consola = consola

const consola2 = require('consola')
consola2.warn('yellow warning about nothing')

delete require.cache[require.resolve('consola')]

const consola3 = require('consola')
consola3.warn('blue warning about nothing')

The last consola3.warn is only blue when you delete the require.cache. This is because the first require already triggered node to cache the consola module, and as all other requires resolve to the same module/file it just uses the cached file.

The problem comes with esm modules like Nuxt has, the delete require.cache doesnt work there because during transpiling all requires are moved to the top of the file. Besides that, the delete require.cache trick only works when exactly:

  • the delete happens after the custom global.consola assigment
  • the require of Nuxt also happens after the custom global.consola assigment (and after the delete ofc)

<summary>Require Nuxt works (both lines blue)</summary>

// run with node -r esm <file.js>
console.log('mix -> works')
import consola from './inc/consola'
delete require.cache[require.resolve('consola')]

const { Nuxt } = require('nuxt')
const nuxt = new Nuxt()
nuxt.hook('render:context', () => {})
consola.warn('blue warning about nothing')

The following doesnt work:

<summary>Import Nuxt doesnt work (Nuxt's warning is yellow but should be blue)</summary>

// run with node -r esm <file.js>
import consola from './inc/consola'
delete require.cache[require.resolve('consola')]
import { Nuxt } from 'nuxt'

const nuxt = new Nuxt()
nuxt.hook('render:context', () => {})
consola.warn('blue warning about nothing')

<summary>inc/consola.js</summary>

import { Consola, FancyReporter } from 'consola'

let consola = global && global.consola

if (!consola) {
  consola = new Consola({
    level: 4,
    types: {
      warn: {
        level: 2,
        color: 'blue'
      },
    }
  })

  consola.add(new MyReporter())

  global.consola = consola
}

export default consola

Is it just too late and am I missing something obvious here? Any help / pointers are appreciated :)

Fyi, I am looking into this because for nuxt-generate-cluster I want all workers to push their log messages to the master so only the master has logging output. This does work nicely with a custom reporter, but I cant seem to capture the success: Generated /users/2 messages from within Nuxt.Generator. At least not without dirty tricks like re-assigning all object props again tp the global.consola object and stubbing the success method.

0
pimlie
593
pimlie
commented 3 months ago

It was partly too late I guess, I couldnt get it too work in nuxt-generate-cluster because there was still another Nuxt es6 import I missed it seems. After double checking to change all the nuxt imports to require's and add the cache delete after my own global.consola assignment it also works in the full project.

@pi0 @clarkdo Do you regards this a documentation issue or do you want to have a go at this to find a 'sexier' solution? If docs, I am happy to add something to the readme.

0
Informations
Question โ€ข Resolved
#c35 - Created 3 months ago