# How the SecureDesign VS Code Extension Persists and Restores State Across Restarts

> Learn how the SecureDesign VS Code extension persists and restores UI state across restarts using the Memento API and WebviewPanelSerializer for seamless development.

- Repository: [Harold Martin/secure-design](https://github.com/hbmartin/secure-design)
- Tags: internals
- Published: 2026-03-03

---

**The SecureDesign VS Code extension ensures state persistence across restarts by combining VS Code's Memento API for workspace data, a registered `WebviewPanelSerializer` for UI restoration, and the `retainContextWhenHidden` flag to preserve webview context.**

The SecureDesign extension maintains chat history, selected design files, and canvas scroll positions even after VS Code shuts down or reloads. By implementing a layered persistence strategy across multiple VS Code APIs, the extension guarantees that users return to the exact UI state they left. This article examines the specific mechanisms found in the `hbmartin/secure-design` repository that make this seamless restoration possible.

## Persisting Workspace Data with the Memento API

The extension persists small, serializable data pieces—such as chat history and selected workspace folders—using VS Code’s `ExtensionContext.workspaceState`. This **Memento** storage is wrapped by the `WorkspaceStateService`, a singleton initialized during extension activation that namespaces all keys to prevent collisions.

In [`src/services/workspaceStateService.ts`](https://github.com/hbmartin/secure-design/blob/main/src/services/workspaceStateService.ts), the service provides type-safe getter and setter methods that interact directly with the VS Code context:

```typescript
public get<T>(key: string): T | undefined {
  const context = this.ensureContext();
  const workspaceKey = this.getNamespacedKey(key);
  return context.workspaceState.get(workspaceKey);
}

public update<T>(key: string, value: T): Thenable<void> {
  const context = this.ensureContext();
  const workspaceKey = this.getNamespacedKey(key);
  return context.workspaceState.update(workspaceKey, value);
}

```

The `WorkspaceStateService` is instantiated in the `activate()` function within [`src/extension.ts`](https://github.com/hbmartin/secure-design/blob/main/src/extension.ts) and shared across all services that require durable storage, ensuring that critical metadata survives full VS Code shutdowns.

## Restoring Webview Panels After Reloads

To survive VS Code reloads, the extension registers a **WebviewPanelSerializer** for the `SuperdesignCanvasPanel`. This registration occurs in [`src/extension.ts`](https://github.com/hbmartin/secure-design/blob/main/src/extension.ts) and tells VS Code how to reconstruct the panel and restore its previous content when the editor restarts.

The serializer implementation receives the saved state object that the panel previously stored through VS Code’s internal persistence mechanism:

```typescript
const canvasSerializer = vscode.window.registerWebviewPanelSerializer(
  SuperdesignCanvasPanel.viewType,
  {
    deserializeWebviewPanel(webviewPanel, state) {
      Logger.info('Restoring SuperdesignCanvasPanel from saved state');
      SuperdesignCanvasPanel.deserialize(
        webviewPanel,
        state,
        context.extensionUri,
        sidebarProvider
      );
      return Promise.resolve();
    },
  }
);

```

When `deserializeWebviewPanel` is called, it invokes the static `SuperdesignCanvasPanel.deserialize()` method, which recreates the panel instance, re-adds it to the internal `panels` map, and prepares the webview to receive its restored UI state.

## Managing Canvas UI State Serialization

The `SuperdesignCanvasPanel` class in [`src/SuperdesignCanvasPanel.ts`](https://github.com/hbmartin/secure-design/blob/main/src/SuperdesignCanvasPanel.ts) defines a `CanvasPanelState` interface that tracks the workspace URI, currently selected design file, and scroll position. When users interact with the canvas—such as selecting a frame—the panel invokes `_saveState()` to post the current state to the webview:

```typescript
private _saveState(): void {
  const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
  if (workspaceFolder && this._state) {
    this._state.workspaceUri = workspaceFolder.uri.toString();
  }
  this._panel.webview.postMessage({ command: 'setState', state: this._state ?? {} });
}

```

VS Code automatically persists this state object between sessions. Upon deserialization, the panel calls `_restoreState()` to push the saved selection back to the webview’s frontend:

```typescript
private _restoreState(): void {
  if (this._state?.selectedFile) {
    this._panel.webview.postMessage({
      command: 'restoreSelection',
      fileName: this._state.selectedFile,
    });
  }
}

```

This bidirectional message flow ensures that the UI appears exactly as the user left it, including precise scroll positions and file selections.

## Preserving Context When Hidden

Both the sidebar webview and the canvas panel are created with `retainContextWhenHidden: true` set in their webview options. This setting prevents VS Code from destroying the webview’s DOM and internal JavaScript state when the user switches to another tab or panel.

Without this flag, the webview would lose its state before the extension could serialize it. By retaining the context, the extension maintains live UI state in memory and only relies on the Memento and serializer APIs for shutdown survival, not for tab switching.

## Summary

- **WorkspaceStateService** wraps `ExtensionContext.workspaceState` to persist chat history and workspace selections across full VS Code shutdowns
- The **WebviewPanelSerializer** registered in `activate()` handles reconstruction of `SuperdesignCanvasPanel` when VS Code reloads, receiving the previously saved state object automatically
- **Canvas panel state** flows through `_saveState()` and `_restoreState()` methods that communicate with the webview via `postMessage` to restore exact UI selections and scroll positions
- **`retainContextWhenHidden: true`** prevents state loss during tab switching by keeping the webview DOM alive while the panel is not visible

## Frequently Asked Questions

### How does SecureDesign store chat history between VS Code sessions?

Chat history and other workspace-specific metadata are stored via the `WorkspaceStateService`, which uses VS Code’s `ExtensionContext.workspaceState` Memento API. This service namespaces all keys and writes data to VS Code’s internal storage, which persists across restarts in workspace storage files.

### What triggers the restoration of the design canvas after a reload?

When VS Code restarts, it automatically calls the registered `WebviewPanelSerializer` for `SuperdesignCanvasPanel.viewType`. The serializer’s `deserializeWebviewPanel` method receives the saved state object and invokes `SuperdesignCanvasPanel.deserialize()` to reconstruct the panel and its webview content.

### Where is the persistent workspace state physically stored?

VS Code stores Memento data—accessed via `workspaceState`—in a SQLite database or JSON files within the workspace’s extension storage folder on disk. The exact location is managed by VS Code’s extension host, not by the SecureDesign extension directly.

### Why doesn't the extension lose state when switching between editor tabs?

Both the sidebar provider and canvas panel webviews are created with the `retainContextWhenHidden: true` option. This prevents VS Code from discarding the webview’s DOM and JavaScript context when the user switches away, ensuring the UI remains live and ready without requiring deserialization.