From 7458a5af98583606a64ddd2e98dfefa5aa5d4038 Mon Sep 17 00:00:00 2001 From: thebanjomatic Date: Tue, 24 Oct 2023 16:26:02 -0600 Subject: [PATCH 1/3] fix: allow types wildcard export to match w/o ext When using typescript's "moduleResolution": "bundler" option, we currently get a bunch of type errors, particularly when trying to extend the types, or when consuming other packages which extend the types (vue-router, pinia, etc). For example, vue-router extends the types as follows: ```ts declare module 'vue/types/vue' { interface Vue { $router: VueRouter $route: Route } } declare module 'vue/types/options' { interface ComponentOptions { router?: VueRouter beforeRouteEnter?: NavigationGuard beforeRouteLeave?: NavigationGuard beforeRouteUpdate?: NavigationGuard } } ``` But this silently fails (when using skipLibChecks: true), and the types aren't available on the vue constructor options or the component instance. The reason for this can be seen when copying the code into your own project with `"moduleResolution": "bundler"`: ``` Invalid module name in augmentation, module 'vue/types/vue' cannot be found.ts(2664) module "vue/types/vue" ``` What is happening is that once "moduleResolution" is set to "bundler", the "exports" maps in package.json starts being used, and there are some peculiarities with wildcard matching that we don't appear to be accounting for here. In particular, wildcard matching is going to require that the full path to the file is provided. So when we specify `declare module 'vue/types/vue'` it is going to look for a file on disk with the relative path: `./types/vue`, and since there is no file with that name, it fails. What this PR does is provide multiple options to look for when an import matches the "./types/*" export. 1) First we append '.d.ts' and check for that file. I suspect this will be the most common occurence (people that didn't use the extension) so I'm listing it first. 2) In the event that someone had done `declare module 'vue/types/vue.js'` or `declare module 'vue/types/vue.d.ts'` in their code to work around this issue in prior versions of vue 2.7.x, we still allow for those to match directly. Fixes: #13106 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b294d8bb6ae..f1ec6540eee 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "require": "./compiler-sfc/index.js" }, "./dist/*": "./dist/*", - "./types/*": "./types/*", + "./types/*": ["./types/*.d.ts", "./types/*"], "./package.json": "./package.json" }, "sideEffects": false, From 963c0c2c7e8aa4008607a1afda6f828b64496b96 Mon Sep 17 00:00:00 2001 From: thebanjomatic Date: Tue, 24 Oct 2023 16:39:15 -0600 Subject: [PATCH 2/3] fix(types): fixing vue/compiler-sfc types Types were broken when consuming the "./compiler-sfc" subpath export from an esm context. To reproduce, you can set `"type": "module"` in package.json, and "moduleResolution": "bundler" or "node16" in your tsconfig.json. This still works by accident for `"type": "commonjs"` because when it matches `"require": "./compiler-sfc/index.js"` typescript will also check for the corresponding `index.d.ts` file. However, for `"./compiler-sfc/index.mjs"` it winds up checking for `index.d.mts` and doesn't find one. After this commit, types should be working in all cases for the compiler-sfc entrypoint with moduleResolution: "node", "node16", and "bundler" when the consuming package is listed as "type": "module" or "commonjs". --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index f1ec6540eee..7e7b2fd6da4 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "types": "./types/index.d.ts" }, "./compiler-sfc": { + "types": "./compiler-sfc/index.d.ts", "import": "./compiler-sfc/index.mjs", "require": "./compiler-sfc/index.js" }, From cbb59cf67ea16bf80d31a4fd92b3a7a3f087d6ef Mon Sep 17 00:00:00 2001 From: thebanjomatic Date: Tue, 24 Oct 2023 16:46:03 -0600 Subject: [PATCH 3/3] chore: moving types condition to top This change is somewhat optional as things are working as currently specified, but the typescript team suggests in their documenation that the "types" condition should be listed first to guarantee that its used. The main difference is that when "types" is listed first, it will match early in the process and just use the types that you specified. If it is listed last, typescript will first match on the "require", "import", "default" conditions that appear higher up in the list. It then does extension modification to try to find corresponding .d.ts files. In more concrete terms, typescript will wind up looking for "./dist/vue.runtime.esm.d.ts" or "./dist/vue.runtime.common.d.ts" (depending on context) first. Since these files don't exist, it will skip those conditions and keep going until it ultimately finds the "types" entry and use that. After moving "types" to be the first condition, we get the same result, but skip the extra checks. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 7e7b2fd6da4..c0f16275078 100644 --- a/package.json +++ b/package.json @@ -18,12 +18,12 @@ ], "exports": { ".": { + "types": "./types/index.d.ts", "import": { "node": "./dist/vue.runtime.mjs", "default": "./dist/vue.runtime.esm.js" }, - "require": "./dist/vue.runtime.common.js", - "types": "./types/index.d.ts" + "require": "./dist/vue.runtime.common.js" }, "./compiler-sfc": { "types": "./compiler-sfc/index.d.ts",