Skip to content

Replace winston deep import with main-entry import for ESM#138

Merged
cuzzlor merged 2 commits intomainfrom
fix/esm-winston-deep-import
Apr 21, 2026
Merged

Replace winston deep import with main-entry import for ESM#138
cuzzlor merged 2 commits intomainfrom
fix/esm-winston-deep-import

Conversation

@cuzzlor
Copy link
Copy Markdown
Collaborator

@cuzzlor cuzzlor commented Apr 21, 2026

Summary

Fixes a runtime SyntaxError in the v2 beta ESM build when consumers import from @makerx/node-winston under pure ESM (e.g. Vitest, Node 22+ with "type": "module"):

SyntaxError: The requested module 'winston/lib/winston/transports' does not provide an export named 'Console'

The offending line was:

import { Console, ConsoleTransportOptions } from 'winston/lib/winston/transports'

That worked under CJS require() but breaks in ESM for two reasons (verified against winston 3.19.0):

  1. Directory import. Node ESM requires the explicit /index.js suffix; otherwise it throws ERR_UNSUPPORTED_DIR_IMPORT.
  2. Lazy-getter named exports aren't statically detectable. Even with the suffix, winston/lib/winston/transports/index.js defines Console via Object.defineProperty(exports, 'Console', { get() { return require('./console') } }). cjs-module-lexer (what Node's ESM→CJS interop uses) doesn't expose this shape as an ESM named binding, so import { Console } fails.

Fix: go through winston's main entry, which does exports.transports = require('./winston/transports') — a form cjs-module-lexer handles cleanly. ConsoleTransportOptions is now sourced via the transports namespace (type-only).

Also updated the direct-usage example in the README to match.

Test plan

  • npm run check-types passes
  • npm run lint passes
  • npm run test — all 34 tests pass
  • npm run build — verified dist/index.mjs no longer references winston/lib/winston/transports
  • Swapped the built package into a consumer ESM project (vitest) — the original SyntaxError: Named export 'Console' not found is gone and the suite passes

🤖 Generated with Claude Code

cuzzlor and others added 2 commits April 21, 2026 12:46
`import { Console, ConsoleTransportOptions } from 'winston/lib/winston/transports'`
worked under CJS but fails from the published ESM build. Two reasons:

- It's a directory import — Node ESM requires the explicit `/index.js`
  suffix and otherwise throws `ERR_UNSUPPORTED_DIR_IMPORT`.
- Even with the suffix, winston's transports index exposes `Console` via
  `Object.defineProperty(exports, 'Console', { get() { return require('./console') } })`,
  a shape `cjs-module-lexer` doesn't expose as an ESM named binding —
  importers get `SyntaxError: Named export 'Console' not found`.

Go through winston's main entry (`exports.transports = require(...)`)
instead, which cjs-module-lexer handles cleanly. Verified the produced
`dist/index.mjs` no longer references the deep path, and that a consumer
ESM project (vitest) can now import `@makerx/node-winston` without the
SyntaxError.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cuzzlor cuzzlor requested review from Royce and pleb April 21, 2026 04:49
@cuzzlor cuzzlor merged commit e6895e3 into main Apr 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants