From f46738bc477ad71db379c8efa09c8ea22110cefc Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 9 Nov 2022 09:39:20 +0100 Subject: [PATCH] Extract usage of `require` to separate function which can be tree-shaken by the monaco editor build and thus ignored by webpack --- src/typings/require.d.ts | 4 +-- src/vs/base/browser/dom.ts | 2 +- src/vs/base/browser/markdownRenderer.ts | 2 +- src/vs/base/common/amd.ts | 5 +++- src/vs/base/common/network.ts | 28 +++++++++++++------ src/vs/base/test/common/network.test.ts | 18 ++++++------ .../browser/extensionResourceLoaderService.ts | 2 +- .../electron-main/protocolMainService.ts | 2 +- .../api/browser/mainThreadExtensionService.ts | 2 +- .../api/worker/extensionHostWorker.ts | 2 +- src/vs/workbench/browser/dnd.ts | 2 +- .../browser/extensionsWorkbenchService.ts | 2 +- .../contrib/files/browser/fileImportExport.ts | 2 +- .../performance/browser/perfviewEditor.ts | 8 ++++-- .../browser/gettingStartedService.ts | 8 +++--- src/vs/workbench/electron-sandbox/window.ts | 2 +- .../textMate/browser/textMateWorker.ts | 27 +++++++++++------- 17 files changed, 71 insertions(+), 47 deletions(-) diff --git a/src/typings/require.d.ts b/src/typings/require.d.ts index 5b0fcf921f7..671692c88da 100644 --- a/src/typings/require.d.ts +++ b/src/typings/require.d.ts @@ -49,8 +49,8 @@ interface NodeRequire { config(data: any): any; onError: Function; __$__nodeRequire(moduleName: string): T; - getStats(): ReadonlyArray; - hasDependencyCycle(): boolean; + getStats?(): ReadonlyArray; + hasDependencyCycle?(): boolean; define(amdModuleId: string, dependencies: string[], callback: (...args: any[]) => any): any; } diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 1abef9c8d49..6f690ebf36f 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -1199,7 +1199,7 @@ export function asCSSUrl(uri: URI | null | undefined): string { if (!uri) { return `url('')`; } - return `url('${FileAccess.asBrowserUri(uri).toString(true).replace(/'/g, '%27')}')`; + return `url('${FileAccess.uriToBrowserUri(uri).toString(true).replace(/'/g, '%27')}')`; } export function asCSSPropertyValue(value: string) { diff --git a/src/vs/base/browser/markdownRenderer.ts b/src/vs/base/browser/markdownRenderer.ts index e4b9dcf4ecd..aadf5d2c87a 100644 --- a/src/vs/base/browser/markdownRenderer.ts +++ b/src/vs/base/browser/markdownRenderer.ts @@ -126,7 +126,7 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende // and because of that special rewriting needs to be done // so that the URI uses a protocol that's understood by // browsers (like http or https) - return FileAccess.asBrowserUri(uri).toString(true); + return FileAccess.uriToBrowserUri(uri).toString(true); } if (!uri) { return href; diff --git a/src/vs/base/common/amd.ts b/src/vs/base/common/amd.ts index 7f788bf4629..fdbdb2e1030 100644 --- a/src/vs/base/common/amd.ts +++ b/src/vs/base/common/amd.ts @@ -40,7 +40,10 @@ export abstract class LoaderStats { map.set(stat.detail, duration + stat.timestamp); } - const stats = require.getStats().slice(0).sort((a, b) => a.timestamp - b.timestamp); + let stats: readonly LoaderEvent[] = []; + if (typeof require.getStats === 'function') { + stats = require.getStats().slice(0).sort((a, b) => a.timestamp - b.timestamp); + } for (const stat of stats) { switch (stat.type) { diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index 05550b9409f..3c706e3d277 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -196,11 +196,18 @@ class FileAccessImpl { * * **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context. */ - asBrowserUri(uri: URI): URI; - asBrowserUri(moduleId: AppResourcePath | ''): URI; - asBrowserUri(uriOrModule: URI | AppResourcePath | ''): URI { - const uri = this.toUri(uriOrModule, require); + asBrowserUri(resourcePath: AppResourcePath | ''): URI { + const uri = this.toUri(resourcePath, require); + return this.uriToBrowserUri(uri); + } + /** + * Returns a URI to use in contexts where the browser is responsible + * for loading (e.g. fetch()) or when used within the DOM. + * + * **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context. + */ + uriToBrowserUri(uri: URI): URI { // Handle remote URIs via `RemoteAuthorities` if (uri.scheme === Schemas.vscodeRemote) { return RemoteAuthorities.rewrite(uri); @@ -236,11 +243,16 @@ class FileAccessImpl { * Returns the `file` URI to use in contexts where node.js * is responsible for loading. */ - asFileUri(uri: URI): URI; - asFileUri(moduleId: AppResourcePath | ''): URI; - asFileUri(uriOrModule: URI | AppResourcePath | ''): URI { - const uri = this.toUri(uriOrModule, require); + asFileUri(resourcePath: AppResourcePath | ''): URI { + const uri = this.toUri(resourcePath, require); + return this.uriToFileUri(uri); + } + /** + * Returns the `file` URI to use in contexts where node.js + * is responsible for loading. + */ + uriToFileUri(uri: URI): URI { // Only convert the URI if it is `vscode-file:` scheme if (uri.scheme === Schemas.vscodeFileResource) { return uri.with({ diff --git a/src/vs/base/test/common/network.test.ts b/src/vs/base/test/common/network.test.ts index a59fec07594..9c6938967d9 100644 --- a/src/vs/base/test/common/network.test.ts +++ b/src/vs/base/test/common/network.test.ts @@ -15,17 +15,17 @@ suite('network', () => { // asCodeUri() & asFileUri(): simple, without authority let originalFileUri = URI.file('network.test.ts'); - let browserUri = FileAccess.asBrowserUri(originalFileUri); + let browserUri = FileAccess.uriToBrowserUri(originalFileUri); assert.ok(browserUri.authority.length > 0); - let fileUri = FileAccess.asFileUri(browserUri); + let fileUri = FileAccess.uriToFileUri(browserUri); assert.strictEqual(fileUri.authority.length, 0); assert(isEqual(originalFileUri, fileUri)); // asCodeUri() & asFileUri(): with authority originalFileUri = URI.file('network.test.ts').with({ authority: 'test-authority' }); - browserUri = FileAccess.asBrowserUri(originalFileUri); + browserUri = FileAccess.uriToBrowserUri(originalFileUri); assert.strictEqual(browserUri.authority, originalFileUri.authority); - fileUri = FileAccess.asFileUri(browserUri); + fileUri = FileAccess.uriToFileUri(browserUri); assert(isEqual(originalFileUri, fileUri)); }); @@ -39,31 +39,31 @@ suite('network', () => { (isWeb ? test.skip : test)('FileAccess: query and fragment is dropped (native)', () => { const originalFileUri = URI.file('network.test.ts').with({ query: 'foo=bar', fragment: 'something' }); - const browserUri = FileAccess.asBrowserUri(originalFileUri); + const browserUri = FileAccess.uriToBrowserUri(originalFileUri); assert.strictEqual(browserUri.query, ''); assert.strictEqual(browserUri.fragment, ''); }); (isWeb ? test.skip : test)('FileAccess: query and fragment is kept if URI is already of same scheme (native)', () => { const originalFileUri = URI.file('network.test.ts').with({ query: 'foo=bar', fragment: 'something' }); - const browserUri = FileAccess.asBrowserUri(originalFileUri.with({ scheme: Schemas.vscodeFileResource })); + const browserUri = FileAccess.uriToBrowserUri(originalFileUri.with({ scheme: Schemas.vscodeFileResource })); assert.strictEqual(browserUri.query, 'foo=bar'); assert.strictEqual(browserUri.fragment, 'something'); - const fileUri = FileAccess.asFileUri(originalFileUri); + const fileUri = FileAccess.uriToFileUri(originalFileUri); assert.strictEqual(fileUri.query, 'foo=bar'); assert.strictEqual(fileUri.fragment, 'something'); }); (isWeb ? test.skip : test)('FileAccess: web', () => { const originalHttpsUri = URI.file('network.test.ts').with({ scheme: 'https' }); - const browserUri = FileAccess.asBrowserUri(originalHttpsUri); + const browserUri = FileAccess.uriToBrowserUri(originalHttpsUri); assert.strictEqual(originalHttpsUri.toString(), browserUri.toString()); }); test('FileAccess: remote URIs', () => { const originalRemoteUri = URI.file('network.test.ts').with({ scheme: Schemas.vscodeRemote }); - const browserUri = FileAccess.asBrowserUri(originalRemoteUri); + const browserUri = FileAccess.uriToBrowserUri(originalRemoteUri); assert.notStrictEqual(originalRemoteUri.scheme, browserUri.scheme); }); }); diff --git a/src/vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService.ts b/src/vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService.ts index e2bc58ae980..c766318f30f 100644 --- a/src/vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService.ts +++ b/src/vs/platform/extensionResourceLoader/browser/extensionResourceLoaderService.ts @@ -30,7 +30,7 @@ class ExtensionResourceLoaderService extends AbstractExtensionResourceLoaderServ } async readExtensionResource(uri: URI): Promise { - uri = FileAccess.asBrowserUri(uri); + uri = FileAccess.uriToBrowserUri(uri); if (uri.scheme !== Schemas.http && uri.scheme !== Schemas.https) { const result = await this._fileService.readFile(uri); diff --git a/src/vs/platform/protocol/electron-main/protocolMainService.ts b/src/vs/platform/protocol/electron-main/protocolMainService.ts index b66fd1c1c0f..79d431b275c 100644 --- a/src/vs/platform/protocol/electron-main/protocolMainService.ts +++ b/src/vs/platform/protocol/electron-main/protocolMainService.ts @@ -127,7 +127,7 @@ export class ProtocolMainService extends Disposable implements IProtocolMainServ // 2.) Use `FileAccess.asFileUri` to convert back from a // `vscode-file:` URI to a `file:` URI. - const unnormalizedFileUri = FileAccess.asFileUri(requestUri); + const unnormalizedFileUri = FileAccess.uriToFileUri(requestUri); // 3.) Strip anything from the URI that could result in // relative paths (such as "..") by using `normalize` diff --git a/src/vs/workbench/api/browser/mainThreadExtensionService.ts b/src/vs/workbench/api/browser/mainThreadExtensionService.ts index 85891b4bd7f..f0b222d8b6a 100644 --- a/src/vs/workbench/api/browser/mainThreadExtensionService.ts +++ b/src/vs/workbench/api/browser/mainThreadExtensionService.ts @@ -189,7 +189,7 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha } async $asBrowserUri(uri: UriComponents): Promise { - return FileAccess.asBrowserUri(URI.revive(uri)); + return FileAccess.uriToBrowserUri(URI.revive(uri)); } } diff --git a/src/vs/workbench/api/worker/extensionHostWorker.ts b/src/vs/workbench/api/worker/extensionHostWorker.ts index 872f077cbb1..998b53a64ce 100644 --- a/src/vs/workbench/api/worker/extensionHostWorker.ts +++ b/src/vs/workbench/api/worker/extensionHostWorker.ts @@ -95,7 +95,7 @@ if ((self).Worker) { const _Worker = (self).Worker; Worker = function (stringUrl: string | URL, options?: WorkerOptions) { if (/^file:/i.test(stringUrl.toString())) { - stringUrl = FileAccess.asBrowserUri(URI.parse(stringUrl.toString())).toString(true); + stringUrl = FileAccess.uriToBrowserUri(URI.parse(stringUrl.toString())).toString(true); } else if (/^vscode-remote:/i.test(stringUrl.toString())) { // Supporting transformation of vscode-remote URIs requires an async call to the main thread, // but we cannot do this call from within the embedded Worker, and the only way out would be diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index 1a73aa0b4c5..d2ce96a0e92 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -237,7 +237,7 @@ export function fillEditorsDragData(accessor: ServicesAccessor, resourcesOrEdito // - only file:/ resources are supported const firstFile = fileSystemResources.find(({ isDirectory }) => !isDirectory); if (firstFile) { - const firstFileUri = FileAccess.asFileUri(firstFile.resource); // enforce `file:` URIs + const firstFileUri = FileAccess.uriToFileUri(firstFile.resource); // enforce `file:` URIs if (firstFileUri.scheme === Schemas.file) { event.dataTransfer.setData(DataTransfers.DOWNLOAD_URL, [Mimes.binary, basename(firstFile.resource), firstFileUri.toString()].join(':')); } diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index b22acd0909a..6a7d8cbd13f 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -174,7 +174,7 @@ export class Extension implements IExtension { private get localIconUrl(): string | null { if (this.local && this.local.manifest.icon) { - return FileAccess.asBrowserUri(resources.joinPath(this.local.location, this.local.manifest.icon)).toString(true); + return FileAccess.uriToBrowserUri(resources.joinPath(this.local.location, this.local.manifest.icon)).toString(true); } return null; } diff --git a/src/vs/workbench/contrib/files/browser/fileImportExport.ts b/src/vs/workbench/contrib/files/browser/fileImportExport.ts index bb2297d08c7..fe66a30e5a5 100644 --- a/src/vs/workbench/contrib/files/browser/fileImportExport.ts +++ b/src/vs/workbench/contrib/files/browser/fileImportExport.ts @@ -672,7 +672,7 @@ export class FileDownload { try { bufferOrUri = (await this.fileService.readFile(stat.resource, { limits: { size: maxBlobDownloadSize } }, cts.token)).value.buffer; } catch (error) { - bufferOrUri = FileAccess.asBrowserUri(stat.resource); + bufferOrUri = FileAccess.uriToBrowserUri(stat.resource); } if (!cts.token.isCancellationRequested) { diff --git a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts index 3d1ddf27618..1f9d20449ef 100644 --- a/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts +++ b/src/vs/workbench/contrib/performance/browser/perfviewEditor.ts @@ -256,9 +256,11 @@ class PerfModelContentProvider implements ITextModelContentProvider { map.set(LoaderEventType.CachedDataFound, []); map.set(LoaderEventType.CachedDataMissed, []); map.set(LoaderEventType.CachedDataRejected, []); - for (const stat of require.getStats()) { - if (map.has(stat.type)) { - map.get(stat.type)!.push(stat.detail); + if (typeof require.getStats === 'function') { + for (const stat of require.getStats()) { + if (map.has(stat.type)) { + map.get(stat.type)!.push(stat.detail); + } } } diff --git a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts index 405ed0b4bd0..c186be0ba4d 100644 --- a/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts +++ b/src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStartedService.ts @@ -281,12 +281,12 @@ export class WalkthroughsService extends Disposable implements IWalkthroughsServ private async registerExtensionWalkthroughContributions(extension: IExtensionDescription) { const convertExtensionPathToFileURI = (path: string) => path.startsWith('https://') ? URI.parse(path, true) - : FileAccess.asFileUri(joinPath(extension.extensionLocation, path)); + : FileAccess.uriToFileUri(joinPath(extension.extensionLocation, path)); const convertExtensionRelativePathsToBrowserURIs = (path: string | { hc: string; hcLight?: string; dark: string; light: string }): { hcDark: URI; hcLight: URI; dark: URI; light: URI } => { const convertPath = (path: string) => path.startsWith('https://') ? URI.parse(path, true) - : FileAccess.asBrowserUri(joinPath(extension.extensionLocation, path)); + : FileAccess.uriToBrowserUri(joinPath(extension.extensionLocation, path)); if (typeof path === 'string') { const converted = convertPath(path); @@ -353,7 +353,7 @@ export class WalkthroughsService extends Disposable implements IWalkthroughsServ type: 'markdown', path: convertExtensionPathToFileURI(step.media.markdown), base: convertExtensionPathToFileURI(dirname(step.media.markdown)), - root: FileAccess.asFileUri(extension.extensionLocation), + root: FileAccess.uriToFileUri(extension.extensionLocation), }; } else if (step.media.svg) { @@ -401,7 +401,7 @@ export class WalkthroughsService extends Disposable implements IWalkthroughsServ icon: { type: 'image', path: iconStr - ? FileAccess.asBrowserUri(joinPath(extension.extensionLocation, iconStr)).toString(true) + ? FileAccess.uriToBrowserUri(joinPath(extension.extensionLocation, iconStr)).toString(true) : DefaultIconPath }, when: ContextKeyExpr.deserialize(override ?? walkthrough.when) ?? ContextKeyExpr.true(), diff --git a/src/vs/workbench/electron-sandbox/window.ts b/src/vs/workbench/electron-sandbox/window.ts index 46307d1d7a4..3aeaa8383f6 100644 --- a/src/vs/workbench/electron-sandbox/window.ts +++ b/src/vs/workbench/electron-sandbox/window.ts @@ -640,7 +640,7 @@ export class NativeWindow extends Disposable { private async handleWarnings(): Promise { // Check for cyclic dependencies - if (require.hasDependencyCycle()) { + if (typeof require.hasDependencyCycle === 'function' && require.hasDependencyCycle()) { if (isCI) { this.logService.error('Error: There is a dependency cycle in the AMD modules that needs to be resolved!'); this.nativeHostService.exit(37); // running on a build machine, just exit without showing a dialog diff --git a/src/vs/workbench/services/textMate/browser/textMateWorker.ts b/src/vs/workbench/services/textMate/browser/textMateWorker.ts index 291cfc0f0a2..ff7f393d33a 100644 --- a/src/vs/workbench/services/textMate/browser/textMateWorker.ts +++ b/src/vs/workbench/services/textMate/browser/textMateWorker.ts @@ -15,9 +15,14 @@ import type { IRawTheme, IOnigLib } from 'vscode-textmate'; import { ContiguousMultilineTokensBuilder } from 'vs/editor/common/tokens/contiguousMultilineTokensBuilder'; import { countEOL } from 'vs/editor/common/core/eolCounter'; import { LineTokens } from 'vs/editor/common/tokens/lineTokens'; -import { FileAccess } from 'vs/base/common/network'; +import { AppResourcePath, FileAccess, nodeModulesAsarPath, nodeModulesPath } from 'vs/base/common/network'; import { TMTokenization } from 'vs/workbench/services/textMate/common/TMTokenization'; +const textmateModuleLocation: AppResourcePath = `${nodeModulesPath}/vscode-textmate`; +const textmateModuleLocationAsar: AppResourcePath = `${nodeModulesAsarPath}/vscode-textmate`; +const onigurumaModuleLocation: AppResourcePath = `${nodeModulesPath}/vscode-oniguruma`; +const onigurumaModuleLocationAsar: AppResourcePath = `${nodeModulesAsarPath}/vscode-oniguruma`; + export interface IValidGrammarDefinitionDTO { location: UriComponents; language?: string; @@ -153,15 +158,17 @@ export class TextMateWorker { } private async _loadTMGrammarFactory(grammarDefinitions: IValidGrammarDefinition[]): Promise { - require.config({ - paths: { - 'vscode-textmate': '../node_modules/vscode-textmate/release/main', - 'vscode-oniguruma': '../node_modules/vscode-oniguruma/release/main', - } - }); - const vscodeTextmate = await import('vscode-textmate'); - const vscodeOniguruma = await import('vscode-oniguruma'); - const response = await fetch(FileAccess.asBrowserUri('vscode-oniguruma/../onig.wasm').toString(true)); + // TODO: asar support + const useAsar = false; // this._environmentService.isBuilt && !isWeb + + const textmateLocation: AppResourcePath = useAsar ? textmateModuleLocation : textmateModuleLocationAsar; + const onigurumaLocation: AppResourcePath = useAsar ? onigurumaModuleLocation : onigurumaModuleLocationAsar; + const textmateMain: AppResourcePath = `${textmateLocation}/release/main.js`; + const onigurumaMain: AppResourcePath = `${onigurumaLocation}/release/main.js`; + const onigurumaWASM: AppResourcePath = `${onigurumaLocation}/release/onig.wasm`; + const vscodeTextmate = await import(FileAccess.asBrowserUri(textmateMain).toString(true)); + const vscodeOniguruma = await import(FileAccess.asBrowserUri(onigurumaMain).toString(true)); + const response = await fetch(FileAccess.asBrowserUri(onigurumaWASM).toString(true)); // Using the response directly only works if the server sets the MIME type 'application/wasm'. // Otherwise, a TypeError is thrown when using the streaming compiler. // We therefore use the non-streaming compiler :(.