Skip to content

Add exports map with ESM-flavoured type declarations for node16/nodenext - #1525

Open
markedwards wants to merge 1 commit into
KevinVandy:v3from
markedwards:fix/add-exports-map
Open

Add exports map with ESM-flavoured type declarations for node16/nodenext#1525
markedwards wants to merge 1 commit into
KevinVandy:v3from
markedwards:fix/add-exports-map

Conversation

@markedwards

Copy link
Copy Markdown

Problem

Under TypeScript's moduleResolution: node16 / nodenext (the modern default for ESM projects), material-react-table resolves to the wrong type shape.

Two things combine:

  1. No exports field. The package ships main (CJS) and module (ESM), but nodenext ignores module, so it falls back to the CJS build.
  2. A single dist/index.d.ts. Under node16/nodenext, a .d.ts file is interpreted as CommonJS when the package has no "type": "module" — regardless of which resolution condition reached it. So dist/index.d.ts (correct for the ESM build) is read in a CommonJS context and named imports/types resolve incorrectly.

Fix

Add an exports map with per-condition types, and emit an ESM-flavoured declaration file so ESM consumers get ESM-interpreted types:

"exports": {
  ".": {
    "import":  { "types": "./dist/index.d.mts", "default": "./dist/index.esm.js" },
    "require": { "types": "./dist/index.d.ts",  "default": "./dist/index.js" }
  },
  "./*": "./*"
}

dist/index.d.mts is produced as a second output of the existing rollup-plugin-dts step — the same bundled declarations, just written with the .d.mts extension so it's read as ESM:

{
  input: './dist/types/index.d.ts',
  output: [
    { file: `./${pkg.typings}`, format: 'esm' },   // dist/index.d.ts
    { file: './dist/index.d.mts', format: 'esm' },  // added
  ],
  plugins: [ /* … */ dts() ],
}

No source changes, no new dependencies, no copy step — the declaration bundler emits both files in the same pass.

Backwards compatibility

Additive, no breaking change:

  • main, module, typings are retained, so legacy resolvers and bundlers behave exactly as before.
  • The require condition still points at the unchanged dist/index.d.ts, so CommonJS consumers are unaffected.
  • "./*": "./*" preserves every existing deep import (e.g. material-react-table/locales/...), so the exports map restricts nothing that resolved before.

The only change is that moduleResolution: node16/nodenext consumers now get correct types. Safe as a patch release.


The build was not run in this PR. The resulting artifact shape (dist/index.d.mts + the exports map) was validated by applying the equivalent change to an installed 3.2.1 and type-checking a real nodenext consumer — types resolve correctly. The rollup-plugin-dts change is a standard second output writing the same bundled declarations to a .d.mts.

`moduleResolution: node16`/`nodenext` consumers currently fall back to the
CommonJS build and read `dist/index.d.ts` in a CommonJS context, so named
imports/types resolve incorrectly.

Add an `exports` map with per-condition types and emit a `dist/index.d.mts`
(read as ESM) alongside the existing `dist/index.d.ts`. The `.d.mts` is a
second output of the existing `rollup-plugin-dts` step — identical bundled
declarations, no copy step, no new dependency.

Additive: `main`/`module`/`typings` retained; the `require` condition still
points at the unchanged `dist/index.d.ts`; `"./*": "./*"` preserves deep
imports (e.g. `locales`). Safe as a patch release.
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

@markedwards is attempting to deploy a commit to the Kevin Vandy OSS Team on Vercel.

A member of the Team first needs to authorize it.

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.

1 participant