mkdist icon indicating copy to clipboard operation
mkdist copied to clipboard

Declarations not genered to `.mts` and `.cts` files

Open brawaru opened this issue 1 year ago • 2 comments

Environment

mkdist 1.1.2 on Node.js 16.14.2, v18.14.0.

Reproduction

  1. Have .mts and .cts files in your src directory.
  2. Run mkdist -d --ext js
Example project files
// farewells.cts
export function sayGoodbye(name: string) {
  console.log(`Goodbye, ${name}!`)
}
// greetings.ts
export function sayHello(name: string) {
  console.log(`Hello, ${name}!`)
}
// index.mts
import { sayHello } from './greetings.js'
import { sayGoodbye } from './farewells.cjs'
 
sayHello('World')
sayGoodbye('World')

StackBlitz example: https://stackblitz.com/edit/node-erv3qh?file=package.json&view=editor (use pnpm build:tsc to build with TypeScript and pnpm build:mkdist to build with mkdist, start to run ./dist/index.mjs with Node).

Describe the bug

mkdist ignores .cts and .mts files and copies them as is instead of compiling them to .cjs (+.d.cts) and .mjs (+.d.mts) respectfully.

Additional context

I could've tried to explain the importance of these file extensions on my own but Bing did a nicer job than me 😢

The .mjs and .cjs extensions are used to specify the module type of a JavaScript file in Node.js 16+. The .mjs extension indicates that the file is an ECMAScript module (ESM), which is a standard format for modular JavaScript code. The .cjs extension indicates that the file is a CommonJS module, which is a legacy format that was widely used before ESM was introduced^1.

The .mts and .cts extensions are used to specify the module type of a TypeScript file. TypeScript is a superset of JavaScript that adds static types and other features. The .mts extension indicates that the file is an ESM TypeScript file, which will be emitted as an .mjs file when compiled to JavaScript. The .cts extension indicates that the file is a CommonJS TypeScript file, which will be emitted as a .cjs file when compiled to JavaScript^1.

These extensions help Node.js to determine how to load and execute different types of modules without relying on ambiguous heuristics or configuration options^3. They also help developers to write clear and consistent code across different environments.

While this is a nice explanation, it fails to mention a few other important things:

If your file has a .ts extension, TypeScript always assumes the resulting file will have .js extension. So if any of the files in your project imports the other file that has .ts extension, and you use Node16 (NodeNext) module resolution (which you very much should btw), TypeScript forces you to write import with .js extension, which is incompatible with mkdist, unless you force it in .js extension mode (--ext js), which you cannot do in environments like nuxt-module-builder without patching it (which is exactly what I'm struggling with and what I am doing).

The other important thing is that .ts, .cts, .mts on the declaration files imply the existence of the file with the same basename: that is, index.d.ts says ‘the declaration file is for index.js’, a.d.cts is ‘for a.cjs’, and b.d.mts is ‘for b.mjs’. That becomes super important for libraries that ship with wildcard exports in package.json, as well helps you as developer to avoid writing types condition which may or may not lead to a correct declaration file (without types export condition TypeScript looks for [basename].d.[ts/cts/mts]).

{
  "exports": {
    "./locale-data/*": { "import": "./dist/locale-data/*" }
  }
}

Logs

No response

brawaru avatar Mar 15 '23 15:03 brawaru