Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot compile a project as both Node ESM and Node CJS without hacky workarounds #55925

Closed
1 task done
alshdavid opened this issue Sep 30, 2023 · 2 comments
Closed
1 task done
Labels
Duplicate An existing issue was already created

Comments

@alshdavid
Copy link

Acknowledgement

  • I acknowledge that issues using this template may be closed without further explanation at the maintainer's discretion.

Comment

I have a project that I want to compile twice, once emitting code targeting commonjs and the second emitting code targeting Node compatible module imports.

My objective is to distribute a library where the import format can be conditionally loaded through the use of Node's conditional exports capability.

To maximise compatibility, the library would be distributed as type: commonjs and the main property which points to the commonjs output.

I need TypeScript to validate that file extensions are present in imports so the emitted code is compatible with Node ESModules.

To achieve the differential loading, I need to use Node's conditional loading via exports

// package.json
{
  "name": "my-pkg",
  "type": "commonjs",
  "main": "./dist/require/index.js"
  "exports": {
    ".": {
      "import": "./dist/import/index.js",
      "require": "./dist/require/index.js",
      "types": "./dist/types/index.d.ts",
    }
  }
  // ...
}

I have a single src that is compiled to the target based on the compiler configuration:

// tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "Node16",
    "moduleResolution": "Node16",
    "lib": ["ESNext"],
    "strict": true
  },
  "include": [
    "./src/**/*"
  ]
}

and I attempt to override the relevant properties in-line on the scripts

// package.json
{
  "name": "my-pkg",
  // ...
  "scripts": {
    "build:require": "npx tsc --outDir dist/require --module CommonJS --moduleResolution Node16 && echo \"{ \\\"type\\\": \\\"commonjs\\\" }\" > dist/require/package.json",
    "build:import": "npx tsc --outDir dist/import --module Node16 --moduleResolution Node16 && echo \"{ \\\"type\\\": \\\"module\\\" }\" > dist/import/package.json",
    "build:types": "npx tsc --outDir dist/types --module Node16 --moduleResolution Node16 --emitDeclarationOnly --declaration"
  }
}

The issue is, module: Node16 determines the output format based on the type property of the package.json.

// package.json
{
  "name": "my-pkg",
  // ...
  "type": "module", // "module" | "commonjs"
}

This means I must programmatically rewrite the package.json['type'] field to instruct tsc to emit CJS or MJS code and cannot rely on a TypeScript configuration compilerOption.

Intuitively, I would have thought:

{ "module": "ESNext", "moduleResolution": "Node16t" } // Emit Modules with support for Node
{ "module": "CommonJS", "moduleResolution": "Node16" } // Emit CommonJS

However, in conjunction with the package.json type field (which cannot be easily set programmatically), the above combinations are invalid and you can only use:

{ "module": "ESNext", "moduleResolution": "NodeNext" }
{ "module": "ESNext", "moduleResolution": "Node16" }
@jakebailey
Copy link
Member

jakebailey commented Sep 30, 2023

I think you're looking for: #54593

See also: https://www.npmjs.com/package/tshy or https://github.com/denoland/dnt, which both do the double-compile.

@DanielRosenwasser DanielRosenwasser added the Duplicate An existing issue was already created label Oct 2, 2023
@typescript-bot
Copy link
Collaborator

This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Oct 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants