Build: Normalize import extensions in ESM package type declarations - #80606
Draft
i-am-chitti wants to merge 1 commit into
Draft
Build: Normalize import extensions in ESM package type declarations#80606i-am-chitti wants to merge 1 commit into
i-am-chitti wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
Adds a shared post-
tscbuild step that appends explicit file extensions to the relative import/export specifiers in the compiled type declarations of"type": "module"packages, so the published.d.tsgraph resolves under Node-style ESM (node16/nodenext) and not justbundler.Why?
tscemits declaration specifiers verbatim from source, and the shared config authors extensionless relative imports (valid undermoduleResolution: "bundler"). Because these packages are"type": "module", Node interprets the emitted.d.tsas ESM, where relative specifiers require file extensions. As reported in #80206,
@arethetypeswrong/cli(attw) flags this as anInternalResolutionErrorfor@wordpress/theme,@wordpress/design-system-mcp, and@wordpress/video-conversion(and@wordpress/vips):"@wordpress/theme"
node16 (from ESM): 🥴 Internal resolution error
bundler: 🟢
Notably, the runtime half of the pipeline already handles this — esbuild emits
./private-apis.mjsinbuild-module. The defect is an asymmetry: the JS emit normalizes extensions, the declaration emit does not. This PR closes that gap inshared tooling rather than per-package.
How?
tools/build-scripts/packages/normalize-declaration-extensions.mjs, run right aftertsc --buildinbuild.mjs."type": "module"package with abuild-types/directory, it resolves every relative specifier against the emitted declaration graph and rewrites it to the runtime counterpart of its target:./foo→./foo.js(targetfoo.d.ts)./foo→./foo.mjs/.cjs(targetfoo.d.mts/foo.d.cts)./dir→./dir/index.js(directory targets)from, side-effectimport, and inline/dynamicimport(...)specifiers; skips bare (package) specifiers and specifiers that already carry an extension (idempotent).build-typesartifacts, mirroring esbuild's existing.mjshandling.normalize-declaration-extensions.test.js.Design notes / trade-offs
.ts/.tsxsource extensions viaallowImportingTsExtensions) is also viable and would make the change visible in source, but touches imports repo-wide. Both are compatible with — and superseded by — a futuretsdown/tsupdual-build migration.tsc --buildon its own still emits extensionless declarations locally; the normalization is applied bynpm run build(the published path). Onlytscwritesbuild-types, so nothing after the step clobbers it.Testing Instructions
npx tsc --build packages/theme/tsconfig.json --forcenode tools/build-scripts/packages/normalize-declaration-extensions.mjsnpx -y @arethetypeswrong/cli@0.18.4 --pack packages/theme --profile esm-onlynpm run test:unit -- tools/build-scripts/packages/normalize-declaration-extensions.test.jsVerified: a consumer importing @wordpress/theme type-checks cleanly under bundler, node16, and nodenext after normalization.
Screenshots or screencast
Not applicable.
Use of AI Tools
Claude Code: Opus 4.8
Investigate and