Add support for web worker extensions to define their entry point via "browser"
This commit is contained in:
parent
98e653e82c
commit
a7b1e06283
9 changed files with 39 additions and 20 deletions
|
@ -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';
|
||||
|
|
|
@ -193,8 +193,6 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract _beforeAlmostReadyToRunExtensions(): Promise<void>;
|
||||
|
||||
public async deactivateAll(): Promise<void> {
|
||||
let allPromises: Promise<void>[] = [];
|
||||
try {
|
||||
|
@ -254,7 +252,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
|||
if (!this._extensionPathIndex) {
|
||||
const tree = TernarySearchTree.forPaths<IExtensionDescription>();
|
||||
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<TelemetryActivationEvent, ActivatePluginClassification>('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<IExtensionModule>(joinPath(extensionDescription.extensionLocation, extensionDescription.main), activationTimesBuilder),
|
||||
this._loadCommonJSModule<IExtensionModule>(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<T>(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T>;
|
||||
|
||||
private _loadExtensionContext(extensionDescription: IExtensionDescription): Promise<vscode.ExtensionContext> {
|
||||
|
||||
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<void>;
|
||||
protected abstract _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined;
|
||||
protected abstract _loadCommonJSModule<T>(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T>;
|
||||
public abstract async $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<T>(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
|
||||
if (module.scheme !== Schemas.file) {
|
||||
throw new Error(`Cannot load URI: '${module}', must be of file-scheme`);
|
||||
|
|
|
@ -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<T>(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
|
||||
|
||||
module = module.with({ path: ensureSuffix(module.path, '.js') });
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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 || '');
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
(<any>extension).main = extension.browser;
|
||||
}
|
||||
return ExtensionRunningLocation.LocalWebWorker;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue