Skip to content

Commit 8df62f1

Browse files
jdz321qmhc
andauthored
fix: resolve tsconfig globs relative to tsconfig dir (#455)
TypeScript resolves include/exclude/files patterns relative to the tsconfig file location, but unplugin-dts passes them to createFilter() which resolves globs relative to plugin root. When tsconfig is not in the project root, this mismatch can exclude valid sources and break dts generation. Convert tsconfig globs to root-relative patterns before creating the filter. Update vue-vite example to use a solution tsconfig with references. Co-authored-by: spark <> Co-authored-by: Rocco <544022268@qq.com>
1 parent 0bb5bc3 commit 8df62f1

4 files changed

Lines changed: 85 additions & 68 deletions

File tree

examples/vue-vite/tsconfig.json

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,7 @@
11
{
22
// test comment
3-
"compilerOptions": {
4-
"target": "esnext",
5-
"module": "esnext",
6-
"moduleResolution": "node",
7-
"importHelpers": true,
8-
"outDir": "dist",
9-
"strict": true,
10-
"jsx": "preserve",
11-
"jsxImportSource": "vue",
12-
"allowJs": true,
13-
"sourceMap": true,
14-
"resolveJsonModule": true,
15-
"esModuleInterop": true,
16-
"skipLibCheck": true,
17-
"experimentalDecorators": true,
18-
"types": [
19-
"node",
20-
"vite/client"
21-
],
22-
"baseUrl": ".",
23-
"paths": {
24-
"@/*": ["./*"],
25-
"@components/*": ["./src/components/*"],
26-
"$alias/*": ["./alias/*"]
27-
},
28-
"lib": ["esnext", "dom"]
29-
},
30-
"include": ["src", "components", "alias", "*.d.ts"]
3+
"files": [],
4+
"references": [
5+
{ "path": "./tsconfig/tsconfig.app.json" }
6+
]
317
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"compilerOptions": {
3+
"target": "esnext",
4+
"module": "esnext",
5+
"moduleResolution": "node",
6+
"importHelpers": true,
7+
"outDir": "dist",
8+
"strict": true,
9+
"jsx": "preserve",
10+
"jsxImportSource": "vue",
11+
"allowJs": true,
12+
"sourceMap": true,
13+
"resolveJsonModule": true,
14+
"esModuleInterop": true,
15+
"skipLibCheck": true,
16+
"experimentalDecorators": true,
17+
"types": [
18+
"node",
19+
"vite/client"
20+
],
21+
"baseUrl": "..",
22+
"paths": {
23+
"@/*": ["./*"],
24+
"@components/*": ["./src/components/*"],
25+
"$alias/*": ["./alias/*"]
26+
},
27+
"lib": ["esnext", "dom"]
28+
},
29+
"include": ["../src", "../components", "../alias", "../*.d.ts"]
30+
}

examples/vue-vite/vite.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export default defineConfig({
3434
plugins: [
3535
// @ts-ignore
3636
dts({
37+
tsconfigPath: resolve('./tsconfig/tsconfig.app.json'),
3738
processor: 'vue',
3839
copyDtsFiles: true,
3940
outDirs: [

packages/unplugin-dts/src/core/runtime.ts

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,24 @@ export class Runtime {
200200
return ensureArray(rootGlobs).map(glob => normalizeGlob(resolveConfigDir(glob, '.')))
201201
}
202202

203-
const relativeRoot = configPath
204-
? normalizePath(relative(root, dirname(configPath)).replace(globSignRE, '\\$&'))
205-
: '.'
203+
// TS globs are relative to tsconfig dir; plugin filter globs are relative to `root`.
204+
const relativeRoot = configPath ? normalizePath(relative(root, dirname(configPath))) : '.'
205+
206+
const relativeRootGlob = relativeRoot === '.' ? '.' : relativeRoot.replace(globSignRE, '\\$&')
207+
208+
const resolveTsGlobToRoot = (glob: string) => {
209+
glob = normalizePath(glob)
210+
211+
// Keep absolute globs as-is (POSIX + `C:/...`).
212+
if (glob.startsWith('/') || /^[a-zA-Z]:\//.test(glob)) return glob
213+
214+
if (relativeRootGlob === '.') return glob
215+
216+
return `${relativeRootGlob}/${glob}`
217+
}
206218

207219
return ensureArray(tsGlobs?.length ? tsGlobs : defaultGlob).map(glob =>
208-
normalizeGlob(resolveConfigDir(glob, relativeRoot)),
220+
normalizeGlob(resolveTsGlobToRoot(resolveConfigDir(glob, '.'))),
209221
)
210222
}
211223

@@ -340,7 +352,14 @@ export class Runtime {
340352
}
341353

342354
async transform(id: string, code: string) {
343-
const { publicRoot, outDirs, resolvers, rootFiles, outputFiles, transformedFiles } = this
355+
const {
356+
publicRoot,
357+
outDirs,
358+
resolvers,
359+
rootFiles,
360+
outputFiles,
361+
transformedFiles,
362+
} = this
344363

345364
let resolver: Resolver | undefined
346365
id = normalizePath(id).split('?')[0]
@@ -575,41 +594,34 @@ export class Runtime {
575594
},
576595
)
577596

578-
await runParallel(
579-
cpus().length,
580-
Array.from(mapFiles.entries()),
581-
async ([filePath, content]) => {
582-
const baseDir = dirname(filePath)
597+
await runParallel(cpus().length, Array.from(mapFiles.entries()), async ([filePath, content]) => {
598+
const baseDir = dirname(filePath)
583599

584-
filePath = resolve(
585-
outDir,
586-
relative(entryRoot, cleanVueFileName ? filePath.replace('.vue.d.ts', '.d.ts') : filePath),
587-
)
588-
589-
try {
590-
const sourceMap: { sources: string[], mappings: string } = JSON.parse(content)
600+
filePath = resolve(
601+
outDir,
602+
relative(entryRoot, cleanVueFileName ? filePath.replace('.vue.d.ts', '.d.ts') : filePath),
603+
)
591604

592-
sourceMap.sources = sourceMap.sources.map(source => {
593-
return normalizePath(
594-
relative(
595-
dirname(filePath),
596-
resolve(currentDir, relative(publicRoot, baseDir), source),
597-
),
598-
)
599-
})
605+
try {
606+
const sourceMap: { sources: string[], mappings: string } = JSON.parse(content)
600607

601-
if (prependMappings.has(filePath)) {
602-
sourceMap.mappings = `${prependMappings.get(filePath)}${sourceMap.mappings}`
603-
}
608+
sourceMap.sources = sourceMap.sources.map(source => {
609+
return normalizePath(
610+
relative(dirname(filePath), resolve(currentDir, relative(publicRoot, baseDir), source)),
611+
)
612+
})
604613

605-
content = JSON.stringify(sourceMap)
606-
} catch (e) {
607-
logger.warn(`${logPrefix} ${yellow('Processing source map fail:')} ${filePath}`)
614+
if (prependMappings.has(filePath)) {
615+
sourceMap.mappings = `${prependMappings.get(filePath)}${sourceMap.mappings}`
608616
}
609617

610-
await writeOutput(filePath, content, outDir)
611-
},
612-
)
618+
content = JSON.stringify(sourceMap)
619+
} catch (e) {
620+
logger.warn(`${logPrefix} ${yellow('Processing source map fail:')} ${filePath}`)
621+
}
622+
623+
await writeOutput(filePath, content, outDir)
624+
})
613625

614626
handleDebug('write output')
615627

@@ -621,12 +633,10 @@ export class Runtime {
621633
pkg = pkgPath && existsSync(pkgPath) ? JSON.parse(await readFile(pkgPath, 'utf-8')) : {}
622634
} catch (e) {}
623635

624-
const transformed = new Set(
625-
Array.from(transformedFiles).map(file => {
626-
file = relative(entryRoot, file)
627-
return `${file.replace(tjsRE, '')}.d.${getJsExtPrefix(file)}ts`
628-
}),
629-
)
636+
const transformed = new Set(Array.from(transformedFiles).map(file => {
637+
file = relative(entryRoot, file)
638+
return `${file.replace(tjsRE, '')}.d.${getJsExtPrefix(file)}ts`
639+
}))
630640

631641
const entryNames = Object.keys(entries)
632642
const types = findTypesPath(pkg.publishConfig, pkg)

0 commit comments

Comments
 (0)