Skip to content

feat(docs): add incremental layout worker - #7433

Open
DR-Univer wants to merge 2 commits into
devfrom
feat/incremental-doc-layout-worker-upstream
Open

feat(docs): add incremental layout worker#7433
DR-Univer wants to merge 2 commits into
devfrom
feat/incremental-doc-layout-worker-upstream

Conversation

@DR-Univer

@DR-Univer DR-Univer commented Aug 7, 2026

Copy link
Copy Markdown
Member

Closes dream-num/univer-cli#1188

Description

Add incremental Docs layout for Traditional and Modern documents while keeping UNSPECIFIED editor documents on the historical Main-only path.

  • Keep the active interaction window on Main and recover the remaining dirty suffix in the Docs layout Worker.
  • Preserve logical caret, selection, and viewport-relative position across local input, Worker publication, and transformed remote OT mutations.
  • Restore the remote collaboration viewport as soon as Main publishes the valid interaction anchor, then let Worker perform the final authoritative calibration.
  • Bound foreground layout work, cancel stale generations, and avoid menu lifetime locks that unnecessarily pause background layout.
  • Reject popup geometry that crosses incompatible page or segment contexts.
  • Reuse the latest Main interaction skeleton for successive edits while Worker continues from the last complete canonical skeleton.

The Worker plugin and runtime live in @univerjs/docs; no standalone worker package is introduced. The capability is implemented in SDK packages. Demo code only registers the plugin and Worker entry.

Validation

Rebased onto origin/dev@cdd5fd06be as one feature commit (0d5eb1965d).

  • Repository-wide typecheck passed for all 81 packages.
  • Typecheck passed for @univerjs/core, @univerjs/docs, @univerjs/docs-ui, @univerjs/engine-render, @univerjs/docs-thread-comment-ui, @univerjs/docs-quick-insert-ui, and @univerjs/rpc.
  • Vitest passed:
    • @univerjs/core: 155 files passed, 3 skipped; 1039 tests passed, 10 skipped
    • @univerjs/docs: 28 files, 167 tests
    • @univerjs/docs-ui: 78 files, 757 tests
    • @univerjs/engine-render: 98 files, 1020 tests
    • @univerjs/docs-thread-comment-ui: 7 files, 21 tests
    • @univerjs/docs-quick-insert-ui: 7 files, 15 tests
    • @univerjs/rpc: 6 files, 15 tests
  • Post-rebase sanity passed for the Docs layout executor, Worker runtime, render controller, layout coordinator, and quick-insert suites.
  • The changed @univerjs/docs-quick-insert-ui package build passed.
  • Changed-file ESLint and git diff --check passed.

The existing Playwright collaboration matrix covers the 294-page stress document, the ClickUp agreement, issue #1188, Traditional and Modern modes, and the UNSPECIFIED Main-only regression.

SDK dependencies

No external SDK dependency version changes are introduced. The related Pro integration PR depends on the APIs in this PR and must merge after this PR.

Scope

No screenshots, sample documents, generated build output, temporary diagnostics, or submodule pointer updates are included. No architecture document is changed because the public behavior and lifecycle contracts are captured by the package APIs and regression suites in this PR.

Pull Request Checklist

  • Related tickets or issues have been linked in the PR description.
  • Naming convention is followed.
  • Unit and E2E tests have been added for the changes.
  • No breaking changes are introduced.

@DR-Univer

Copy link
Copy Markdown
Member Author

Stress follow-up for the 295-page rendered / ~594k-character DOCX sample:

  • Confirmed the imported snapshot contains all 31 drawings.
  • Reproduced a Worker publication regression: synchronous layout retained 31/31 drawing geometries, while incremental publications initially carried 0/31.
  • Fixed page finalization so block indices, inline drawings, paragraph shading, and borders are finalized before each physical page is published.
  • Removed the document-wide body finalization pass from paginated completion; final completion-step time in the stress harness dropped from 38.4 ms to 0.9 ms.
  • Worker publications now retain 31/31 drawings and still publish at most one page per update.
  • Real keyboard input near the document tail remained visible; measured automation-call median was 55.2 ms (the browser-control round trip contributes roughly 20–30 ms).
  • Added a compact regression covering inline drawing geometry on an early incrementally published page.

Validation: @univerjs/engine-render 97 files passed, 889 tests passed, 59 skipped; targeted typecheck and ESLint passed.

@DR-Univer

Copy link
Copy Markdown
Member Author

Latest stress and interaction follow-up: the 298-page / 594,044-character snapshot now reaches 50 ms for the first real key mutation-to-selection publication and 37–41 ms for the following eight keys (40 ms median). The remaining full-document ViewModel reset was replaced with a validated plain-text incremental update, and text-run lookup now uses range buckets instead of per-character Map entries. The active page retained focus after Worker completion. The Issue #1188 revision-85 snapshot also passed real keyboard paragraph input, floating menu, background color, and table-cell input with a stable viewport. All 19 Docs UI locales include the hard Worker-recovery message. Targeted regression validation: 7 files, 70 tests passed; Docs, Engine Render, Docs UI, and Docs layout Worker typechecks passed.

@DR-Univer

Copy link
Copy Markdown
Member Author

Follow-up validation for 5dbca9a:

  • Restored the shared Doc input, IME, selection, paragraph-menu, list-marker, and product-owned canvas-host behavior to the origin/dev path. Worker state now remains outside the immediate Main editing loop.
  • Fixed imported DOCX raw custom-block and legacy section metadata so regular typing and Enter no longer roll back the mutation.
  • Worker tail publication no longer rebuilds the active selection. A protected-page replacement preserves editing state and re-anchors the logical caret/viewport only when required.
  • Removed large-document capability degradation; table cells and paragraph hit targets are computed on demand, including header/footer and variable-height pages.

Validation:

  • Core: 996 passed / 10 skipped.
  • Docs: 118 passed.
  • Docs UI: 658 passed.
  • Engine Render: 902 passed / 59 skipped.
  • Docs Layout Worker: 1 passed.
  • Docs Drawing: 16 passed; Docs Drawing UI: 111 passed; RPC: 15 passed.
  • Related package typechecks passed; changed-file lint has 0 errors.
  • Pro Embed UI: 245 passed and typecheck passed.
  • The docs-layout-worker package and the complete examples Browser Asset Graph build successfully.

Real-browser 294-page DOCX-derived snapshot checks used physical pointer/keyboard input: Enter plus text insertion, table-cell insertion, text-range creation by double-click, yellow background formatting, floating text menu, image selection/menu, and Chinese text insertion all work. Waiting for Worker handoff does not replace the active page or remove the entered content. Quick Insert remains host-composition-owned and is identical with Worker enabled and disabled.

@DR-Univer

Copy link
Copy Markdown
Member Author

Latest editing regression fix: RichTextEditingMutation commonly carries exactly one post-edit text range without isActive. The render controller now treats that sole range as the foreground caret anchor, so Main publishes the new caret geometry before the existing selection refresh runs. This fixes Enter followed by continued typing in Worker-enabled Modern Docs without changing the input, shortcut, menu, Command, or Mutation paths.

Validation added in commit a2bd655:

  • focused DocRenderController suite: 34/34 passed
  • same-host Worker disabled/enabled E2E for Traditional and Modern: physical Enter/Shift+Enter, arrows, Backspace/Delete, Undo/Redo, clipboard paste, double-click TextRange, and Quick Insert command/body equivalence
  • generated long Traditional fixture remains editable on an already-published far page while initial Worker layout is incomplete
  • real 294-page snapshot remains editable before initial Worker completion: physical far-page click, text input, Enter, and following-line input all reached the model while at least 15 pages were published
  • affected package typechecks and E2E build passed

@DR-Univer
DR-Univer marked this pull request as ready for review August 10, 2026 06:06
@DR-Univer DR-Univer changed the title Add incremental Docs layout Worker feat(docs): add incremental layout worker Aug 10, 2026
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

Playwright test results

passed  10 passed
skipped  5 skipped

Details

stats  15 tests across 8 suites
duration  1 minute, 24 seconds
commit  d272f30
info  For more information, see full report and artifacts

Skipped tests

chromium › smoking/docs-layout-worker-editing.spec.ts › keeps Enter active when the 294-page document only shows the Quick Insert button
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps the keyboard caret visible when Enter crosses the viewport edge during Worker layout
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps the 294-page document editable in the Docs Core host without Quick Insert
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps a local caret viewport-stable after a remote edit before it in the 294-page document
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps a local caret viewport-stable after a remote edit after it in the 294-page document

@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.93261% with 800 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.28%. Comparing base (cdd5fd0) to head (fb7eb92).

