Skip to content

fix: chunk large JCEF messages to prevent JetBrains sidebar freezes#11899

Merged
Patrick-Erichsen merged 8 commits intomainfrom
fix/jcef-chunked-messages
Mar 26, 2026
Merged

fix: chunk large JCEF messages to prevent JetBrains sidebar freezes#11899
Patrick-Erichsen merged 8 commits intomainfrom
fix/jcef-chunked-messages

Conversation

@RomneyDa
Copy link
Copy Markdown
Contributor

@RomneyDa RomneyDa commented Mar 26, 2026

Summary

  • When sendToWebview is called with a large payload (e.g. loading a long conversation session), the entire JSON is embedded in a single executeJavaScript("window.postMessage(<huge JSON>, '*')") call. JCEF's JS source parser/compiler cannot handle multi-megabyte source strings and freezes the IDE.
  • This adds a chunked path for messages over 1MB: the JSON is base64-encoded, split into 2MB chunks sent as separate executeJavaScript calls that each push to an array buffer, then one final small call joins, decodes, and dispatches the complete message via window.postMessage.
  • Messages under 1MB (the vast majority) take the existing fast path, unchanged.

How the chunking works

JCEF never sees partial JSON. Each executeJavaScript call just pushes a base64 string fragment to an array (buffer.push("abc123...")). No JSON parsing happens until the very last call, which runs JSON.parse(atob(buffer.join(""))) on the reassembled complete string. The freeze was caused by JCEF having to compile a massive JS source string, not by V8 processing the data — so keeping each source string small (~2MB) avoids the freeze entirely.

Array push+join is used instead of string concatenation to keep reassembly O(n) instead of O(n²). The chunk generation logic is extracted into a testable buildChunkScripts() function with unit tests.

Related issues

Fixes the large-session-file variant of the JCEF freeze reported across multiple issues:

Test plan

  • Open a JetBrains IDE with Continue installed
  • Have a normal short conversation — verify messages display correctly (fast path)
  • Load a session with a very long conversation history (large session JSON file) — verify it loads without freezing the IDE
  • Verify the sidebar remains responsive after loading a large session
  • Run ./gradlew test --tests "*.ContinueBrowserChunkTest" — all 7 unit tests pass

When session data exceeds ~1MB (e.g. long conversations with many context
items), sendToWebview embeds the entire JSON payload in a single
executeJavaScript call. JCEF's JS parser/compiler cannot handle source
strings that large and freezes the IDE.

This adds a chunked sending path: payloads over 1MB are base64-encoded,
split into 512KB chunks sent as individual executeJavaScript calls that
each append to a buffer variable, then a final call decodes and dispatches
the reassembled message via window.postMessage. Each individual call is
trivial for JCEF to parse, and V8 handles the string concatenation and
final JSON.parse without issue.

Messages under 1MB (the vast majority) take the existing fast path unchanged.
@RomneyDa RomneyDa requested a review from a team as a code owner March 26, 2026 19:08
@RomneyDa RomneyDa requested review from sestinj and removed request for a team March 26, 2026 19:08
@dosubot dosubot bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Mar 26, 2026
@continue
Copy link
Copy Markdown
Contributor

continue bot commented Mar 26, 2026

Docs Review: No documentation updates needed.

This PR is an internal bug fix to the JetBrains extension's JCEF message handling. The chunking mechanism is:

  • Completely transparent to users (no new APIs or config options)
  • An implementation detail that doesn't affect how developers use Continue
  • A performance/stability fix that users benefit from automatically

The existing docs accurately describe using Continue in JetBrains — they don't need to explain internal message transport mechanisms.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowser.kt">

<violation number="1" location="extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/browser/ContinueBrowser.kt:92">
P2: Escape or serialize messageId before embedding it into JavaScript string literals. As written, a messageId containing quotes/backslashes will break the generated JS (or allow injection) in the chunked path.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Replaces O(n²) string concatenation (+=) with O(n) array push + join
for JS-side chunk buffering. Extracts script generation into testable
buildChunkScripts() and adds unit tests for chunking logic.
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Mar 26, 2026
Reduces IPC round-trips by 4x (e.g. 7 calls instead of 26 for 10MB).
Safe because chunks are trivial JS with pure Base64 string literals.
atob() returns Latin-1, so multi-byte UTF-8 characters (em dashes,
accented letters, CJK, emoji) were mangled. Use TextDecoder to
properly decode UTF-8 bytes after base64 decoding.
@github-project-automation github-project-automation bot moved this from Todo to In Progress in Issues and PRs Mar 26, 2026
@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Mar 26, 2026
@Patrick-Erichsen Patrick-Erichsen merged commit afd5e5e into main Mar 26, 2026
65 of 66 checks passed
@Patrick-Erichsen Patrick-Erichsen deleted the fix/jcef-chunked-messages branch March 26, 2026 21:59
@github-project-automation github-project-automation bot moved this from In Progress to Done in Issues and PRs Mar 26, 2026
@github-actions github-actions bot locked and limited conversation to collaborators Mar 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants