ref(typescript): Default to node16 module/moduleResolution#21520
ref(typescript): Default to node16 module/moduleResolution#21520mydea wants to merge 12 commits into
Conversation
… imports Svelte's `exports` map does not declare deep subpaths like `svelte/types/compiler/preprocess`, which our source imports (still needed for Svelte 3 support). `node16` resolution honors the `exports` map and rejects these, so pin the svelte package back to the legacy `node` resolver, which resolves them via filesystem lookup. Emitted `.d.ts` is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`@sentry/angular` is `"type": "module"`, so under the new `node16` base resolution its relative imports would require explicit `.js` extensions (TS2835), breaking the `ng build`. Like our other framework packages (react, vue) it's compiled via a bundler (ng-packagr), so set `module: esnext` + `moduleResolution: bundler` explicitly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`@sentry/solid` imports ESM-only deps (`solid-js`, `solid-js/web`). Under the new `node16` base resolution, a CommonJS file can't `require` an ESM module (TS1479/TS1541). Like our other framework packages it's bundled, so set `module: esnext` + `moduleResolution: bundler` explicitly. Emitted `.d.ts` is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`@sentry/angular` is built with ng-packagr, which pins TypeScript 4.6 — that version predates `node16` and rejects the literal anywhere in the inherited config chain, even when the package overrides module/moduleResolution. So stop extending the shared base entirely and inline the effective base options here, using `esnext`/`node` (which TS 4.6 supports). Build output verified byte-identical to before. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ests The TS 3.8 compatibility job patches the base tsconfig before running, but only stripped `noUncheckedIndexedAccess`. With the base now defaulting to `node16` module/moduleResolution (added in TS 4.7), TS 3.8 fails on the unrecognized literal. Downgrade both to TS 3.8-compatible `esnext`/`node` in the `use-ts-3_8.js` setup scripts for node and node-core integration tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The previous attempt set `module: esnext` when patching the base tsconfig for TS 3.8. But the integration-test scenarios run via `node -r ts-node/register`, so ts-node compiled them to ESM and they crashed on load as CommonJS — every scenario timed out. Restore the pre-`node16` base shape instead: drop `module` (ts-node falls back to CommonJS, as before) and keep `moduleResolution: node`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6f65ac6 to
6229192
Compare
There was a problem hiding this comment.
in #19435 we change the resolution to bundler for ts 6.0/7.0 compatibility, should we go for that instead?
Note: The TS upgrade guide recommends either bundler or nodenext with bundler being a more suitable option for us.
ah, I see. I guess then we can go ahead and just move it to bundler/esnext everywhere already, should be fine I think! |
Cool, |
Everything we ship is bundled (Rollup emits the JS; tsc only emits .d.ts, which is byte-identical either way), so the base config now defaults to esnext/bundler — a uniform, modern default that the bundled majority of packages already used. This also avoids the node16 literal, which older toolchains (Angular's pinned TS 4.6, the TS 3.8 compat job) can't parse. Removes all now-redundant module/moduleResolution overrides across packages, leaving only genuine exceptions: - svelte: `node` resolution (Svelte 3 imports deep paths not in its exports map) - angular: inlined config with esnext/node (ng-packagr pins TS 4.6) - nextjs/remix tsconfig.test.json: Node16 (deliberately exercise node resolution) - astro tsconfig.dev.json: unchanged dev config Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Make
module: "node16"+moduleResolution: "node16"the default in the base config (packages/typescript/tsconfig.json, previouslymoduleResolution: "node"with an implicitmodule: "es6"), then clean up the per-package overrides accordingly.This is a dev-time-only change. In this repo tsc never emits the shipped JavaScript — Rollup does (every package's
exportspoint at/build/...). tsc is used only to (a) type-check our source and (b) emit.d.ts. Somodule/moduleResolutionaffect only how strictly our own source is type-checked; they do not change any shipped artifact.Verification: built
.d.ts(and, for Angular, the full ng-packagr output) old-vs-new for representatives of each category and diffed — byte-identical. JS bundles are Rollup-emitted and provably independent of these options. All build/types configs type-check with no config-validity errors.node16/node16 vs esnext/bundler — and why each, where
The two coherent pairings model different consumers (mixing them, e.g.
esnext+node16, is rejected by tsc):node16/node16models Node's real resolver: honorsexports/importsconditional resolution and the CJS/ESM file-mode split. Stricter, "how Node actually sees it." Best fit for packages meant to run in Node.esnext/bundlermodels how a bundler (Rollup/webpack/Vite/esbuild) resolves: readsexportsconditions but skips the Node CJS/ESM mode split and extension rules. Best fit for packages that are always run through a bundler (browser / framework / edge).Since everything here is bundled and consumers only ever see built
/buildfiles + hand-authoredexportsmaps, the choice is about type-checking fidelity, not output. We default tonode16because the majority of packages are Node/server packages — they get stricter, Node-realistic checking for free — and we keepbundlerwhere it was already deliberately configured for bundled targets.What changed
Base (
packages/typescript/tsconfig.json):module: node16+moduleResolution: node16.Removed now-redundant overrides (these inherit the base):
Node16overrides dropped fromnode,node-core,tanstackstart.lib: ["es2020"]dropped fromnode,tanstackstart,types,server-utils,node-native,profiling-node(base already setslib: ["es2020"];node-corekeeps its extraES2021.WeakRef).Added explicit overrides where a package previously set only one of the pair and leaned on the old base default (otherwise they'd hit the invalid
node16+bundler/esnext+node16combos):module: "esnext"added to keep theirbundler:browser,astro,integration-shims,react-router.moduleResolution: "bundler"added to keep theiresnext:cloudflare,hono,deno,feedback,node-native,profiling-node,replay-canvas,replay-internal,replay-worker.Per-package exceptions surfaced by node16
node16 honors
exportsmaps and ESM/CJS file modes that the oldnode(node10) resolver ignored. Three packages needed targeted handling:TS2307: imports deep internal subpaths (e.g.svelte/types/compiler/preprocess) that Svelte'sexportsmap doesn't declare. Still needed for Svelte 3 support, so pinned to the legacynoderesolver (filesystem lookup)..d.tsunchanged.TS1479/TS1541: a CommonJS package importing ESM-only deps (solid-js). Bundled, so setesnext/bundler..d.tsunchanged.node16didn't exist until TS 4.7, so TS 4.6 rejects the literal anywhere in the inherited config chain (even when overridden). Resolved by not extending the shared base for this package — its tsconfig now inlines the effective base options and usesesnext/node(TS-4.6-compatible). It is the only package that doesn't extend the base; a comment documents why. Full ng-packagr build output verified byte-identical.Net effect: the default now matches the Node-package majority, the bundled packages explicitly declare they're bundler-targeted instead of silently relying on a default, and nothing we ship changes.
🤖 Generated with Claude Code