diff --git a/resources/serverless/code-web.js b/resources/serverless/code-web.js index be47d30ec4b..7c334d442a3 100644 --- a/resources/serverless/code-web.js +++ b/resources/serverless/code-web.js @@ -154,8 +154,6 @@ async function getExtensionPackageJSON(extensionPath) { } if (packageJSON.browser) { - packageJSON.main = packageJSON.browser; - let mainFilePath = path.join(extensionPath, packageJSON.browser); if (path.extname(mainFilePath) !== '.js') { mainFilePath += '.js'; diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index eaf57da1a75..c7240616746 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -193,8 +193,6 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme } } - protected abstract _beforeAlmostReadyToRunExtensions(): Promise; - public async deactivateAll(): Promise { let allPromises: Promise[] = []; try { @@ -254,7 +252,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme if (!this._extensionPathIndex) { const tree = TernarySearchTree.forPaths(); const extensions = this._registry.getAllExtensionDescriptions().map(ext => { - if (!ext.main) { + if (!this._getEntryPoint(ext)) { return undefined; } return this._hostUtils.realpath(ext.extensionLocation.fsPath).then(value => tree.set(URI.file(value).fsPath, ext)); @@ -345,7 +343,8 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme const event = getTelemetryActivationEvent(extensionDescription, reason); type ActivatePluginClassification = {} & TelemetryActivationEventFragment; this._mainThreadTelemetryProxy.$publicLog2('activatePlugin', event); - if (!extensionDescription.main) { + const entryPoint = this._getEntryPoint(extensionDescription); + if (!entryPoint) { // Treat the extension as being empty => NOT AN ERROR CASE return Promise.resolve(new EmptyExtension(ExtensionActivationTimes.NONE)); } @@ -355,15 +354,13 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup); return Promise.all([ - this._loadCommonJSModule(joinPath(extensionDescription.extensionLocation, extensionDescription.main), activationTimesBuilder), + this._loadCommonJSModule(joinPath(extensionDescription.extensionLocation, entryPoint), activationTimesBuilder), this._loadExtensionContext(extensionDescription) ]).then(values => { return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, values[0], values[1], activationTimesBuilder); }); } - protected abstract _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise; - private _loadExtensionContext(extensionDescription: IExtensionDescription): Promise { const globalState = new ExtensionMemento(extensionDescription.identifier.value, true, this._storage); @@ -747,6 +744,9 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme this._onDidChangeRemoteConnectionData.fire(); } + protected abstract _beforeAlmostReadyToRunExtensions(): Promise; + protected abstract _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined; + protected abstract _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise; public abstract async $setRemoteEnvironment(env: { [key: string]: string | null }): Promise; } diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 3a02c5ce0b7..8558835c744 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -13,6 +13,7 @@ import { ExtHostDownloadService } from 'vs/workbench/api/node/extHostDownloadSer import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; class NodeModuleRequireInterceptor extends RequireInterceptor { @@ -76,6 +77,10 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { }; } + protected _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined { + return extensionDescription.main; + } + protected _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { if (module.scheme !== Schemas.file) { throw new Error(`Cannot load URI: '${module}', must be of file-scheme`); diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts index 020f78b7b7f..c71ab1c7da4 100644 --- a/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts @@ -8,6 +8,7 @@ import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHost import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { URI } from 'vs/base/common/uri'; import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; class WorkerRequireInterceptor extends RequireInterceptor { @@ -40,6 +41,10 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { await this._fakeModules.install(); } + protected _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined { + return extensionDescription.browser; + } + protected async _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { module = module.with({ path: ensureSuffix(module.path, '.js') }); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts index e0542111088..1c780f7fb4f 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts @@ -157,7 +157,7 @@ export class RuntimeExtensionsEditor extends BaseEditor { this._extensionService.getExtensions().then((extensions) => { // We only deal with extensions with source code! this._extensionsDescriptions = extensions.filter((extension) => { - return !!extension.main; + return Boolean(extension.main) || Boolean(extension.browser); }); this._updateExtensions(); }); diff --git a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts index f856f4e05aa..26599aef2be 100644 --- a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts +++ b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts @@ -64,7 +64,7 @@ class DefaultFormatter extends Disposable implements IWorkbenchContribution { DefaultFormatter.extensionDescriptions.push(nls.localize('nullFormatterDescription', "None")); for (const extension of extensions) { - if (extension.main) { + if (extension.main || extension.browser) { DefaultFormatter.extensionIds.push(extension.identifier.value); DefaultFormatter.extensionDescriptions.push(extension.description || ''); } diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts index 5a8bb9b6577..4b6c5dff01a 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts @@ -204,8 +204,8 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { const [telemetryInfo, remoteInitData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]); // Collect all identifiers for extension ids which can be considered "resolved" - const resolvedExtensions = remoteInitData.allExtensions.filter(extension => !extension.main).map(extension => extension.identifier); - const hostExtensions = remoteInitData.allExtensions.filter(extension => extension.main && extension.api === 'none').map(extension => extension.identifier); + const resolvedExtensions = remoteInitData.allExtensions.filter(extension => !extension.main && !extension.browser).map(extension => extension.identifier); + const hostExtensions = remoteInitData.allExtensions.filter(extension => (extension.main || extension.browser) && extension.api === 'none').map(extension => extension.identifier); const workspace = this._contextService.getWorkspace(); return { commit: this._productService.commit, diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 5e30ddba98e..58f61544564 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -706,10 +706,6 @@ function determineRunningLocation(productService: IProductService, configuration } if (extensionKind === 'web' && isInstalledLocally && hasLocalWebWorker) { // web worker extensions run in the local web worker if possible - if (typeof extension.browser !== 'undefined') { - // The "browser" field determines the entry point - (extension).main = extension.browser; - } return ExtensionRunningLocation.LocalWebWorker; } } diff --git a/src/vs/workbench/services/extensions/node/extensionPoints.ts b/src/vs/workbench/services/extensions/node/extensionPoints.ts index ab1480d249b..23795239346 100644 --- a/src/vs/workbench/services/extensions/node/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/node/extensionPoints.ts @@ -389,9 +389,8 @@ class ExtensionManifestValidator extends ExtensionManifestHandler { notices.push(nls.localize('extensionDescription.main1', "property `{0}` can be omitted or must be of type `string`", 'main')); return false; } else { - let normalizedAbsolutePath = path.join(extensionFolderPath, extensionDescription.main); - - if (normalizedAbsolutePath.indexOf(extensionFolderPath)) { + const normalizedAbsolutePath = path.join(extensionFolderPath, extensionDescription.main); + if (!normalizedAbsolutePath.startsWith(extensionFolderPath)) { notices.push(nls.localize('extensionDescription.main2', "Expected `main` ({0}) to be included inside extension's folder ({1}). This might make the extension non-portable.", normalizedAbsolutePath, extensionFolderPath)); // not a failure case } @@ -401,6 +400,22 @@ class ExtensionManifestValidator extends ExtensionManifestHandler { return false; } } + if (typeof extensionDescription.browser !== 'undefined') { + if (typeof extensionDescription.browser !== 'string') { + notices.push(nls.localize('extensionDescription.browser1', "property `{0}` can be omitted or must be of type `string`", 'browser')); + return false; + } else { + const normalizedAbsolutePath = path.join(extensionFolderPath, extensionDescription.browser); + if (!normalizedAbsolutePath.startsWith(extensionFolderPath)) { + notices.push(nls.localize('extensionDescription.browser2', "Expected `browser` ({0}) to be included inside extension's folder ({1}). This might make the extension non-portable.", normalizedAbsolutePath, extensionFolderPath)); + // not a failure case + } + } + if (typeof extensionDescription.activationEvents === 'undefined') { + notices.push(nls.localize('extensionDescription.browser3', "properties `{0}` and `{1}` must both be specified or must both be omitted", 'activationEvents', 'browser')); + return false; + } + } return true; }