thread-stream icon indicating copy to clipboard operation
thread-stream copied to clipboard

Error in TypeScript + ESM setup

Open Frando opened this issue 2 years ago • 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.

Frando avatar Jan 24 '23 14:01 Frando

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

mcollina avatar Jan 24 '23 15:01 mcollina

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

izakfilmalter avatar Feb 05 '24 23:02 izakfilmalter

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

claudioc avatar Feb 20 '24 18:02 claudioc

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

mcollina avatar Feb 21 '24 06:02 mcollina

@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.

claudioc avatar Feb 21 '24 08:02 claudioc

This is my workaround 🙃

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

I wish there was a better way...

albinekb avatar Apr 09 '24 06:04 albinekb