Skip to content

Commit b3a39de

Browse files
committed
fix(language-core): don't look for input files during evaluation of vueCompilerOptions
close #5598
1 parent 56f1267 commit b3a39de

File tree

2 files changed

+99
-101
lines changed
  • packages

2 files changed

+99
-101
lines changed

packages/component-meta/lib/base.ts

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,24 @@ export function createCheckerByJsonConfigBase(
2727
rootDir = rootDir.replace(windowsPathReg, '/');
2828
return baseCreate(
2929
ts,
30-
() => vue.createParsedCommandLineByJson(ts, ts.sys, rootDir, json),
30+
() => {
31+
const commandLine = vue.createParsedCommandLineByJson(ts, ts.sys, rootDir, json);
32+
const { fileNames } = ts.parseJsonConfigFileContent(
33+
json,
34+
ts.sys,
35+
rootDir,
36+
{},
37+
undefined,
38+
undefined,
39+
vue.getAllExtensions(commandLine.vueOptions)
40+
.map(extension => ({
41+
extension: extension.slice(1),
42+
isMixedContent: true,
43+
scriptKind: ts.ScriptKind.Deferred,
44+
})),
45+
);
46+
return [commandLine, fileNames];
47+
},
3148
checkerOptions,
3249
rootDir,
3350
path.join(rootDir, 'jsconfig.json.global.vue'),
@@ -42,25 +59,45 @@ export function createCheckerBase(
4259
tsconfig = tsconfig.replace(windowsPathReg, '/');
4360
return baseCreate(
4461
ts,
45-
() => vue.createParsedCommandLine(ts, ts.sys, tsconfig),
62+
() => {
63+
const commandLine = vue.createParsedCommandLine(ts, ts.sys, tsconfig);
64+
const { fileNames } = ts.parseJsonSourceFileConfigFileContent(
65+
ts.readJsonConfigFile(tsconfig, ts.sys.readFile),
66+
ts.sys,
67+
path.dirname(tsconfig),
68+
{},
69+
tsconfig,
70+
undefined,
71+
vue.getAllExtensions(commandLine.vueOptions)
72+
.map(extension => ({
73+
extension: extension.slice(1),
74+
isMixedContent: true,
75+
scriptKind: ts.ScriptKind.Deferred,
76+
})),
77+
);
78+
return [commandLine, fileNames];
79+
},
4680
checkerOptions,
4781
path.dirname(tsconfig),
4882
tsconfig + '.global.vue',
4983
);
5084
}
5185

52-
export function baseCreate(
86+
function baseCreate(
5387
ts: typeof import('typescript'),
54-
getCommandLine: () => vue.ParsedCommandLine,
88+
getConfigAndFiles: () => [
89+
commandLine: vue.ParsedCommandLine,
90+
fileNames: string[],
91+
],
5592
checkerOptions: MetaCheckerOptions,
5693
rootPath: string,
5794
globalComponentName: string,
5895
) {
59-
let commandLine = getCommandLine();
96+
let [commandLine, _fileNames] = getConfigAndFiles();
6097
/**
6198
* Used to lookup if a file is referenced.
6299
*/
63-
let fileNames = new Set(commandLine.fileNames.map(path => path.replace(windowsPathReg, '/')));
100+
let fileNames = new Set(_fileNames.map(path => path.replace(windowsPathReg, '/')));
64101
let projectVersion = 0;
65102

66103
vue.writeGlobalTypes(commandLine.vueOptions, ts.sys.writeFile);
@@ -172,8 +209,8 @@ export function baseCreate(
172209
projectVersion++;
173210
},
174211
reload() {
175-
commandLine = getCommandLine();
176-
fileNames = new Set(commandLine.fileNames.map(path => path.replace(windowsPathReg, '/')));
212+
[commandLine, _fileNames] = getConfigAndFiles();
213+
fileNames = new Set(_fileNames.map(path => path.replace(windowsPathReg, '/')));
177214
this.clearCache();
178215
},
179216
clearCache() {

packages/language-core/lib/utils/ts.ts

Lines changed: 54 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,41 @@ import { camelize, NOOP as noop } from '@vue/shared';
22
import { posix as path } from 'path-browserify';
33
import type * as ts from 'typescript';
44
import { generateGlobalTypes, getGlobalTypesFileName } from '../codegen/globalTypes';
5-
import { getAllExtensions } from '../languagePlugin';
65
import type { RawVueCompilerOptions, VueCompilerOptions, VueLanguagePlugin } from '../types';
76
import { hyphenateTag } from './shared';
87

9-
export type ParsedCommandLine = ts.ParsedCommandLine & {
8+
interface ParseConfigHost extends Omit<ts.ParseConfigHost, 'readDirectory'> {}
9+
10+
export interface ParsedCommandLine extends Omit<ts.ParsedCommandLine, 'fileNames'> {
1011
vueOptions: VueCompilerOptions;
11-
};
12+
}
1213

1314
export function createParsedCommandLineByJson(
1415
ts: typeof import('typescript'),
15-
parseConfigHost: ts.ParseConfigHost & {
16-
writeFile?(path: string, data: string): void;
17-
},
16+
host: ParseConfigHost,
1817
rootDir: string,
1918
json: any,
2019
configFileName?: string,
2120
): ParsedCommandLine {
22-
const proxyHost = proxyParseConfigHostForExtendConfigPaths(parseConfigHost);
23-
ts.parseJsonConfigFileContent(json, proxyHost.host, rootDir, {}, configFileName);
24-
25-
const resolver = new CompilerOptionsResolver(parseConfigHost.fileExists);
21+
const extendedPaths = new Set<string>();
22+
const proxyHost = {
23+
...host,
24+
readFile(fileName: string) {
25+
if (!fileName.endsWith('/package.json')) {
26+
extendedPaths.add(fileName);
27+
}
28+
return host.readFile(fileName);
29+
},
30+
readDirectory() {
31+
return [];
32+
},
33+
};
34+
const parsed = ts.parseJsonConfigFileContent(json, proxyHost, rootDir, {}, configFileName);
35+
const resolver = new CompilerOptionsResolver(host.fileExists);
2636

27-
for (const extendPath of proxyHost.extendConfigPaths.reverse()) {
37+
for (const extendPath of [...extendedPaths].reverse()) {
2838
try {
29-
const configFile = ts.readJsonConfigFile(extendPath, proxyHost.host.readFile);
39+
const configFile = ts.readJsonConfigFile(extendPath, host.readFile);
3040
const obj = ts.convertToObject(configFile, []);
3141
const rawOptions: RawVueCompilerOptions = obj?.vueCompilerOptions ?? {};
3242
resolver.addConfig(rawOptions, path.dirname(configFile.fileName));
@@ -37,111 +47,62 @@ export function createParsedCommandLineByJson(
3747
// ensure the rootDir is added to the config roots
3848
resolver.addConfig({}, rootDir);
3949

40-
const resolvedVueOptions = resolver.build();
41-
const parsed = ts.parseJsonConfigFileContent(
42-
json,
43-
proxyHost.host,
44-
rootDir,
45-
{},
46-
configFileName,
47-
undefined,
48-
getAllExtensions(resolvedVueOptions)
49-
.map(extension => ({
50-
extension: extension.slice(1),
51-
isMixedContent: true,
52-
scriptKind: ts.ScriptKind.Deferred,
53-
})),
54-
);
55-
56-
// fix https://github.com/vuejs/language-tools/issues/1786
57-
// https://github.com/microsoft/TypeScript/issues/30457
58-
// patching ts server broke with outDir + rootDir + composite/incremental
59-
parsed.options.outDir = undefined;
60-
6150
return {
6251
...parsed,
63-
vueOptions: resolvedVueOptions,
52+
vueOptions: resolver.build(),
6453
};
6554
}
6655

6756
export function createParsedCommandLine(
6857
ts: typeof import('typescript'),
69-
parseConfigHost: ts.ParseConfigHost,
70-
tsConfigPath: string,
58+
host: ParseConfigHost,
59+
configFileName: string,
7160
): ParsedCommandLine {
7261
try {
73-
const rootDir = path.dirname(tsConfigPath);
74-
const proxyHost = proxyParseConfigHostForExtendConfigPaths(parseConfigHost);
75-
const config = ts.readJsonConfigFile(tsConfigPath, proxyHost.host.readFile);
76-
ts.parseJsonSourceFileConfigFileContent(config, proxyHost.host, rootDir, {}, tsConfigPath);
77-
78-
const resolver = new CompilerOptionsResolver(parseConfigHost.fileExists);
62+
const extendedPaths = new Set<string>();
63+
const proxyHost = {
64+
...host,
65+
readFile(fileName: string) {
66+
if (!fileName.endsWith('/package.json')) {
67+
extendedPaths.add(fileName);
68+
}
69+
return host.readFile(fileName);
70+
},
71+
readDirectory() {
72+
return [];
73+
},
74+
};
75+
const config = ts.readJsonConfigFile(configFileName, proxyHost.readFile);
76+
const parsed = ts.parseJsonSourceFileConfigFileContent(
77+
config,
78+
proxyHost,
79+
path.dirname(configFileName),
80+
{},
81+
configFileName,
82+
);
83+
const resolver = new CompilerOptionsResolver(host.fileExists);
7984

80-
for (const extendPath of proxyHost.extendConfigPaths.reverse()) {
85+
for (const extendPath of [...extendedPaths].reverse()) {
8186
try {
82-
const configFile = ts.readJsonConfigFile(extendPath, proxyHost.host.readFile);
87+
const configFile = ts.readJsonConfigFile(extendPath, host.readFile);
8388
const obj = ts.convertToObject(configFile, []);
8489
const rawOptions: RawVueCompilerOptions = obj?.vueCompilerOptions ?? {};
8590
resolver.addConfig(rawOptions, path.dirname(configFile.fileName));
8691
}
8792
catch {}
8893
}
8994

90-
const resolvedVueOptions = resolver.build();
91-
const parsed = ts.parseJsonSourceFileConfigFileContent(
92-
config,
93-
proxyHost.host,
94-
path.dirname(tsConfigPath),
95-
{},
96-
tsConfigPath,
97-
undefined,
98-
getAllExtensions(resolvedVueOptions)
99-
.map(extension => ({
100-
extension: extension.slice(1),
101-
isMixedContent: true,
102-
scriptKind: ts.ScriptKind.Deferred,
103-
})),
104-
);
105-
106-
// fix https://github.com/vuejs/language-tools/issues/1786
107-
// https://github.com/microsoft/TypeScript/issues/30457
108-
// patching ts server broke with outDir + rootDir + composite/incremental
109-
parsed.options.outDir = undefined;
110-
11195
return {
11296
...parsed,
113-
vueOptions: resolvedVueOptions,
114-
};
115-
}
116-
catch {
117-
// console.warn('Failed to resolve tsconfig path:', tsConfigPath, err);
118-
return {
119-
fileNames: [],
120-
options: {},
121-
vueOptions: getDefaultCompilerOptions(),
122-
errors: [],
97+
vueOptions: resolver.build(),
12398
};
12499
}
125-
}
100+
catch {}
126101

127-
function proxyParseConfigHostForExtendConfigPaths(parseConfigHost: ts.ParseConfigHost) {
128-
const extendConfigPaths: string[] = [];
129-
const host = new Proxy(parseConfigHost, {
130-
get(target, key) {
131-
if (key === 'readFile') {
132-
return (fileName: string) => {
133-
if (!fileName.endsWith('/package.json') && !extendConfigPaths.includes(fileName)) {
134-
extendConfigPaths.push(fileName);
135-
}
136-
return target.readFile(fileName);
137-
};
138-
}
139-
return target[key as keyof typeof target];
140-
},
141-
});
142102
return {
143-
host,
144-
extendConfigPaths,
103+
options: {},
104+
errors: [],
105+
vueOptions: getDefaultCompilerOptions(),
145106
};
146107
}
147108

0 commit comments

Comments
 (0)