Skip to content

Editor: Decouple local and remote autosave monitors - #79801

Open
Mamaduka wants to merge 8 commits into
trunkfrom
try/autosave-monitor-follow-ups
Open

Editor: Decouple local and remote autosave monitors#79801
Mamaduka wants to merge 8 commits into
trunkfrom
try/autosave-monitor-follow-ups

Conversation

@Mamaduka

@Mamaduka Mamaduka commented Jul 2, 2026

Copy link
Copy Markdown
Member

What?

Follow-up to #79043.

PR reformulates the autosave decision logic so remote and local autosave are independent — each has its own clock, its own "anything to save?" check, and its own notion of busy. Here's what's changed:

  • Splits the shared engine: AutosaveMonitor is now remote-only, and LocalAutosaveMonitor composes its own timer tick instead of wrapping the remote component. The only shared code is the small useInterval helper (now built on useEvent).
  • The local tick judges itself against the sessionStorage backup: saveable content, autosave not locked, new distinct edits, and a diff against the existing backup. It no longer calls isEditedPostAutosaveable() or isAutosavingPost().
  • Wraps both monitors in <PostTypeSupportCheck supportKeys="autosave">, so nothing mounts (no timers, no hooks) for post types without autosave support.
  • Moves the remote autosave-exists notice from EditorProvider into AutosaveMonitor, so both autosave notices live beside the code that triggers them.
  • localAutosaveGet() now returns parsed { title, content, excerpt } edits instead of a raw string; both call sites dropped their parse/compare boilerplate.
  • Colocates the files: local-autosave-monitor/ merged into autosave-monitor/ as local.js. Public exports are unchanged.
  • Adds characterization tests for LocalAutosaveMonitor, including its independence from remote save state.

Why?

  • LocalAutosaveMonitor reused the remote engine and silently inherited remote-only checks: local backups compared edits against the server autosave, waited for the server autosave to load, and paused while a REST save was in flight. None of that is relevant to writing sessionStorage.
  • The old logic was hard to explain because one code path served two different jobs (flagged in Editor: Refactor AutosaveMonitor to a function component #79043 review). Every condition in each tick now has a single, stateable purpose.

Open question: #79043 dropped the old 1s fast-retry while the post is ineligible, so the first autosave after a post becomes eligible can lag up to one interval. This PR keeps it out; flagging for reviewers whether to reintroduce it.

Behavior changes:

  • The autosave-exists notice no longer skips re-creation on error recovery (same ID, so no duplicates).
  • The local restore/purge hooks no longer run for post types without autosave support.

Testing Instructions

  1. CI checks should be green.
  2. Smoke test remote autosaving (edit a draft, wait ~60s, check network/revisions).
  3. Smoke test local backup: edit a post, wait ~15s, reload without saving; the "backup of this post in your browser" notice should appear and restore correctly.

Testing local autosaves.

  1. Create a post.
  2. Add title and save.
  3. Emulate offline mode.
  4. Add some content and try saving. Request will fail.
  5. Wait 20-30s and reload the page.
  6. Local autosave notice should be displayed.

User-facing behavior is also covered via test/e2e/specs/editor/various/autosave.spec.js.

Testing Instructions for Keyboard

Same.

Use of AI Tools

Assisted by Claude

@Mamaduka Mamaduka self-assigned this Jul 2, 2026
@Mamaduka Mamaduka added [Type] Enhancement A suggestion for improvement. [Package] Editor /packages/editor labels Jul 2, 2026
@Mamaduka
Mamaduka requested review from jsnajdr and tyxla July 2, 2026 06:40
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

Size Change: +203 B (0%)

Total Size: 7.68 MB

📦 View Changed
Filename Size Change
build/scripts/editor/index.min.js 494 kB +203 B (+0.04%)

compressed-size-action

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Comment thread packages/editor/src/components/autosave-monitor/test/local.js
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

Flaky tests detected in 3436c62.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/28920037212
📝 Reported issues:

@tyxla tyxla left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is looking mostly good to me, left just a few minor questions.

How do we test this thoroughly to ensure there are no regressions? Do you feel the test steps (and the existing tests) are enough?

// remote (REST) save state.
describe( 'independence from the remote monitor', () => {
it( 'should save while a remote autosave is in flight', () => {
setState( { isSaveable: true, isDirty: true, isAutosaving: true } );

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This test mocks isEditedPostSaveable to return true, but in a real use it returns false whenever a save is running (isSavingPost = state.saving.pending), which is exactly the case during a remote autosave. So in production, the local tick's if ( ! isEditedPostSaveable() ... ) return; guard would actually skip the backup here, which is the opposite of what the test claims. The test passes only because the mock hides that coupling. So the local monitor isn't really independent of remote saves. Either the test should use the real saveable logic, or the guard needs to stop depending on isSavingPost if full independence is what we want to ensure.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch, @tyxla!

The local autosave is still dependent on remove saving; the isSavingPost will be true for both manual and autosave triggers.

I guess the main question here is whether we want a local backup autosave while the remote one is in-flight, which later will be purged if the save request is successful.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I guess the main question here is whether we want a local backup autosave while the remote one is in-flight, which later will be purged if the save request is successful.

Maybe we want one to capture the scenario when the remote one wasn't successful?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated, tried to capture new behavior in should create local autosave if remote autosave fails e2e test. It's not perfect, but I couldn't come up with anything better.

Comment thread packages/editor/src/components/autosave-monitor/index.js
Comment thread packages/editor/src/components/autosave-monitor/local.js
@Mamaduka
Mamaduka force-pushed the try/autosave-monitor-follow-ups branch from 3436c62 to d91e31d Compare July 9, 2026 12:59
@Mamaduka

Mamaduka commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

@tyxla, added a section for testing local autosaves.

( key ) => backup[ key ] === getEditedPostAttribute( key )
);
if ( isBackupCurrent ) {
return;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will never update the lastEditsReferenceRef ref, is that expected? Should we still set it to editsReference as done below?

And if yes, we might want to add test coverage for this scenario.

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

Labels

[Package] Editor /packages/editor [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants