Skip to content

Commit 9c467b9

Browse files
committed
lazy load webview if there is no webview outputs or not kernel dependencies
1 parent cf9d6d7 commit 9c467b9

3 files changed

Lines changed: 96 additions & 42 deletions

File tree

extensions/vscode-notebook-tests/src/notebook.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ suite('webview', () => {
933933
// await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
934934
// assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true, 'notebook first');
935935
// const uri = vscode.notebook.activeNotebookEditor!.asWebviewUri(vscode.Uri.file('./hello.png'));
936-
// assert.equal(uri.scheme, 'vscode-resource');
936+
// assert.equal(uri.scheme, 'vscode-webview-resource');
937937
// await vscode.commands.executeCommand('workbench.action.closeAllEditors');
938938
// });
939939

src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts

Lines changed: 86 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
7575
private _overlayContainer!: HTMLElement;
7676
private _body!: HTMLElement;
7777
private _webview: BackLayerWebView | null = null;
78+
private _webviewResolved: boolean = false;
79+
private _webviewResolvePromise: Promise<BackLayerWebView | null> | null = null;
7880
private _webviewTransparentCover: HTMLElement | null = null;
7981
private _list: INotebookCellList | undefined;
8082
private _dndController: CellDragAndDropController | null = null;
@@ -591,7 +593,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
591593
// @deprecated
592594
if (provider && provider.kernel) {
593595
// it has a builtin kernel, don't automatically choose a kernel
594-
this._loadKernelPreloads(provider.providerExtensionLocation, provider.kernel);
596+
await this._loadKernelPreloads(provider.providerExtensionLocation, provider.kernel);
595597
tokenSource.dispose();
596598
return;
597599
}
@@ -610,7 +612,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
610612
// the provider doesn't have a builtin kernel, choose a kernel
611613
this.activeKernel = availableKernels[0];
612614
if (this.activeKernel) {
613-
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
615+
await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
614616
}
615617

616618
tokenSource.dispose();
@@ -630,7 +632,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
630632
}
631633

632634
if (this.activeKernel) {
633-
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
635+
await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
634636
await this.activeKernel.resolve(this.viewModel!.uri, this.getId(), tokenSource.token);
635637
}
636638

@@ -643,7 +645,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
643645
if (kernelsFromSameExtension.length) {
644646
const preferedKernel = kernelsFromSameExtension.find(kernel => kernel.isPreferred) || kernelsFromSameExtension[0];
645647
this.activeKernel = preferedKernel;
646-
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
648+
await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
647649
await preferedKernel.resolve(this.viewModel!.uri, this.getId(), tokenSource.token);
648650
tokenSource.dispose();
649651
return;
@@ -652,15 +654,16 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
652654
// the provider doesn't have a builtin kernel, choose a kernel
653655
this.activeKernel = kernels[0];
654656
if (this.activeKernel) {
655-
this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
657+
await this._loadKernelPreloads(this.activeKernel.extensionLocation, this.activeKernel);
656658
await this.activeKernel.resolve(this.viewModel!.uri, this.getId(), tokenSource.token);
657659
}
658660

659661
tokenSource.dispose();
660662
}
661663

662-
private _loadKernelPreloads(extensionLocation: URI, kernel: INotebookKernelInfoDto) {
663-
if (kernel.preloads) {
664+
private async _loadKernelPreloads(extensionLocation: URI, kernel: INotebookKernelInfoDto) {
665+
if (kernel.preloads && kernel.preloads.length) {
666+
await this._resolveWebview();
664667
this._webview?.updateKernelPreloads([extensionLocation], kernel.preloads.map(preload => URI.revive(preload)));
665668
}
666669
}
@@ -675,34 +678,63 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
675678
this._notebookExecuting?.set(notebookMetadata.runState === NotebookRunState.Running);
676679
}
677680

678-
private async _createWebview(id: string, resource: URI): Promise<void> {
679-
this._webview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource);
680-
// attach the webview container to the DOM tree first
681-
this._list?.rowsContainer.insertAdjacentElement('afterbegin', this._webview.element);
682-
await this._webview.createWebview();
683-
this._webview.webview.onDidBlur(() => {
684-
this._outputFocus?.set(false);
685-
this.updateEditorFocus();
681+
private async _resolveWebview(): Promise<BackLayerWebView | null> {
682+
if (!this.textModel) {
683+
return null;
684+
}
686685

687-
if (this._overlayContainer.contains(document.activeElement)) {
688-
this._webiewFocused = false;
689-
}
690-
});
691-
this._webview.webview.onDidFocus(() => {
692-
this._outputFocus?.set(true);
693-
this.updateEditorFocus();
694-
this._onDidFocusEmitter.fire();
686+
if (this._webviewResolvePromise) {
687+
return this._webviewResolvePromise;
688+
}
689+
690+
if (!this._webview) {
691+
this._webview = this.instantiationService.createInstance(BackLayerWebView, this, this.getId(), this.textModel!.uri);
692+
// attach the webview container to the DOM tree first
693+
this._list?.rowsContainer.insertAdjacentElement('afterbegin', this._webview.element);
694+
}
695+
696+
this._webviewResolvePromise = new Promise(async resolve => {
697+
await this._webview!.createWebview();
698+
this._webview!.webview!.onDidBlur(() => {
699+
this._outputFocus?.set(false);
700+
this.updateEditorFocus();
701+
702+
if (this._overlayContainer.contains(document.activeElement)) {
703+
this._webiewFocused = false;
704+
}
705+
});
706+
this._webview!.webview!.onDidFocus(() => {
707+
this._outputFocus?.set(true);
708+
this.updateEditorFocus();
709+
this._onDidFocusEmitter.fire();
710+
711+
if (this._overlayContainer.contains(document.activeElement)) {
712+
this._webiewFocused = true;
713+
}
714+
});
715+
716+
this._localStore.add(this._webview!.onMessage(({ message, forRenderer }) => {
717+
if (this.viewModel) {
718+
this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.getId(), forRenderer, message);
719+
}
720+
}));
695721

696-
if (this._overlayContainer.contains(document.activeElement)) {
697-
this._webiewFocused = true;
722+
if (this.viewModel && this.viewModel!.renderers.size) {
723+
this._webview?.updateRendererPreloads(this.viewModel!.renderers);
698724
}
725+
726+
this._webviewResolved = true;
727+
728+
resolve(this._webview!);
699729
});
700730

701-
this._localStore.add(this._webview.onMessage(({ message, forRenderer }) => {
702-
if (this.viewModel) {
703-
this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.getId(), forRenderer, message);
704-
}
705-
}));
731+
return this._webviewResolvePromise;
732+
}
733+
734+
private async _createWebview(id: string, resource: URI): Promise<void> {
735+
this._webview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource);
736+
// attach the webview container to the DOM tree first
737+
this._list?.rowsContainer.insertAdjacentElement('afterbegin', this._webview.element);
706738
}
707739

708740
private async _attachModel(textModel: NotebookTextModel, viewState: INotebookEditorViewState | undefined) {
@@ -736,10 +768,17 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
736768
}
737769
}
738770

739-
this._webview?.updateRendererPreloads(this.viewModel.renderers);
771+
if (this.viewModel.renderers.size) {
772+
await this._resolveWebview();
773+
this._webview?.updateRendererPreloads(this.viewModel.renderers);
774+
}
740775

741776
this._localStore.add(this._list!.onWillScroll(e => {
742-
this._webview!.updateViewScrollTop(-e.scrollTop, []);
777+
if (!this._webviewResolved) {
778+
return;
779+
}
780+
781+
this._webview?.updateViewScrollTop(-e.scrollTop, []);
743782
this._webviewTransparentCover!.style.top = `${e.scrollTop}px`;
744783
}));
745784

@@ -751,6 +790,11 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
751790

752791
const scrollTop = this._list?.scrollTop || 0;
753792
const scrollHeight = this._list?.scrollHeight || 0;
793+
794+
if (!this._webviewResolved) {
795+
return;
796+
}
797+
754798
this._webview!.element.style.height = `${scrollHeight}px`;
755799

756800
if (this._webview?.insetMapping) {
@@ -1375,6 +1419,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
13751419
return;
13761420
}
13771421

1422+
await this._resolveWebview();
1423+
13781424
let preloads = this._notebookViewModel!.renderers;
13791425

13801426
if (!this._webview!.insetMapping.has(output)) {
@@ -1389,15 +1435,15 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
13891435
}
13901436

13911437
removeInset(output: IProcessedOutput) {
1392-
if (!this._webview) {
1438+
if (!this._webview || !this._webviewResolved) {
13931439
return;
13941440
}
13951441

13961442
this._webview!.removeInset(output);
13971443
}
13981444

13991445
hideInset(output: IProcessedOutput) {
1400-
if (!this._webview) {
1446+
if (!this._webview || !this._webviewResolved) {
14011447
return;
14021448
}
14031449

@@ -1409,10 +1455,14 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
14091455
}
14101456

14111457
postMessage(forRendererId: string | undefined, message: any) {
1458+
if (!this._webview || !this._webviewResolved) {
1459+
return;
1460+
}
1461+
14121462
if (forRendererId === undefined) {
1413-
this._webview?.webview.postMessage(message);
1463+
this._webview.webview?.postMessage(message);
14141464
} else {
1415-
this._webview?.postRendererMessage(forRendererId, message);
1465+
this._webview.postRendererMessage(forRendererId, message);
14161466
}
14171467
}
14181468

src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ export interface INotebookWebviewMessage {
219219
let version = 0;
220220
export class BackLayerWebView extends Disposable {
221221
element: HTMLElement;
222-
webview!: WebviewElement;
222+
webview: WebviewElement | undefined = undefined;
223223
insetMapping: Map<IProcessedOutput, ICachedInset> = new Map();
224224
hiddenInsetMapping: Set<IProcessedOutput> = new Set();
225225
reversedInsetMapping: Map<string, IProcessedOutput> = new Map();
@@ -714,15 +714,15 @@ ${loaderJs}
714714
return;
715715
}
716716

717-
this.webview.focus();
717+
this.webview?.focus();
718718
}
719719

720720
focusOutput(cellId: string) {
721721
if (this._disposed) {
722722
return;
723723
}
724724

725-
this.webview.focus();
725+
this.webview?.focus();
726726
setTimeout(() => { // Need this, or focus decoration is not shown. No clue.
727727
this._sendMessageToWebview({
728728
type: 'focus-output',
@@ -814,6 +814,10 @@ ${loaderJs}
814814
}
815815

816816
private _updatePreloads(resources: IPreloadResource[], source: 'renderer' | 'kernel') {
817+
if (!this.webview) {
818+
return;
819+
}
820+
817821
const mixedResourceRoots = [...(this.localResourceRootsCache || []), ...this.rendererRootsCache, ...this.kernelRootsCache];
818822

819823
this.webview.localResourcesRoot = mixedResourceRoots;
@@ -830,7 +834,7 @@ ${loaderJs}
830834
return;
831835
}
832836

833-
this.webview.postMessage(message);
837+
this.webview?.postMessage(message);
834838
}
835839

836840
clearPreloadsCache() {
@@ -839,7 +843,7 @@ ${loaderJs}
839843

840844
dispose() {
841845
this._disposed = true;
842-
this.webview.dispose();
846+
this.webview?.dispose();
843847
super.dispose();
844848
}
845849
}

0 commit comments

Comments
 (0)