Skip to content

Commit a4719fb

Browse files
committed
Move to more well defined api
- Resolve the plugin path by looking for a `browser` field in the `package.json` - Use `import(...)` to load the module async - Load the plugin async
1 parent ba3586a commit a4719fb

File tree

3 files changed

+44
-8
lines changed

3 files changed

+44
-8
lines changed

src/server/project.ts

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,7 @@ namespace ts.server {
906906
return this.getFileNames().map((fileName): protocol.FileWithProjectReferenceRedirectInfo => ({
907907
fileName,
908908
isSourceOfProjectReferenceRedirect: includeProjectReferenceRedirectInfo && this.isSourceOfProjectReferenceRedirect(fileName)
909-
}));
909+
}));
910910
}
911911

912912
hasConfigFile(configFilePath: NormalizedPath) {
@@ -1482,7 +1482,7 @@ namespace ts.server {
14821482
if (!lastReportedFileNames.has(fileName)) {
14831483
added.set(fileName, isSourceOfProjectReferenceRedirect);
14841484
}
1485-
else if (includeProjectReferenceRedirectInfo && isSourceOfProjectReferenceRedirect !== lastReportedFileNames.get(fileName)){
1485+
else if (includeProjectReferenceRedirectInfo && isSourceOfProjectReferenceRedirect !== lastReportedFileNames.get(fileName)) {
14861486
updatedRedirects.push({
14871487
fileName,
14881488
isSourceOfProjectReferenceRedirect
@@ -1555,9 +1555,9 @@ namespace ts.server {
15551555

15561556
// Search any globally-specified probe paths, then our peer node_modules
15571557
const searchPaths = [
1558-
...this.projectService.pluginProbeLocations,
1559-
// ../../.. to walk from X/node_modules/typescript/lib/tsserver.js to X/node_modules/
1560-
combinePaths(this.projectService.getExecutingFilePath(), "../../.."),
1558+
...this.projectService.pluginProbeLocations,
1559+
// ../../.. to walk from X/node_modules/typescript/lib/tsserver.js to X/node_modules/
1560+
combinePaths(this.projectService.getExecutingFilePath(), "../../.."),
15611561
];
15621562

15631563
if (this.projectService.globalPlugins) {
@@ -1577,7 +1577,7 @@ namespace ts.server {
15771577
}
15781578
}
15791579

1580-
protected enablePlugin(pluginConfigEntry: PluginImport, searchPaths: string[], pluginConfigOverrides: Map<any> | undefined) {
1580+
protected async enablePlugin(pluginConfigEntry: PluginImport, searchPaths: string[], pluginConfigOverrides: Map<any> | undefined) {
15811581
this.projectService.logger.info(`Enabling plugin ${pluginConfigEntry.name} from candidate paths: ${searchPaths.join(",")}`);
15821582
if (!pluginConfigEntry.name || parsePackageName(pluginConfigEntry.name).rest) {
15831583
this.projectService.logger.info(`Skipped loading plugin ${pluginConfigEntry.name || JSON.stringify(pluginConfigEntry)} because only package name is allowed plugin name`);
@@ -1589,8 +1589,27 @@ namespace ts.server {
15891589
const logError = (message: string) => {
15901590
(errorLogs || (errorLogs = [])).push(message);
15911591
};
1592-
const resolvedModule = firstDefined(searchPaths, searchPath =>
1593-
Project.resolveModule(pluginConfigEntry.name, searchPath, this.projectService.host, log, logError) as PluginModuleFactory | undefined);
1592+
1593+
let resolvedModule: any | undefined;
1594+
if (this.projectService.host.fetchServicePlugin) {
1595+
for (const searchPath of searchPaths) {
1596+
try {
1597+
resolvedModule = await this.projectService.host.fetchServicePlugin(searchPath, pluginConfigEntry.name);
1598+
}
1599+
catch (e) {
1600+
// TODO: log this?
1601+
continue;
1602+
}
1603+
if (resolvedModule) {
1604+
break;
1605+
}
1606+
}
1607+
}
1608+
else {
1609+
resolvedModule = firstDefined(searchPaths, searchPath =>
1610+
Project.resolveModule(pluginConfigEntry.name, searchPath, this.projectService.host, log, logError) as PluginModuleFactory | undefined);
1611+
}
1612+
15941613
if (resolvedModule) {
15951614
const configurationOverride = pluginConfigOverrides && pluginConfigOverrides.get(pluginConfigEntry.name);
15961615
if (configurationOverride) {

src/server/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ declare namespace ts.server {
1616
gc?(): void;
1717
trace?(s: string): void;
1818
require?(initialPath: string, moduleName: string): RequireResult;
19+
fetchServicePlugin?(root: string, moduleName: string): Promise<any>;
1920
}
2021
}

src/webServer/webServer.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,22 @@ namespace ts.server {
166166

167167
return ({ module: undefined, error: new Error("Could not resolve module") });
168168
},
169+
fetchServicePlugin: async (root: string, moduleName: string) => {
170+
const packageRoot = combinePaths(root, "node_modules", moduleName);
171+
172+
const packageJsonResponse = await fetch(combinePaths(packageRoot, "package.json"));
173+
const packageJson = await packageJsonResponse.json();
174+
const browser = packageJson.browser;
175+
if (!browser) {
176+
throw new Error("Could not load plugin. No 'browser' field found in package.json.");
177+
}
178+
179+
const scriptPath = combinePaths(packageRoot, browser);
180+
181+
// TODO: TS rewrites `import(...)` to `require`. Use eval to bypass this
182+
// eslint-disable-next-line no-eval
183+
return eval(`import(${JSON.stringify(scriptPath)})`);
184+
},
169185
exit: notImplemented,
170186

171187
// Debugging related

0 commit comments

Comments
 (0)