ezolenko / rollup-plugin-typescript2

Rollup plugin for typescript with compiler errors.
MIT License
819 stars 71 forks source link

set declaration to be `index.d.cts` for `cjs` format #448

Open mesqueeb opened 1 year ago

mesqueeb commented 1 year ago

currently

With this plugin I generate index.cjs via rollup and this plugin generates the index.d.ts next to it.

desired

how can I set the generated index.d.ts file to be called index.d.cts instead?

Versions

  System:
    OS: macOS 13.3.1
    CPU: (8) arm64 Apple M2
    Memory: 309.73 MB / 24.00 GB
    Shell: 3.6.0 - /opt/homebrew/bin/fish
  Binaries:
    Node: 16.20.0 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 8.19.4 - /usr/local/bin/npm
  npmPackages:
    rollup: ^3.22.0 => 3.22.0
    rollup-plugin-typescript2: ^0.34.1 => 0.34.1
    typescript: ^5.0.4 => 5.0.4

rollup.config.js

:
```js import typescript from 'rollup-plugin-typescript2' import pkg from '../package.json' assert { type: 'json' } export default { input: 'src/index.ts', output: [ { file: pkg.exports['.'].require.default, format: 'cjs' }, { file: pkg.exports['.'].import.default, format: 'esm' }, ], external: Object.keys(pkg.dependencies || []), plugins: [typescript({ tsconfigOverride: { exclude: ['test/**/*'] } })], } ```

tsconfig.json

:
```json5 { "compilerOptions": { "allowJs": false, "baseUrl": ".", "declaration": true, "downlevelIteration": true, "esModuleInterop": true, "isolatedModules": true, "lib": ["esnext", "DOM", "DOM.Iterable"], "module": "esnext", "moduleResolution": "node", "noImplicitReturns": true, "noUnusedLocals": true, "skipLibCheck": true, "sourceMap": true, "strict": true, "target": "es2019", "useDefineForClassFields": true }, "include": ["src/**/*", "test/**/*"] } ```

package.json

:
```json "sideEffects": false, "type": "module", "types": "./dist/index.d.ts", "module": "./dist/index.js", "main": "./dist/index.js", "exports": { ".": { "require": { "types": "./dist/cjs/index.d.ts", "default": "./dist/cjs/index.cjs" }, "import": { "types": "./dist/index.d.ts", "default": "./dist/index.js" } } }, "files": [ "dist" ], "engines": { "node": ">=12.13" }, ```
mesqueeb commented 1 year ago

current workaround:

import typescript from 'rollup-plugin-typescript2'
import pkg from '../package.json' assert { type: 'json' }
import fs from 'fs'

function renameCjsTypeDeclaration() {
  return {
    name: 'renameCjsTypeDeclaration',
    writeBundle: {
      sequential: true,
      order: 'post',
      handler({ dir, format }) {
        if (format === 'cjs') {
          fs.rename('dist/cjs/index.d.ts', 'dist/cjs/index.d.cts', console.error)
        }
      },
    },
  }
}

export default {
  input: 'src/index.ts',
  output: [
    { file: pkg.exports['.'].import.default, format: 'esm' },
    { file: pkg.exports['.'].require.default, format: 'cjs' },
  ],
  external: Object.keys(pkg.dependencies || []),
  plugins: [
    typescript({ tsconfigOverride: { exclude: ['test/**/*'] } }),
    renameCjsTypeDeclaration(),
  ],
}
agilgur5 commented 1 year ago

So CJS and Rollup's CJS option have been available long before .cts or .cjs. As such, any logic would have to be able to output with different file endings.

We could introduce an option to customize file endings.

Another option could be to check the file ending of the output JS file and mirror that for the typings. As in, if outputting as .cjs, then output typings as .d.cts. That would be considered a breaking change though since it would change existing behavior.

That's a great, simple workaround in the meantime! Thanks for providing the code so that other users can do the same if needed!

ezolenko commented 1 year ago

That would be considered a breaking change though since it would change existing behavior.

Would all the tooling that uses typings (debuggers, language servers, etc) expect correct extension though? Or do they usually have fallbacks to d.ts?

If so, changing typing extension to match output extension would break or obsolete mostly workarounds. A minor version bump either way.

agilgur5 commented 1 year ago

I was more thinking in the opposite direction -- tools that don't yet support .cts would break. For example, if a user has a declaration processor plugin after rpt2, this change could break that user's plugin pipeline (unless they have already updated that plugin to a version that supports .cts).

Either way, it is changed behavior. And yea, since rpt2 is still 0.x, a minor is considered breaking, so that would work. Just not a patch.

agilgur5 commented 1 year ago

how can I set the generated index.d.ts file to be called index.d.cts instead?

So there is potentially a small problem here. If your input is index.mts, TypeScript would only generate index.d.mts (similar for .cts).

Rollup cannot convert a declaration file to cjs format as Rollup cannot interpret TS files. The TypeScript compiler might be able to do that when module: "commonjs", but I'm not sure it would. Either way, we only set the tsconfig once for the whole program, so being able to change this on-the-fly during Rollup's output phase may not be possible or may require some decent refactoring 😕

ezolenko commented 1 year ago

Using multiple rollup configs instead of multiple outputs in one config might be needed, similar to what rpt2 does itself: https://github.com/ezolenko/rollup-plugin-typescript2/blob/master/rollup.config.self.js