Skip to content

[Improve] Dispose view listeners and ignore stale views when the webview is replaced - #2213

Merged
edelauna merged 3 commits into
mainfrom
fix/dispose-stale-view-listeners-0ffy29ws1ihsp
Oct 28, 2026
Merged

edelauna merged 3 commits into
mainfrom
fix/dispose-stale-view-listeners-0ffy29ws1ihsp

Conversation

@zoomote2

@zoomote2 zoomote2 Bot commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

​Created by Roomote. Follow up by mentioning @roomote, in the web UI, or in Discord.

Related GitHub Issue

Closes: #2205

Description

ClineProvider.resolveWebviewView now keeps all subscriptions of the current view in one list, webviewDisposables. The list holds the message, focus tracker, view state, dispose, and configuration listeners. The dispose listener moved there from the extension-lifetime disposables list. A replaced view can no longer keep listeners alive.

A resolve that starts for a different view now disposes that list at entry. The view dispose path also disposes it. Each listener ignores events from a view that is no longer the current view. This covers the message, visibility, view state, configuration, and dispose listeners. A stale dispose can no longer clear the listeners of the new view.

Two guards stop a resolve that finishes after disposal or replacement. One guard runs after the HTML load. A stale resolve does not assign HTML. The other guard runs after await this.getState(). A stale resolve does not install listeners. The sidebar dispose handler clears this.view before it clears the view resources.

This PR does not add heartbeat or watchdog code. That work stays in PR #1715, which rebases on this change.

Six provider test files used a shared onDidDispose mock that fired the callback at registration. Real VS Code never fires a dispose event at registration. The new sidebar dispose behavior would clear this.view during every resolve with that mock. The mocks now record the registration and return a disposable only.

Test Procedure

A new suite, src/core/webview/__tests__/ClineProvider.stale-view.spec.ts, covers each behavior with eight tests:

  • Each stale-resolve guard, after the HTML load and after await this.getState(). Each guard has a replacement case and a provider-disposed case. No earlier test reached the guard after getState().
  • One-list disposal when a different view replaces the current view.
  • Ignored events from a replaced view for message, visibility, and dispose. A stale dispose leaves the current view listeners active.
  • Sidebar dispose clears this.view and disposes the view subscriptions. The provider instance stays registered.
  • Accept paths: the current view still dispatches messages, visibility, and theme refreshes.

Commands run from the repository root:

  • pnpm --dir src exec vitest run core/webview — 731 tests pass, including the new suite.
  • pnpm --dir src run check-types — passes.
  • pnpm --dir src exec eslint --prune-suppressions --max-warnings=0 <changed files> — passes. Suppression counts did not increase.
  • pnpm test — all 14 tasks pass.

Reviewers can repeat the focused run with pnpm --dir src exec vitest run core/webview/__tests__/ClineProvider.stale-view.spec.ts.

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I reviewed my own code with care.
  • Writing Style: The PR title and description use Simplified Technical English (ASD-STE100): short sentences, plain words, active voice, one idea per sentence, no contractions.
  • Testing: New and/or updated tests have been added to cover my changes (if applicable).
  • Visual Snapshot (UI changes only): not applicable. This change has no UI-visible state.
  • Documentation Impact: I checked if my changes need documentation updates (see "Documentation Updates" section below).
  • Contribution Guidelines: I read and agree to the Contributor Guidelines.

Visual Snapshots

None. This change handles extension-host view lifecycle only. It has no rendered UI state.

Videos (interaction / animation only)

None.

Documentation Updates

  • No documentation updates are required.

This change fixes internal listener lifecycle behavior. It adds no setting, command, or user-visible behavior. The Zoo-Code-Docs repository needs no paired change.

Additional Notes

Get in Touch

Use the follow-up links in the note at the top of this PR.

@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one): 1
  • coderabbit-review-active

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@zoomote2

zoomote2 Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor Author

No code issues found. See session

The follow-up commits fix the outstanding item: the unused disposables field and its drain loop are removed (e35e95bf), and the onDidDispose registration now happens before the HTML/state loads so a dispose during resolve invalidates it (4eebab1). The earlier webview-visual note no longer applies: the branch is now based on the snapshot fix from #2209.

  • src/core/webview/ClineProvider.ts:1184 — after moving the onDidDispose registration to webviewDisposables, this.disposables has no remaining writers; remove the orphaned field and its drain loop in dispose().

Reviewed e35e95bf

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Review status

This PR was opened by an automated account. A human maintainer must verify the change intent, provenance, and validation before merging.

Current step: The required review sequence passed. Remaining merge requirements apply.

Review-state labels are managed by this workflow; do not edit them manually. community-approved is managed the same way — do not add or remove it manually. It signals a fresh community code approval for the current head as an advisory priority only; maintainer review is still required.

@codecov

codecov Bot commented Oct 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Comment thread src/core/webview/ClineProvider.ts Resolved
@edelauna
edelauna force-pushed the fix/dispose-stale-view-listeners-0ffy29ws1ihsp branch from 64c7d62 to 4eebab1 Compare October 28, 2026 01:41
@edelauna
edelauna marked this pull request as ready for review October 28, 2026 02:59
@edelauna
edelauna enabled auto-merge October 28, 2026 03:01
@edelauna
edelauna added this pull request to the merge queue Oct 28, 2026
Merged via the queue into main with commit 3f51e9d Oct 28, 2026
39 of 40 checks passed
@edelauna
edelauna deleted the fix/dispose-stale-view-listeners-0ffy29ws1ihsp branch October 28, 2026 03:11
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.

[ENHANCEMENT] Dispose view listeners and ignore stale views when the webview is replaced

2 participants