Files with missing lines Patch % Lines
...ollers/render-controllers/doc.render-controller.ts 77.56% 166 Missing ⚠️
packages/docs/src/layout-worker/index.ts 3.64% 132 Missing ⚠️
...ender-controllers/back-scroll.render-controller.ts 1.17% 84 Missing ⚠️
...-ui/src/services/doc-layout-coordinator.service.ts 80.47% 83 Missing ⚠️
...s/docs/src/services/doc-layout-executor.service.ts 82.30% 60 Missing ⚠️
...rollers/doc-drawing-transform-update.controller.ts 70.05% 53 Missing ⚠️
...ntrollers/doc-layout-recovery.render-controller.ts 28.81% 42 Missing ⚠️
packages/docs/src/layout-worker/worker.ts 79.32% 37 Missing ⚠️
packages/core/src/docs/data-model/text-x/utils.ts 38.46% 32 Missing ⚠️
...docs/data-model/text-x/apply-utils/update-apply.ts 27.27% 16 Missing ⚠️
... and 18 more
Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #7433      +/-   ##
==========================================
- Coverage   81.30%   81.28%   -0.02%     
==========================================
  Files        2716     2731      +15     
  Lines      170611   175764    +5153     
  Branches    42511    43379     +868     
==========================================
+ Hits       138709   142878    +4169     
- Misses      31854    32836     +982     
- Partials       48       50       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@DR-Univer
DR-Univer force-pushed the feat/incremental-doc-layout-worker-upstream branch from 1078787 to 920895e Compare August 10, 2026 09:24
@DR-Univer

Copy link
Copy Markdown
Member Author

Post-rebase CI note: the only remaining failed check is the pre-existing diff merged cells rendering Sheet visual flake. Shard 4 consistently reports 74,265 differing pixels (ratio 0.02) in mergedCellsRendering.ci.png. The current dev change #7467 produced the exact same failure in run 31368132657 before its rerun passed in run 31368462690. A local base/head comparison also produced the same dimensions and diff summary on both origin/dev and this branch. All unit shards, typecheck, ESLint, build, Semgrep, Codecov, and the Pro text-layout/embed suites pass. I intentionally did not update the unrelated Sheet snapshot or mix a Sheet test change into this Docs PR.

@DR-Univer

DR-Univer commented Aug 10, 2026

Copy link
Copy Markdown
Member Author

Post-rebase CI follow-up for 6c918787d6:

  • Build, typecheck, ESLint, and all unit-test shards pass.
  • The local real-browser Docs suite passes 12/12, and the Issue refactor: remove BaseComponent #1188 plus 294-page performance gates each pass 1/1.
  • I reran the failed Playwright workflow once. The only executed failure is still the unrelated Sheet snapshot visual-comparison/sheets/sheets-visual-comparison.spec.ts › diff merged cells rendering, with the exact same 74,265 differing pixels / 0.02 ratio already reproduced on the unmodified base. The remaining shards were canceled by fail-fast; no Docs E2E failed.

I am not updating the Sheet implementation or snapshot in this Docs PR.

@DR-Univer
DR-Univer force-pushed the feat/incremental-doc-layout-worker-upstream branch 2 times, most recently from 99ccd88 to 096df65 Compare August 10, 2026 18:49
@DR-Univer

Copy link
Copy Markdown
Member Author

Follow-up validation for Modern continuous editing (commit d0e8486):

  • Replaced the fixed 5-block foreground cutoff with a viewport-derived protected end offset plus one viewport of overscan.
  • The viewport lookup uses binary search over laid-out lines, so far-document input does not add an O(n) Main-thread scan.
  • Main advances within the remaining 28 ms command budget, then yields across tasks until the visible range is protected before handing the suffix to the Worker.
  • Added a real-keyboard E2E over a 2,000-paragraph Modern document. Paragraph 505 remains hit-testable for 20 consecutive animation frames while paragraph 500 is edited; the model mutation and caret are also verified.

Validation:

  • pnpm --filter @univerjs/docs-ui test: 76 files / 704 tests passed
  • pnpm typecheck: 82/82 packages passed
  • pnpm lint: passed
  • Modern flavor 2 complete keyboard/IME/Enter/Quick Insert/table-format E2E: passed
  • UNSPECIFIED flavor 0 and TRADITIONAL flavor 1 equivalent E2E: passed
  • Forced uncached E2E build plus Modern visible-suffix regression: passed

@DR-Univer
DR-Univer force-pushed the feat/incremental-doc-layout-worker-upstream branch 2 times, most recently from c1153fa to d21edde Compare August 12, 2026 07:47
@DR-Univer

Copy link
Copy Markdown
Member Author

Fixed an incremental list-layout crash exposed by the ClickUp MSA DOCX.

Root cause: imported lists may start at nesting level 1 or deeper. The list ancestor cache was created as a sparse array, and copying it materialized skipped levels as undefined. Incremental table checkpoints later cloned every level as an iterable, so both the Worker and the main-thread fallback failed with s is not iterable.

