Path: blob/main/src/vs/workbench/api/worker/extHostExtensionService.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { createApiFactoryAndRegisterActors } from '../common/extHost.api.impl.js';6import { ExtensionActivationTimesBuilder } from '../common/extHostExtensionActivator.js';7import { AbstractExtHostExtensionService } from '../common/extHostExtensionService.js';8import { URI } from '../../../base/common/uri.js';9import { RequireInterceptor } from '../common/extHostRequireInterceptor.js';10import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';11import { ExtensionRuntime } from '../common/extHostTypes.js';12import { timeout } from '../../../base/common/async.js';13import { ExtHostConsoleForwarder } from './extHostConsoleForwarder.js';14import { extname } from '../../../base/common/path.js';1516class WorkerRequireInterceptor extends RequireInterceptor {1718protected _installInterceptor() { }1920getModule(request: string, parent: URI): undefined | any {21for (const alternativeModuleName of this._alternatives) {22const alternative = alternativeModuleName(request);23if (alternative) {24request = alternative;25break;26}27}2829if (this._factories.has(request)) {30return this._factories.get(request)!.load(request, parent, () => { throw new Error('CANNOT LOAD MODULE from here.'); });31}32return undefined;33}34}3536export class ExtHostExtensionService extends AbstractExtHostExtensionService {37readonly extensionRuntime = ExtensionRuntime.Webworker;3839private _fakeModules?: WorkerRequireInterceptor;4041protected async _beforeAlmostReadyToRunExtensions(): Promise<void> {42// make sure console.log calls make it to the render43this._instaService.createInstance(ExtHostConsoleForwarder);4445// initialize API and register actors46const apiFactory = this._instaService.invokeFunction(createApiFactoryAndRegisterActors);47this._fakeModules = this._instaService.createInstance(WorkerRequireInterceptor, apiFactory, { mine: this._myRegistry, all: this._globalRegistry });48await this._fakeModules.install();49performance.mark('code/extHost/didInitAPI');5051await this._waitForDebuggerAttachment();52}5354protected _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined {55return extensionDescription.browser;56}5758protected async _loadCommonJSModule<T extends object | undefined>(extension: IExtensionDescription | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {59module = module.with({ path: ensureSuffix(module.path, '.js') });60const extensionId = extension?.identifier.value;61if (extensionId) {62performance.mark(`code/extHost/willFetchExtensionCode/${extensionId}`);63}6465// First resolve the extension entry point URI to something we can load using `fetch`66// This needs to be done on the main thread due to a potential `resourceUriProvider` (workbench api)67// which is only available in the main thread68const browserUri = URI.revive(await this._mainThreadExtensionsProxy.$asBrowserUri(module));69const response = await fetch(browserUri.toString(true));70if (extensionId) {71performance.mark(`code/extHost/didFetchExtensionCode/${extensionId}`);72}7374if (response.status !== 200) {75throw new Error(response.statusText);76}7778// fetch JS sources as text and create a new function around it79const source = await response.text();80// Here we append #vscode-extension to serve as a marker, such that source maps81// can be adjusted for the extra wrapping function.82const sourceURL = `${module.toString(true)}#vscode-extension`;83const fullSource = `${source}\n//# sourceURL=${sourceURL}`;84let initFn: Function;85try {86initFn = new Function('module', 'exports', 'require', fullSource); // CodeQL [SM01632] js/eval-call there is no alternative until we move to ESM87} catch (err) {88if (extensionId) {89console.error(`Loading code for extension ${extensionId} failed: ${err.message}`);90} else {91console.error(`Loading code failed: ${err.message}`);92}93console.error(`${module.toString(true)}${typeof err.line === 'number' ? ` line ${err.line}` : ''}${typeof err.column === 'number' ? ` column ${err.column}` : ''}`);94console.error(err);95throw err;96}9798if (extension) {99await this._extHostLocalizationService.initializeLocalizedMessages(extension);100}101102// define commonjs globals: `module`, `exports`, and `require`103const _exports = {};104const _module = { exports: _exports };105const _require = (request: string) => {106const result = this._fakeModules!.getModule(request, module);107if (result === undefined) {108throw new Error(`Cannot load module '${request}'`);109}110return result;111};112113try {114activationTimesBuilder.codeLoadingStart();115if (extensionId) {116performance.mark(`code/extHost/willLoadExtensionCode/${extensionId}`);117}118initFn(_module, _exports, _require);119return <T>(_module.exports !== _exports ? _module.exports : _exports);120} finally {121if (extensionId) {122performance.mark(`code/extHost/didLoadExtensionCode/${extensionId}`);123}124activationTimesBuilder.codeLoadingStop();125}126}127128protected override _loadESMModule<T>(extension: IExtensionDescription | null, module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {129throw new Error('ESM modules are not supported in the web worker extension host');130}131132async $setRemoteEnvironment(_env: { [key: string]: string | null }): Promise<void> {133return;134}135136private async _waitForDebuggerAttachment(waitTimeout = 5000) {137// debugger attaches async, waiting for it fixes #106698 and #99222138if (!this._initData.environment.isExtensionDevelopmentDebug) {139return;140}141142const deadline = Date.now() + waitTimeout;143while (Date.now() < deadline && !('__jsDebugIsReady' in globalThis)) {144await timeout(10);145}146}147}148149function ensureSuffix(path: string, suffix: string): string {150const extName = extname(path);151return extName ? path : path + suffix;152}153154155