提交 ea123f75 编写于 作者: J Johannes Rieken

web - make service worker optional

上级 bbb69b22
......@@ -1200,7 +1200,7 @@ export function asDomUri(uri: URI): URI {
if (Schemas.vscodeRemote === uri.scheme) {
// rewrite vscode-remote-uris to uris of the window location
// so that they can be intercepted by the service worker
return _location.with({ path: '/vscode-resources/fetch', query: `u=${JSON.stringify(uri)}` });
return _location.with({ path: '/vscode-remote', query: JSON.stringify(uri) });
}
return uri;
}
......@@ -4,8 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { getMediaMime } from 'vs/base/common/mime';
//https://stackoverflow.com/questions/56356655/structuring-a-typescript-project-with-workers/56374158#56374158
declare var self: ServiceWorkerGlobalScope;
......@@ -35,8 +33,8 @@ self.addEventListener('activate', event => {
//#region --- fetching/caching
const _cacheName = 'vscode-resources';
const _resourcePrefix = '/vscode-resources/fetch';
const _cacheName = 'vscode-extension-resources';
const _resourcePrefix = '/vscode-remote';
const _pendingFetch = new Map<string, Function>();
self.addEventListener('message', event => {
......@@ -71,38 +69,18 @@ async function respondWithDefault(event: FetchEvent): Promise<Response> {
}
async function respondWithResource(event: FetchEvent, uri: URI): Promise<Response> {
const cacheKey = event.request.url.replace('&r=1', '');
const cachedValue = await caches.open(_cacheName).then(cache => cache.match(cacheKey));
const cachedValue = await caches.open(_cacheName).then(cache => cache.match(event.request));
if (cachedValue) {
return cachedValue;
}
return new Promise<Response>(resolve => {
const token = generateUuid();
const [first] = uri.query.split('&');
const components = JSON.parse(first.substr(2));
_pendingFetch.set(token, async (data: ArrayBuffer, isExtensionResource: boolean) => {
const res = new Response(data, {
status: 200,
headers: { 'Content-Type': getMediaMime(components.path) || 'text/plain' }
});
if (isExtensionResource) {
// only cache extension resources but not other
// resources, esp not workspace resources
await caches.open(_cacheName).then(cache => cache.put(cacheKey, res.clone()));
}
return resolve(res);
});
const response: Response = await event.preloadResponse || await fetch(event.request);
if (response.headers.get('X-VSCode-Extension') === 'true') {
await caches.open(_cacheName).then(cache => cache.put(event.request, response.clone()));
}
self.clients.get(event.clientId).then(client => {
client.postMessage({ uri: components, token });
});
});
return response;
}
//#endregion
......@@ -3,145 +3,41 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IFileService } from 'vs/platform/files/common/files';
import { URI } from 'vs/base/common/uri';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContributionsRegistry, Extensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { isEqualOrParent } from 'vs/base/common/resources';
import { ILogService } from 'vs/platform/log/common/log';
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
// load and start service worker as soon as this file
// is being loaded and later, when services are ready,
// claim this service worker so that messages can be
// replied to
const _serviceWorker = new class ServiceWorkerStarter {
class ResourceServiceWorker {
private static _url = require.toUrl('./resourceServiceWorkerMain.js');
private _beforeReadyEvents: ExtendableMessageEvent[] = [];
private _messageHandler?: (event: ExtendableMessageEvent) => void;
private readonly _disposables = new DisposableStore();
constructor() {
navigator.serviceWorker.register(ServiceWorkerStarter._url, { scope: '/' }).then(reg => {
// console.debug('SW#reg', reg);
constructor(
@ILogService private readonly _logService: ILogService,
) {
navigator.serviceWorker.register(ResourceServiceWorker._url, { scope: '/' }).then(reg => {
this._logService.trace('SW#reg', reg);
return reg.update();
// }).then(() => {
// // console.debug('SW#updated', reg);
// return navigator.serviceWorker.ready;
}).then(() => {
console.info('SW#ready');
this._logService.info('SW#ready');
}).catch(err => {
console.error('SW#init', err);
this._logService.error('SW#init', err);
});
const handleMessage = (event: ExtendableMessageEvent) => {
if (!this._messageHandler) {
this._beforeReadyEvents.push(event);
console.debug('SW#buffered', event.data);
} else {
this._messageHandler(event);
}
};
navigator.serviceWorker.addEventListener('message', e => handleMessage(e as ExtendableMessageEvent));
const handler = (e: ExtendableMessageEvent) => this._handleMessage(e);
navigator.serviceWorker.addEventListener('message', handler);
this._disposables.add(toDisposable(() => navigator.serviceWorker.removeEventListener('message', handler)));
}
dispose(): void {
// when to dispose?
}
claim(handler: (event: ExtendableMessageEvent) => void): void {
this._messageHandler = handler;
this._beforeReadyEvents.forEach(this._messageHandler);
}
};
class ResourceServiceWorker {
constructor(
@IFileService private readonly _fileService: IFileService,
@IExtensionService private readonly _extensionService: IExtensionService,
@ILogService private readonly _logService: ILogService,
) {
this._updateEarlyResourceUris();
_serviceWorker.claim(e => this._handleMessage(e));
this._disposables.dispose();
}
private _handleMessage(event: ExtendableMessageEvent): void {
this._logService.trace('SW - fetch', event.data.uri);
const uri = URI.revive(event.data.uri);
Promise.all([
this._fileService.readFile(uri),
this._isExtensionResource(uri)
]).then(([file, isExtensionResource]) => {
if (!event.source) {
return;
}
event.source.postMessage({
token: event.data.token,
data: file.value.buffer.buffer,
isExtensionResource
}, [file.value.buffer.buffer]);
});
}
private async _isExtensionResource(uri: URI): Promise<boolean> {
for (const ext of await this._extensionService.getExtensions()) {
if (isEqualOrParent(uri, ext.extensionLocation)) {
return true;
}
}
return false;
}
private _updateEarlyResourceUris(): void {
let updateCount = 0;
// find style-tags
const styleElements = document.querySelectorAll('style');
for (let i = 0; i < styleElements.length; i++) {
const el = styleElements.item(i);
if (!el.sheet) {
continue;
}
const rules = (<CSSStyleSheet>el.sheet).rules;
for (let j = 0; j < rules.length; j++) {
const rule = rules[j];
const newCssText = this._updateResourceUris(rule.cssText);
if (newCssText) {
(<CSSStyleSheet>el.sheet).deleteRule(j);
(<CSSStyleSheet>el.sheet).insertRule(newCssText, j);
updateCount += 1;
}
}
}
// find any tag using remote uris
const htmlElements = document.querySelectorAll('[style*="/vscode-resources/fetch"]');
for (let i = 0; i < htmlElements.length; i++) {
const el = <HTMLElement>htmlElements.item(i);
const newCssText = this._updateResourceUris(el.style.cssText);
if (newCssText) {
el.style.cssText = newCssText;
updateCount += 1;
}
}
this._logService.trace('SW - count of changed, early dom element: ', updateCount);
}
private _updateResourceUris(cssText: string): string | undefined {
let changed = false;
let newCssText = cssText.replace(/url\((["'])?(.+?\/vscode-resources\/fetch\?.+?)\1\)/g, (_match, g1, g2, _offset, _input) => {
changed = true;
return `url(${g1 || ''}${g2}&r=1${g1 || ''})`;
});
return changed ? newCssText : undefined;
this._logService.trace('SW', event.data);
}
}
......
......@@ -10,7 +10,7 @@
// statement.
// trigger service worker updates
const _tag = 'a6f9835e-c10e-4299-ab39-b8e29547c20a';
const _tag = '52278406-3ca9-48af-a8fb-8495add5bb4e';
// loader world
const baseUrl = '../../../../../';
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册