Skip to content

fix: serve CJS runtime with ESM type declarations#130

Draft
angeloashmore wants to merge 1 commit intomainfrom
aa/fix-module-resolution
Draft

fix: serve CJS runtime with ESM type declarations#130
angeloashmore wants to merge 1 commit intomainfrom
aa/fix-module-resolution

Conversation

@angeloashmore
Copy link
Member

Resolves: #129, #105

Description

Fixes ERR_MODULE_NOT_FOUND errors on Node.js 22+ and 24+ caused by ESM bare specifier imports of next/script, next/navigation, etc.

The exports map now serves CJS for runtime (avoiding bare import issues) while pointing the types condition to .d.ts (ESM) declarations, ensuring TypeScript resolves @prismicio/client and next/* types correctly.

Root cause and how this was tested

The package previously used require/import conditional exports, serving .cjs for CJS consumers and .js (ESM) for ESM consumers. The ESM output contains bare specifier imports like import Script from "next/script" which fail under strict ESM resolution in Node.js 22+/24+ because Next.js subpaths don't resolve without file extensions in ESM mode.

Prior fix attempts (#106, #125, #128) oscillated between CJS-only and dual formats. CJS-only fixed runtime but created a type resolution problem: .d.cts type declarations resolve dependencies in CJS mode (require condition), and if a dependency like @prismicio/client is ESM-only, TypeScript silently degrades those types to any (verified with tsc --traceResolution).

The fix uses types/default conditions instead of require/import:

".": {
    "types": "./dist/index.d.ts",
    "default": "./dist/index.cjs"
}
  • Runtime: Both require() and import() resolve to .cjs — no bare import errors.
  • Types: TypeScript uses the types condition → .d.ts → resolves in ESM mode → @prismicio/client and next/* types resolve correctly with full type safety.

This was tested by creating isolated test projects with moduleResolution: "node16" and "bundler", verifying type resolution traces, and confirming that types do not silently degrade to any.

Also set exports: false in tsdown.config.ts to prevent tsdown from overwriting the custom exports map during builds.

Checklist

  • If my changes require tests, I added them.
  • If my changes affect backward compatibility, it has been discussed.
  • If my changes require an update to the CONTRIBUTING.md guide, I updated it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

Node 24 Dynamic import missing file extension

1 participant