Skip to content

typescript 5.2 broke the ability to build hybrid node packagesΒ #55705

Closed as not planned
@isaacs

Description

@isaacs

πŸ”Ž Search Terms

hybrid
commonjs
esm
module
moduleResolution
package.json

πŸ•— Version & Regression Information

  • This changed between versions 5.1 and 5.2

⏯ Playground Link

No response

πŸ’» Code

src/index.ts

export const foo = 'bar'

tsconfig.json

{
  "include": ["src/*.ts"],
  "compilerOptions": {
    "declaration": true,
    "declarationMap": true,
    "inlineSources": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "sourceMap": true,
    "strict": true,
    "target": "es2022",
    "moduleResolution": "nodenext",
    "module": "nodenext"
  }
}

tsconfig/cjs.json

  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node16",
    "outDir": "../dist/cjs"
  }

tsconfig/esm.json

  "compilerOptions": {
    "outDir": "../dist/mjs"
  }

package.json

{
  "name": "foo",
  "version": "1.2.3",
  "type": "module",
  "exports": {
    ".": {
      "import": {
        "types": "./dist/mjs/index.d.ts",
        "default": "./dist/mjs/index.js"
      },
      "require": {
        "types": "./dist/cjs/index.d.ts",
        "default": "./dist/cjs/index.js"
      }
    }
  },
  "scripts": {
    "prepare": "tsc -p tsconfig/cjs.json && tsc -p tsconfig/esm.json && bash scripts/fixup.sh"
  }
}

scripts/fixup.sh

#!/usr/bin/env bash

cat >dist/cjs/package.json <<!EOF
{
  "type": "commonjs"
}
!EOF

cat >dist/mjs/package.json <<!EOF
{
  "type": "module"
}
!EOF

πŸ™ Actual behavior

tsconfig/cjs.json:4:15 - error TS5110: Option 'module' must be set to 'Node16' when option 'moduleResolution' is set to 'Node16'.

πŸ™‚ Expected behavior

Should create a CommonJS module at ./dist/cjs/index.js.

Should create an ESM module at ./dist/mjs/index.js

Should not emit errors.


I also tried setting the module to node16 in the cjs.json, but then it emits ESM for the CJS build.

If I remove "type": "module" from the root package.json (first of all, that's a pain, because my tests are ESM, but w/e), then it emits CommonJS for both.

If it's going to force module to match moduleResolution, and infer the type from the package.json file, then it should infer the type from the package.json file that is closest to the build location, not the source location, because that is where Node will get the type from.

Better yet, it should just allow CommonJS even if the package.json is "type": "module" and has a "require" export point.

Or just trust that the author of the config file knows what they're doing, and obey the explicitly stated config. If someone writes "module": "commonjs", then TSC should emit a commonjs module, regardless of what the package.json's type is.

Additional information about the issue

The only workaround I can see right now is to have my build script edit the root package.json (or write a package.json temporarily in ./src) in between each build, and that just feels terribly brittle.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions