Support serialization of IPYNB in web worker (#230190)

This commit is contained in:
Don Jayamanne 2024-10-01 21:22:55 +10:00 коммит произвёл GitHub
Родитель 96f0082842
Коммит 620fd6cb9a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
3 изменённых файлов: 109 добавлений и 3 удалений

Просмотреть файл

@ -8,15 +8,31 @@
'use strict';
const withBrowserDefaults = require('../shared.webpack.config').browser;
const path = require('path');
const config = withBrowserDefaults({
const mainConfig = withBrowserDefaults({
context: __dirname,
entry: {
extension: './src/ipynbMain.browser.ts'
},
output: {
filename: 'ipynbMain.browser.js'
filename: 'ipynbMain.browser.js',
path: path.join(__dirname, 'dist', 'browser')
}
});
module.exports = config;
const workerConfig = withBrowserDefaults({
context: __dirname,
entry: {
notebookSerializerWorker: './src/notebookSerializerWorker.web.ts',
},
output: {
filename: 'notebookSerializerWorker.js',
path: path.join(__dirname, 'dist', 'browser'),
libraryTarget: 'var',
library: 'serverExportVar'
},
});
module.exports = [mainConfig, workerConfig];

Просмотреть файл

@ -3,7 +3,83 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { DeferredPromise, generateUuid } from './helper';
import { NotebookSerializerBase } from './notebookSerializer';
export class NotebookSerializer extends NotebookSerializerBase {
private experimentalSave = vscode.workspace.getConfiguration('ipynb').get('experimental.serialization', false);
private worker?: Worker;
private tasks = new Map<string, DeferredPromise<Uint8Array>>();
constructor(context: vscode.ExtensionContext) {
super(context);
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('ipynb.experimental.serialization')) {
this.experimentalSave = vscode.workspace.getConfiguration('ipynb').get('experimental.serialization', false);
}
}));
}
override dispose() {
try {
void this.worker?.terminate();
} catch {
//
}
super.dispose();
}
public override async serializeNotebook(data: vscode.NotebookData, token: vscode.CancellationToken): Promise<Uint8Array> {
if (this.disposed) {
return new Uint8Array(0);
}
if (this.experimentalSave) {
return this.serializeViaWorker(data);
}
return super.serializeNotebook(data, token);
}
private async startWorker() {
if (this.disposed) {
throw new Error('Serializer disposed');
}
if (this.worker) {
return this.worker;
}
const entry = vscode.Uri.joinPath(this.context.extensionUri, 'dist', 'browser', 'notebookSerializerWorker.js');
this.worker = new Worker(entry.toString());
this.worker.addEventListener('exit', (exitCode) => {
if (!this.disposed) {
console.error(`IPynb Notebook Serializer Worker exited unexpectedly`, exitCode);
}
this.worker = undefined;
});
this.worker.onmessage = (e) => {
const result = e.data as { id: string; data: Uint8Array };
const task = this.tasks.get(result.id);
if (task) {
task.complete(result.data);
this.tasks.delete(result.id);
}
};
this.worker.onerror = (err) => {
if (!this.disposed) {
console.error(`IPynb Notebook Serializer Worker errored unexpectedly`, err);
}
};
return this.worker;
}
private async serializeViaWorker(data: vscode.NotebookData): Promise<Uint8Array> {
const worker = await this.startWorker();
const id = generateUuid();
const deferred = new DeferredPromise<Uint8Array>();
this.tasks.set(id, deferred);
worker.postMessage({ data, id });
return deferred.p;
}
}

Просмотреть файл

@ -0,0 +1,14 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { serializeNotebookToString } from './serializers';
import type { NotebookData } from 'vscode';
onmessage = (e) => {
const data = e.data as { id: string; data: NotebookData };
const json = serializeNotebookToString(data.data);
const bytes = new TextEncoder().encode(json);
postMessage({ id: data.id, data: bytes });
};