Commit: 33f7e0df1 fix(docs): normalize skipped list levels

Validation:

  • Added a regression test for a list that starts directly at nesting level 1.
  • @univerjs/engine-render: 71 focused tests passed.
  • @univerjs/engine-render typecheck passed.
  • @univerjs/docs-layout-worker: 3 tests passed.
  • Imported the reported DOCX (619 paragraphs, 312 list paragraphs), loaded it in the Pro traditional demo with the Worker enabled, and scrolled through the final page 122 without a Worker restart, main-thread fallback, or iterable error.

No fixture document, screenshots, or generated demo artifacts are included in the commit.

@DR-Univer

Copy link
Copy Markdown
Member Author

Validated the incremental layout implementation against origin/dev with three real document snapshots, including the 29.8 MB stress document.

A real parity bug was found in resumable table pagination: the precomputation path opened a new table fragment at remainHeight <= 72 and only treated AUTO rows as splittable, while the synchronous production path uses remainHeight <= 0 and allows every non-EXACT row to split. This changed several cross-page row heights and reduced the stress document from 138 to 137 layout pages.

Commit e208de3 aligns the resumable rules and adds focused regression tests for positive remaining height and AT_LEAST rows.

Validation:

  • Stress snapshot: synchronous / incremental / Worker all produce 138 pages; 0 visible page, character-range, table, drawing, or column-group differences.
  • Issue refactor: remove BaseComponent #1188 snapshot: visible layout matches origin/dev and incremental/Worker parity.
  • ClickUp contract snapshot: geometry matches origin/dev; the only logical-index difference is the intentional legacy-token normalization already covered by this branch.
  • @univerjs/engine-render: 995 passed, 59 skipped.
  • @univerjs/docs-layout-worker: all tests passed.
  • Full monorepo typecheck: 82/82 workspaces passed.
  • DOCX golden e2e: 28 passed, 180 skipped.

@DR-Univer
DR-Univer force-pushed the feat/incremental-doc-layout-worker-upstream branch 7 times, most recently from d272f30 to 9d70664 Compare August 17, 2026 17:04
@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown

Playwright test results

failed  5 failed
passed  4 passed
skipped  10 skipped

Details

stats  19 tests across 3 suites
duration  1 minute, 50 seconds
commit  f56b509
info  For more information, see full report and artifacts

Failed tests

chromium › smoking/docs-layout-worker-complex-elements.spec.ts › keeps complex text editing and floating drawing movement stable with Worker layout in flavor 2
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps flavor 0 keyboard editing and Quick Insert semantics unchanged with the Doc layout Worker
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps flavor 1 keyboard editing and Quick Insert semantics unchanged with the Doc layout Worker
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps flavor 2 keyboard editing and Quick Insert semantics unchanged with the Doc layout Worker
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps the caret editable after continuous typing crosses a physical page

Skipped tests

chromium › smoking/docs-layout-worker-editing.spec.ts › keeps the original Issue #1188 editing semantics unchanged with the Doc layout Worker
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps the real 294-page fixture interactive before initial Worker layout completes
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps publishing pages across repeated IME commits in the fully laid out 294-page fixture
chromium › smoking/docs-layout-worker-editing.spec.ts › records reproducible browser performance for both large Doc fixtures
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps Enter active when the 294-page document only shows the Quick Insert button
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps the keyboard caret visible when Enter crosses the viewport edge during Worker layout
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps the 294-page document editable in the Docs Core host without Quick Insert
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps a local caret viewport-stable after a remote edit before it in the 294-page document
chromium › smoking/docs-layout-worker-editing.spec.ts › keeps a local caret viewport-stable after a remote edit after it in the 294-page document
chromium › smoking/docs-layout-worker-real-fixtures.spec.ts › edits and completes the real issue-1188 fixture in flavor 1

Comment thread packages/ui/src/views/progress-bar/ProgressBar.tsx Outdated
Comment thread packages/docs-layout-worker/package.json Outdated
@DR-Univer
DR-Univer force-pushed the feat/incremental-doc-layout-worker-upstream branch 2 times, most recently from f05559f to f56b509 Compare August 18, 2026 06:44
@DR-Univer
DR-Univer force-pushed the feat/incremental-doc-layout-worker-upstream branch from f56b509 to 9ffc1da Compare August 27, 2026 15:58
@DR-Univer
DR-Univer force-pushed the feat/incremental-doc-layout-worker-upstream branch from 9ffc1da to 0d5eb19 Compare August 27, 2026 16:07
@DR-Univer
DR-Univer requested a review from jikkai August 27, 2026 16:14
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.

2 participants