pinojs/thread-stream

Error in TypeScript + ESM setup

Opened this issue · 6 comments

Hi,
I'm using thread-stream (through pino) in a project that uses TypeScript compiled to ESM modules, running in Node.js.

I'm getting this error when running the project:

file:///path-to-project/node_modules/thread-stream/index.js:50
  const toExecute = bundlerOverrides['thread-stream-worker'] || join(__dirname, 'lib', 'worker.js')
                                                                     ^
ReferenceError: __dirname is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '/path-to-project/packages/repco-cli/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
    at createWorker (file:///path-to-project/node_modules/thread-stream/index.js:50:70)
    at new ThreadStream (file:///path-to-project/node_modules/thread-stream/index.js:224:19)
    at buildStream (file:///path-to-project/node_modules/pino/lib/transport.js:21:18)
    at transport (file:///path-to-project/node_modules/pino/lib/transport.js:110:10)
    at normalizeArgs (file:///path-to-project/node_modules/pino/lib/tools.js:297:16)
    at pino (file:///path-to-project/node_modules/pino/pino.js:86:28)
    at file:///path-to-project/packages/repco-common/src/log.ts:29:20
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
    at async Promise.all (index 0)
    at ESMLoader.import (node:internal/modules/esm/loader:526:24)

I could fix the error through a hackish solution for the time being:

import module from 'module'
import p from 'path'
import pino from 'pino'

// Fix thread-stream error due to __dirname
// @ts-ignore
globalThis.__bundlerPathsOverrides = {
  'thread-stream-worker': p.join(
    p.dirname(module.createRequire(import.meta.url).resolve('thread-stream')),
    'lib',
    'worker.js',
  ),
}

const logger = pino()

However, it would be nice if that could be fixed somehow upstream.

Thanks for reporting! Would you like to send a Pull Request to address this issue? Remember to add unit tests.

@Frando You should check out https://github.com/wd-David/esbuild-plugin-pino. Solved my issues for me.

I tried looking into a way to make __dirname always available but it's not trivial, since ideally one should check the presence of "import.meta" and if it's there, then use the fileUrlToPath method to define __dirname.

Unfortunately nodejs fails with an un-catcheable syntax error if you try to just "typeof import.meta" when you are in commonjs even in a code branch that's not supposed to run...

Not sure how to do that. Luckily as @Frando pointed out - thanks to the good design one can override the 'thread-stream-worker' and everything works

I would love for a better solution 😭. Each thread must have a different entry point.

@mcollina can you please introduce pre-processor instructions to Nodejs? :D

#ifdef ESM
const __dirname = ...
#endif

Done! ;)

Seriously though, do you know why testing for the availability of "import.meta" generates an uncatchable error in node (it's a syntax error)? Tried in node 20...

Anyway, there should also be a way to NOT use __dirname altogether here.

This is my workaround 🙃

const dirname =
  typeof __dirname !== 'undefined'
    ? __dirname
    : fileURLToPath(new URL('.', import.meta.url))

I wish there was a better way...