diff --git a/README.md b/README.md index 8e9e8351c..8ff6f88a6 100644 --- a/README.md +++ b/README.md @@ -174,14 +174,14 @@ Our changes include: - Allow multiple extension directories (both user and built-in). - Modify the loader, websocket, webview, service worker, and asset requests to use the URL of the page as a base (and TLS if necessary for the websocket). -- Send client-side telemetry through the server and get the initial log level - from the server. -- Add an upload service for use in editor windows and the explorer along with a - file prefix to ignore for temporary files created during upload. +- Send client-side telemetry through the server. +- Add an upload service along with a file prefix to ignore for temporary files + created during upload. - Make changing the display language work. -- Make hiding or toggling the menu bar possible. - Make it possible for us to load code on the client. -- Modify the build process to include our code. +- Make extensions work in the browser. +- Fix getting permanently disconnected when you sleep or hibernate for a while. +- Make it possible to automatically update the binary. ## License diff --git a/scripts/vscode.patch b/scripts/vscode.patch index be9646249..cef5f25fa 100644 --- a/scripts/vscode.patch +++ b/scripts/vscode.patch @@ -510,62 +510,27 @@ index 49a8e254fd..99d233aed5 100644 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 afd82468c0..67d938e9ab 100644 +index afd82468c0..289145be54 100644 --- a/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts -@@ -9,6 +9,10 @@ import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHost +@@ -9,6 +9,9 @@ import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHost import { endsWith } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor'; +import { joinPath } from 'vs/base/common/resources'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -+import { fromTar } from 'vs/server/node_modules/@coder/requirefs/out/requirefs'; -+import { Client } from 'vs/server/node_modules/@coder/node-browser/out/client/client'; ++import { loadCommonJSModule } from 'vs/server/src/browser/worker'; class WorkerRequireInterceptor extends RequireInterceptor { -@@ -41,7 +45,48 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { +@@ -41,7 +44,14 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { await this._fakeModules.install(); } - protected async _loadCommonJSModule(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + protected async _loadCommonJSModule(module: URI | IExtensionDescription, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise { + if (!URI.isUri(module) && module.extensionKind !== 'web') { -+ const fetchUri = URI.from({ -+ scheme: self.location.protocol.replace(':', ''), -+ authority: self.location.host, -+ path: `${self.location.pathname.replace(/\/static.*\/out\/vs\/workbench\/services\/extensions\/worker\/extensionHostWorkerMain.js$/, '')}/tar`, -+ query: `path=${encodeURIComponent(module.extensionLocation.path)}`, -+ }); -+ const response = await fetch(fetchUri.toString(true)); -+ if (response.status !== 200) { -+ throw new Error(`Failed to download extension '${module.extensionLocation.path}'`); -+ } -+ const client = new Client(this._nodeProxy, { logger: this._logService }); -+ const init = await client.handshake(); -+ const buffer = new Uint8Array(await response.arrayBuffer()); -+ const rfs = fromTar(buffer); -+ (self).global = self; -+ rfs.provide('vscode', this._fakeModules.getModule('vscode', module.extensionLocation)); -+ Object.keys(client.modules).forEach((key) => { -+ const mod = (client.modules as any)[key]; -+ if (key === 'process') { -+ (self).process = mod; -+ (self).process.env = init.env; -+ return; -+ } -+ -+ rfs.provide(key, mod); -+ switch (key) { -+ case 'buffer': -+ (self).Buffer = mod.Buffer; -+ break; -+ case 'timers': -+ (self).setImmediate = mod.setImmediate; -+ break; -+ } -+ }); -+ return rfs.require('.'); ++ return loadCommonJSModule(module, activationTimesBuilder, this._nodeProxy, this._logService, this._fakeModules.getModule('vscode', module.extensionLocation)); + } + + if (!URI.isUri(module)) { @@ -574,7 +539,7 @@ index afd82468c0..67d938e9ab 100644 module = module.with({ path: ensureSuffix(module.path, '.js') }); const response = await fetch(module.toString(true)); -@@ -57,7 +102,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { +@@ -57,7 +67,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { const _exports = {}; const _module = { exports: _exports }; const _require = (request: string) => { diff --git a/src/browser/worker.ts b/src/browser/worker.ts new file mode 100644 index 000000000..ed7ea6c96 --- /dev/null +++ b/src/browser/worker.ts @@ -0,0 +1,57 @@ +import { URI } from "vs/base/common/uri"; +import { IExtensionDescription } from "vs/platform/extensions/common/extensions"; +import { ILogService } from "vs/platform/log/common/log"; +import { Client } from "vs/server/node_modules/@coder/node-browser/out/client/client"; +import { fromTar } from "vs/server/node_modules/@coder/requirefs/out/requirefs"; +import { ExtensionActivationTimesBuilder } from "vs/workbench/api/common/extHostExtensionActivator"; +import { IExtHostNodeProxy } from "./extHostNodeProxy"; + +export const loadCommonJSModule = async ( + module: IExtensionDescription, + activationTimesBuilder: ExtensionActivationTimesBuilder, + nodeProxy: IExtHostNodeProxy, + logService: ILogService, + vscode: any, +): Promise => { + const fetchUri = URI.from({ + scheme: self.location.protocol.replace(":", ""), + authority: self.location.host, + path: `${self.location.pathname.replace(/\/static.*\/out\/vs\/workbench\/services\/extensions\/worker\/extensionHostWorkerMain.js$/, "")}/tar`, + query: `path=${encodeURIComponent(module.extensionLocation.path)}`, + }); + const response = await fetch(fetchUri.toString(true)); + if (response.status !== 200) { + throw new Error(`Failed to download extension "${module.extensionLocation.path}"`); + } + const client = new Client(nodeProxy, { logger: logService }); + const init = await client.handshake(); + const buffer = new Uint8Array(await response.arrayBuffer()); + const rfs = fromTar(buffer); + (self).global = self; + rfs.provide("vscode", vscode); + Object.keys(client.modules).forEach((key) => { + const mod = (client.modules as any)[key]; + if (key === "process") { + (self).process = mod; + (self).process.env = init.env; + return; + } + + rfs.provide(key, mod); + switch (key) { + case "buffer": + (self).Buffer = mod.Buffer; + break; + case "timers": + (self).setImmediate = mod.setImmediate; + break; + } + }); + + try { + activationTimesBuilder.codeLoadingStart(); + return rfs.require("."); + } finally { + activationTimesBuilder.codeLoadingStop(); + } +};