vite-plugin-dts
vite-plugin-dts copied to clipboard
Generate different declaration types
Description
One of the differences introduced by TypeScript v5 is that .d.ts files are affected by esm and cjs contexts. So, sharing a single .d.ts file between the two can lead to invalid formats when a library is dual publishing for these contexts.
The solution is to generate .d.mts & .d.cjs files.
https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/FalseCJS.md https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/FalseESM.md
Under what circumstance would Vite create these wrong, I am not sure. However, for integrity, it would be best for these to be split up.
Suggested solution
Create an option to generate different, or multiple versions of the output files. It's not necessarily a requirement for the library to add specific support to generate .d.mts, .d.cts variants, but the ability to do it yourself would work.
Perhaps this is already possible through one of the included hooks. However, this I am not sure of.
Alternative
I don't really think there is an alternative.
Additional context
Alternatively/additionally, a section on the FAQ could also help.
This could also be a vue-tsc related issue, as I don't think they generate those files.
Validations
- [X] Read the FAQ.
- [X] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
I have read the information you provided, but I can't find the difference in content between .d.cts
and .d.mts
files. Are they just different file extensions?
I have equally had the same questions but have found little information on what the true differences actually are syntactically. Sadly, the js ecosystem is really weird and this question is very obscure.
The only differences I can think of are the differences with how things are exported, cjs exports map to export =
, mjs exports map to export {}
or export default
The original issue was found when looking at https://publint.dev/rules#export_types_invalid_format
So, it is quite possible that these things are the same. But there isn't a whole lot of info. In my opinion, they are likely the same. But perhaps this is a deeper question to TypeScript as there isn't a whole lot of information on this topic.
Indeed this https://arethetypeswrong.github.io/?p=bootstrap-vue-next%400.12.0 displays that some of the issue described contain these resolution issues
I found this in TypeScript docs: https://www.typescriptlang.org/docs/handbook/esm-node.html#packagejson-exports-imports-and-self-referencing.
It says: It’s important to note that the CommonJS entrypoint and the ES module entrypoint each needs its own declaration file, even if the contents are the same between them.
And I have never seen a declaration file uses export =
.
So, currently we can consider they are only different in their file extensions. For this, we can add some options for custom the declaration file extensions (while considering multiple outputs with different file extensions).
And I have never seen a declaration file uses export =.
This was a mistake. I meant to account for the differences between export default/export {} & module.exports.
So, currently we can consider they are only different in their file extensions. For this, we can add some options for custom the declaration file extensions (while considering multiple outputs with different file extensions).
This will likely work. If this is implemented, I would like to check and see what arethetypeswrong.github.io says. If it comes out with everything being clean, then imo there should likely be a section on this projects README as it should become the standard
Hello, facing the exact same issue. Any updates so far?
The way we've handled this in our company's internal component library, is to use the afterBuild
hook to copy and rename the files:
import { copyFileSync } from "node:fs"
import { defineConfig } from "vite"
import dts from "vite-plugin-dts"
// https://vitejs.dev/config/
export default defineConfig({
build: {...},
plugins: [
...,
dts({
afterBuild: () => {
// To pass publint (`npm x publint@latest`) and ensure the
// package is supported by all consumers, we must export types that are
// read as ESM. To do this, there must be duplicate types with the
// correct extension supplied in the package.json exports field.
copyFileSync("dist/index.d.ts", "dist/index.d.mts")
},
exclude: [ ... ],
include: ["src"],
}),
],
})
One small change to make publint happy. Change to copyFileSync("dist/index.d.ts", "dist/index.d.cts");
and have your package.json exports look something like:
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/main.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/main.cjs"
}
}
},
Specifically, the CJS types need to use the .cts
extension rather than having a .mts
extension for ESM, at least when you're using "type": "module"
.
@mkilpatrick yes! I had to do that version when converting to proper esm-first.
And I have never seen a declaration file uses
export =
.
If I only have a default export attw
complains about node16 (from CJS) │ ❗️ Incorrect default export
. If I modify the .d.cts
file's export default MyDefaultExportedFn
to export = MyDefaultExportedFn
then the error goes away.
Or as an odd workaround, if I add an extra export, next to the default export, then the error also goes away in attw