Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/worker/extHostExtensionService.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { createApiFactoryAndRegisterActors } from '../common/extHost.api.impl.js';
7
import { ExtensionActivationTimesBuilder } from '../common/extHostExtensionActivator.js';
8
import { AbstractExtHostExtensionService } from '../common/extHostExtensionService.js';
9
import { URI } from '../../../base/common/uri.js';
10
import { RequireInterceptor } from '../common/extHostRequireInterceptor.js';
11
import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
12
import { ExtensionRuntime } from '../common/extHostTypes.js';
13
import { timeout } from '../../../base/common/async.js';
14
import { ExtHostConsoleForwarder } from './extHostConsoleForwarder.js';
15
import { extname } from '../../../base/common/path.js';
16
17
class WorkerRequireInterceptor extends RequireInterceptor {
18
19
protected _installInterceptor() { }
20
21
getModule(request: string, parent: URI): undefined | any {
22
for (const alternativeModuleName of this._alternatives) {
23
const alternative = alternativeModuleName(request);
24
if (alternative) {
25
request = alternative;
26
break;
27
}
28
}
29
30
if (this._factories.has(request)) {
31
return this._factories.get(request)!.load(request, parent, () => { throw new Error('CANNOT LOAD MODULE from here.'); });
32
}
33
return undefined;
34
}
35
}
36
37
export class ExtHostExtensionService extends AbstractExtHostExtensionService {
38
readonly extensionRuntime = ExtensionRuntime.Webworker;
39
40
private _fakeModules?: WorkerRequireInterceptor;
41
42
protected async _beforeAlmostReadyToRunExtensions(): Promise<void> {
43
// make sure console.log calls make it to the render
44
this._instaService.createInstance(ExtHostConsoleForwarder);
45
46
// initialize API and register actors
47
const apiFactory = this._instaService.invokeFunction(createApiFactoryAndRegisterActors);
48
this._fakeModules = this._instaService.createInstance(WorkerRequireInterceptor, apiFactory, { mine: this._myRegistry, all: this._globalRegistry });
49
await this._fakeModules.install();
50
performance.mark('code/extHost/didInitAPI');
51
52
await this._waitForDebuggerAttachment();
53
}
54
55
protected _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined {
56
return extensionDescription.browser;
57
}
58
59
protected async _loadCommonJSModule<T extends object | undefined>(extension: IExtensionDescription | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
60
module = module.with({ path: ensureSuffix(module.path, '.js') });
61
const extensionId = extension?.identifier.value;
62
if (extensionId) {
63
performance.mark(`code/extHost/willFetchExtensionCode/${extensionId}`);
64
}
65
66
// First resolve the extension entry point URI to something we can load using `fetch`
67
// This needs to be done on the main thread due to a potential `resourceUriProvider` (workbench api)
68
// which is only available in the main thread
69
const browserUri = URI.revive(await this._mainThreadExtensionsProxy.$asBrowserUri(module));
70
const response = await fetch(browserUri.toString(true));
71
if (extensionId) {
72
performance.mark(`code/extHost/didFetchExtensionCode/${extensionId}`);
73
}
74
75
if (response.status !== 200) {
76
throw new Error(response.statusText);
77
}
78
79
// fetch JS sources as text and create a new function around it
80
const source = await response.text();
81
// Here we append #vscode-extension to serve as a marker, such that source maps
82
// can be adjusted for the extra wrapping function.
83
const sourceURL = `${module.toString(true)}#vscode-extension`;
84
const fullSource = `${source}\n//# sourceURL=${sourceURL}`;
85
let initFn: Function;
86
try {
87
initFn = new Function('module', 'exports', 'require', fullSource); // CodeQL [SM01632] js/eval-call there is no alternative until we move to ESM
88
} catch (err) {
89
if (extensionId) {
90
console.error(`Loading code for extension ${extensionId} failed: ${err.message}`);
91
} else {
92
console.error(`Loading code failed: ${err.message}`);
93
}
94
console.error(`${module.toString(true)}${typeof err.line === 'number' ? ` line ${err.line}` : ''}${typeof err.column === 'number' ? ` column ${err.column}` : ''}`);
95
console.error(err);
96
throw err;
97
}
98
99
if (extension) {
100
await this._extHostLocalizationService.initializeLocalizedMessages(extension);
101
}
102
103
// define commonjs globals: `module`, `exports`, and `require`
104
const _exports = {};
105
const _module = { exports: _exports };
106
const _require = (request: string) => {
107
const result = this._fakeModules!.getModule(request, module);
108
if (result === undefined) {
109
throw new Error(`Cannot load module '${request}'`);
110
}
111
return result;
112
};
113
114
try {
115
activationTimesBuilder.codeLoadingStart();
116
if (extensionId) {
117
performance.mark(`code/extHost/willLoadExtensionCode/${extensionId}`);
118
}
119
initFn(_module, _exports, _require);
120
return <T>(_module.exports !== _exports ? _module.exports : _exports);
121
} finally {
122
if (extensionId) {
123
performance.mark(`code/extHost/didLoadExtensionCode/${extensionId}`);
124
}
125
activationTimesBuilder.codeLoadingStop();
126
}
127
}
128
129
protected override _loadESMModule<T>(extension: IExtensionDescription | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
130
throw new Error('ESM modules are not supported in the web worker extension host');
131
}
132
133
async $setRemoteEnvironment(_env: { [key: string]: string | null }): Promise<void> {
134
return;
135
}
136
137
private async _waitForDebuggerAttachment(waitTimeout = 5000) {
138
// debugger attaches async, waiting for it fixes #106698 and #99222
139
if (!this._initData.environment.isExtensionDevelopmentDebug) {
140
return;
141
}
142
143
const deadline = Date.now() + waitTimeout;
144
while (Date.now() < deadline && !('__jsDebugIsReady' in globalThis)) {
145
await timeout(10);
146
}
147
}
148
}
149
150
function ensureSuffix(path: string, suffix: string): string {
151
const extName = extname(path);
152
return extName ? path : path + suffix;
153
}
154
155