Core Data UI: move EntitiesSavedStates out of the editor into a dedicated package - #80022
Core Data UI: move EntitiesSavedStates out of the editor into a dedicated package#80022enejb wants to merge 9 commits into
Conversation
…spense into the shared lazy wrapper
…ated package Boot's always-mounted save UI statically rendered `EntitiesSavedStates` from `@wordpress/editor`. Because a classic-script import lands in a module's eager dependencies, this forced the entire editor (block-editor, block-library, media-utils) to load on every boot-powered view, including dashboard/list views that never edit. Rather than lazy-loading the editor (which still couples boot to it), this moves the entity-save UI to its right layer: a new `@wordpress/core-data-ui` package that depends on `@wordpress/core-data` + `@wordpress/components` but never on `@wordpress/editor`. - Add `@wordpress/core-data-ui` (classic script) hosting `EntitiesSavedStates`, `EntitiesSavedStatesExtensible`, and `useEntitiesSavedStatesIsDirty`. - Move `saveDirtyEntities` to a private `@wordpress/core-data` action (it is generic entity-save orchestration). Drop the block-editor `__unstableMarkLastChangeAsPersistent()` coupling and the editor-state-coupled "Post Meta." per-record indicator (`hasPostMetaChanges`). - `@wordpress/editor` re-exports the component/hook (public) and `EntitiesSavedStatesExtensible` (private) unchanged, so existing consumers (edit-site, editor) keep working; edit-site's save button now reads `saveDirtyEntities` from core-data. - Boot imports `EntitiesSavedStates` directly from `@wordpress/core-data-ui` and drops the `React.lazy`/`Suspense` shim and the `@wordpress/editor` / `@wordpress/lazy-editor` re-export. The editor now loads only when the canvas mounts it (dynamic import), never from the shell. Alternative to WordPress#71948 (which moved the component into `@wordpress/core-data`), keeping the data package free of UI dependencies. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`@wordpress/core-data-ui` uses `lock`/`unlock` for its private `EntitiesSavedStatesExtensible` export, so it must be in the core-modules allowlist; otherwise loading the package (and therefore the editor, which re-exports from it) throws at runtime. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address BC review of the EntitiesSavedStates relocation so consumers across all environments are unaffected: - Restore the private `core/editor` `saveDirtyEntities` action as a thin wrapper delegating to the new `core` (core-data) action, so external consumers of `unlock( dispatch( 'core/editor' ) ).saveDirtyEntities` and the documented private API keep working. edit-site's save button is reverted to the editor store (net zero change). - Keep the block-editor `__unstableMarkLastChangeAsPersistent()` behavior in core-data's `saveDirtyEntities` (core-data already depends on block-editor via its awareness code, so this adds no new coupling), preserving undo behavior for every caller. - Preserve the per-record "Post Meta." changes indicator in the moved component by computing it from core-data edits directly. The editor's `hasPostMetaChanges` selector only consulted editor state as a fallback for omitted args, which this call path never used, so the indicator is fully reproducible without the editor store. - Document the new `saveDirtyEntities` private action under the core-data store in docs/private-apis.md. Net effect: no public or private API removals, and no user-visible behavior change, while boot still loads no editor code. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the verbose `//` comments added across this work; the code reads clearly on its own. No functional changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
2 similar comments
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
|
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 If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
I don't have a fixed opinion here but for me a new package is the least appealing option. I'd see:
Not strictly opposed to the new package but I'm not sure I like it to be honest, I fear the duplication of very close packages causing more confusion for contributors. |
|
Thanks for the ping! Also, don't love the idea of a new package, which seems to have been introduced more recently. Ideally, UIs like What are the missing pieces to achieve this? What makes it hard to replicate this UI piece? I know @WordPress/gutenberg-components forks are very busy, but they might have some options. P.S. The |
The "why" is not clear to me here. |
|
My understanding is that |
|
Thanks for the feedback @youknowriad and @Mamaduka! I will add the components to the |
|
I am closing this in favour of #80074 |
What?
Introduce
@wordpress/core-data-ui, a small package that hosts the entity-save UI (EntitiesSavedStates), and move it out of@wordpress/editor.@wordpress/bootthen renders it directly fromcore-data-ui, so@wordpress/editor— and its heavy@wordpress/block-library/@wordpress/media-utilsdependencies — are no longer part of boot's dependency graph. The editor loads only when you're actually editing (the canvas loads it dynamically).This is an alternative to #71948 (which moves
EntitiesSavedStatesinto@wordpress/core-data). Putting React UI — which pulls in@wordpress/components,icons,clsx, etc. — into the data-onlycore-datapackage is a layering smell, so this variant keepscore-datapure data and introduces a dedicated UI package instead.Why?
Follow-up to #79913 and its review.
@wordpress/boot's always-mounted save UI statically importedEntitiesSavedStatesfrom@wordpress/editor. Because a classic-script import lands in a script module's eager dependencies (static or dynamic), this forced@wordpress/editorand everything it pulls in — most significantly@wordpress/block-library(all core blocks) and@wordpress/media-utils— to load on every boot-powered view, including dashboard/list views that never open the editor.#79913 deferred that with
React.lazy, but as @youknowriad noted, that still couples boot to the editor. The right fix is to move the component to its correct layer so the editor isn't pulled in at all.Scope of the load reduction
To be precise about what this removes:
wp-core-dataalready declareswp-block-editoras a dependency on trunk (via itsawareness/code), soblock-editorwas already loading on boot-powered views regardless of this change. What this PR removes from those views iswp-editor,wp-block-library, andwp-media-utils— the bulk of the editor payload. Verified against the built assets: boot's module now depends onwp-core-data-uiand dynamically imports@wordpress/lazy-editor, with nowp-editor/wp-block-library/wp-media-utilsin its static graph.How?
@wordpress/core-data-ui(classic script, handlewp-core-data-ui) exportingEntitiesSavedStates,EntitiesSavedStatesExtensible(private), anduseEntitiesSavedStatesIsDirty. Depends on@wordpress/core-data+@wordpress/components, never on@wordpress/editor.saveDirtyEntitiesimplementation moves to a private@wordpress/core-dataaction (it's generic entity-save orchestration).@wordpress/bootimportsEntitiesSavedStatesdirectly fromcore-data-ui, dropping theReact.lazy/<Suspense>shim and the@wordpress/editor/@wordpress/lazy-editorre-export.@wordpress/buildcompanion fix from Boot: lazy-load the editor instead of importing it eagerly in the save UI #79913 (routes enqueue their own classic deps, e.g.wp-viewport), which is still required once the editor stops loading on those views.Backwards compatibility
This is intended to be fully non-breaking for consumers across all environments (npm, WordPress script handles, editors):
@wordpress/editorre-exportsEntitiesSavedStates/useEntitiesSavedStatesIsDirty(public) andEntitiesSavedStatesExtensible(private) unchanged.getTemplateInfo/getTemplatePartIcon/ thehasPostMetaChangesselector stay ineditor.core/editorsaveDirtyEntitiesaction is retained as a thin wrapper delegating to the new core-data action, so existing consumers keep working.__unstableMarkLastChangeAsPersistent()undo marking stays (core-data already depends onblock-editor), and the per-record "Post Meta." indicator is reproduced from core-data edits directly.wp-core-data-uineeds adding to core'swp_default_packages_scripts()(standard new-package step). If ported to upstreamWordPress/gutenberg, the package would also need a native build entry.Deliberate scope choices
getTemplateInfo/getTemplatePartIconutils are duplicated intocore-data-ui(they only depend on@wordpress/icons) rather than moved out ofeditor, to avoid re-pointing ~10 unrelated editor consumers. Open to consolidating later.Testing Instructions
On the experimental Dashboard (Beta) page (
gutenberg-dashboard-widgetsexperiment), which mounts@wordpress/boot:editor.min.js,block-library.min.js, andmedia-utils.min.jsare not requested;core-data-uiloads; the page renders.window.wp.editorisundefined;window.wp.viewportis defined.edit-sitesave button / save panel and the editor publish panels.