Skip to content

fix(dockview-vue): mount panels via Teleport so keep-alive lifecycle works (#1369)#1380

Open
mathuo wants to merge 1 commit into
masterfrom
feat/vue-teleport-mount
Open

fix(dockview-vue): mount panels via Teleport so keep-alive lifecycle works (#1369)#1380
mathuo wants to merge 1 commit into
masterfrom
feat/vue-teleport-mount

Conversation

@mathuo

@mathuo mathuo commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes #1369 — wrapping <dockview-vue> in <keep-alive> stopped panel components' onActivated/onDeactivated hooks from firing.

Root cause: panels were mounted as detached render() roots, placing them outside the Vue component tree. KeepAlive only fires activation hooks for components in its own subtree, so it could never reach the panels. The same disconnect also broke provide/inject (previously patched with a one-time appContext.provides snapshot copy).

Fix: mount components through <Teleport>. A shared reactive VueRendererRegistry collects the components and a <DockviewPortals> child of each host teleports them into dockview's DOM. Components stay logical descendants of the host (tree-walking features work) while dockview keeps full control of physical DOM placement — including across popout windows.

Compatibility — why this is a minor, not a major

The renderers gain an optional registry argument: with it they use the teleport path; without it they fall back to the unchanged mountVueComponent render root. mountVueComponent, VuePart, and the renderer classes keep backwards-compatible signatures and exports. No public API change.

Covers all four families: dockview, splitview, gridview, paneview.

Behavioural notes (for release notes)

  • onActivated/onDeactivated now fire for panels under <keep-alive>.
  • provide/inject now resolves via live component-tree ancestry (was a one-time snapshot).
  • ⚠️ Panel mounting is now asynchronous (deferred to Vue's flush, matching dockview-react) rather than synchronous on init. Code reading panel DOM synchronously after api.addPanel() should await nextTick().

Tests

dockview-vue suite: 121 passing (was 110). New coverage:

  • Panel renders via teleport — dockview, splitview, gridview, paneview
  • onActivated/onDeactivated across keep-alive toggles — all four families
  • provide/inject reaches a teleported panel
  • Tab switching (onlyWhenVisible detach/reattach) preserves panel instances (no remount/unmount)
  • Panel param updates flow through the reactive props ref

Verified: nx build:types (vue-tsc), nx lint (0 errors), nx build, nx test.

Not covered

  • Cross-window popout e2e. The popout path is sound by construction (core evacuates panels back to the main document before destroying a popout window) and validated at the unit level, but real cross-document behaviour can only be asserted in the Playwright e2e/ harness, which lives on the v8 line, not on master. To be added when this is forward-ported to v8.

🤖 Generated with Claude Code

…works (#1369)

Panel components were mounted as detached `render()` roots, so they sat
outside the Vue component tree. Anything that walks the tree therefore
never reached them — most visibly `<keep-alive>`'s `onActivated` /
`onDeactivated` hooks (#1369), but also `provide`/`inject`.

Mount components through `<Teleport>` instead: a shared, reactive
`VueRendererRegistry` collects the components and a `<DockviewPortals>`
child of each host teleports them into dockview's DOM. The components
stay logical descendants of the host (so tree-walking features work)
while dockview keeps full control of physical DOM placement.

The renderers gain an optional `registry` argument — with it they use
the teleport path, without it they fall back to the unchanged
`mountVueComponent` render root. Public exports are untouched, so this
is backwards compatible.

Covers dockview, splitview, gridview and paneview. Verified: panels
render, `onActivated`/`onDeactivated` fire across keep-alive toggles,
`provide`/`inject` resolves, tab switching (`onlyWhenVisible`) preserves
instances, and param updates flow through.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

After wrapping the dockview-vue component with keepalive, the onActivated method of the panel component managed by dockview-vue is no longer working.

1 participant