Skip to content

Commit 5d22d7f

Browse files
committed
create API instance per extension
1 parent 0fb1f55 commit 5d22d7f

2 files changed

Lines changed: 69 additions & 26 deletions

File tree

src/vs/workbench/api/common/extHostExtensionService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
384384
try {
385385
activationTimesBuilder.activateCallStart();
386386
logService.trace(`ExtensionService#_callActivateOptional ${extensionId.value}`);
387-
const scope = typeof global === 'object' ? global : self; //todo@joh not so nice
387+
const scope = typeof global === 'object' ? global : self; // `global` is nodejs while `self` is for workers
388388
const activateResult: Promise<IExtensionAPI> = extensionModule.activate.apply(scope, [context]);
389389
activationTimesBuilder.activateCallStop();
390390

@@ -525,7 +525,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
525525
}
526526

527527
private async _doHandleExtensionTests(): Promise<void> {
528-
const { extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, extensionTestsLocationURI } = this._initData.environment;
528+
const { extensionDevelopmentLocationURI, extensionTestsLocationURI } = this._initData.environment;
529529
if (!(extensionDevelopmentLocationURI && extensionTestsLocationURI && extensionTestsLocationURI.scheme === Schemas.file)) {
530530
return Promise.resolve(undefined);
531531
}

src/vs/workbench/api/worker/extHostExtensionService.ts

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,96 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { createApiFactoryAndRegisterActors } from 'vs/workbench/api/common/extHost.api.impl';
6+
import { createApiFactoryAndRegisterActors, IExtensionApiFactory } from 'vs/workbench/api/common/extHost.api.impl';
77
import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHostExtensionActivator';
88
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
99
import { endsWith } from 'vs/base/common/strings';
10+
import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
11+
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
12+
import * as vscode from 'vscode';
13+
import { TernarySearchTree } from 'vs/base/common/map';
1014
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
15+
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
16+
17+
class ApiInstances {
18+
19+
private readonly _apiInstances = new Map<string, typeof vscode>();
20+
21+
constructor(
22+
private readonly _apiFactory: IExtensionApiFactory,
23+
private readonly _extensionPaths: TernarySearchTree<IExtensionDescription>,
24+
private readonly _extensionRegistry: ExtensionDescriptionRegistry,
25+
private readonly _configProvider: ExtHostConfigProvider,
26+
) {
27+
//
28+
}
29+
30+
get(modulePath: string): typeof vscode {
31+
const extension = this._extensionPaths.findSubstr(modulePath) || nullExtensionDescription;
32+
const id = ExtensionIdentifier.toKey(extension.identifier);
33+
34+
let apiInstance = this._apiInstances.get(id);
35+
if (!apiInstance) {
36+
apiInstance = this._apiFactory(extension, this._extensionRegistry, this._configProvider);
37+
this._apiInstances.set(id, apiInstance);
38+
}
39+
return apiInstance;
40+
}
41+
}
1142

1243
export class ExtHostExtensionService extends AbstractExtHostExtensionService {
1344

45+
private _apiInstances?: ApiInstances;
46+
1447
protected async _beforeAlmostReadyToRunExtensions(): Promise<void> {
1548
// initialize API and register actors
16-
const factory = this._instaService.invokeFunction(createApiFactoryAndRegisterActors);
17-
18-
// globally define the vscode module and share that for all extensions
19-
// todo@joh have an instance per extension, not a shared one....
20-
const sharedApiInstance = factory(nullExtensionDescription, this._registry, await this._extHostConfiguration.getConfigProvider());
21-
define('vscode', sharedApiInstance);
49+
const apiFactory = this._instaService.invokeFunction(createApiFactoryAndRegisterActors);
50+
const configProvider = await this._extHostConfiguration.getConfigProvider();
51+
const extensionPath = await this.getExtensionPathIndex();
52+
this._apiInstances = new ApiInstances(apiFactory, extensionPath, this._registry, configProvider);
2253
}
2354

2455
protected _loadCommonJSModule<T>(modulePath: string, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
25-
// fake commonjs world
56+
57+
// make sure modulePath ends with `.js`
58+
const suffix = '.js';
59+
modulePath = endsWith(modulePath, suffix) ? modulePath : modulePath + suffix;
60+
61+
interface FakeCommonJSSelf {
62+
module?: object;
63+
exports?: object;
64+
require?: (module: string) => any;
65+
window?: object;
66+
__dirname: never;
67+
__filename: never;
68+
}
69+
70+
// FAKE commonjs world that only collects exports
71+
const patchSelf: FakeCommonJSSelf = <any>self;
2672
const module = { exports: {} };
27-
//@ts-ignore
28-
self['module'] = module;
29-
//@ts-ignore
30-
self['exports'] = module.exports;
31-
// that's improper but might help extensions that aren't author correctly
32-
// @ts-ignore
33-
self['window'] = self;
73+
patchSelf.module = module;
74+
patchSelf.exports = module.exports;
75+
patchSelf.window = self; // <- that's improper but might help extensions that aren't authored correctly
76+
77+
// FAKE require function that only works for the vscode-module
78+
patchSelf.require = (module: string) => {
79+
if (module !== 'vscode') {
80+
throw new Error(`Cannot load module '${module}'`);
81+
}
82+
return this._apiInstances!.get(modulePath);
83+
};
3484

3585
try {
3686
activationTimesBuilder.codeLoadingStart();
37-
// import the single (!) script, make sure it's a JS-file
38-
const suffix = '.js';
39-
if (endsWith(modulePath, suffix)) {
40-
importScripts(modulePath);
41-
} else {
42-
importScripts(modulePath + suffix);
43-
}
87+
importScripts(modulePath);
4488
} finally {
4589
activationTimesBuilder.codeLoadingStop();
4690
}
4791

48-
// return what it exported
4992
return Promise.resolve(module.exports as T);
5093
}
5194

52-
public async $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
95+
async $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
5396
throw new Error('Not supported');
5497
}
5598
}

0 commit comments

Comments
 (0)