fix: Preload GutenbergKit and invalidate cache for non-Jetpack sites#25226
fix: Preload GutenbergKit and invalidate cache for non-Jetpack sites#25226
Conversation
🤖 Build Failure AnalysisThis build has failures. Claude has analyzed them - check the build annotations for details. |
|
The CI failures are seemingly unrelated to these changes and should be addressed by #25224. |
72730cd to
7dadca0
Compare
|
| App Name | WordPress | |
| Configuration | Release-Alpha | |
| Build Number | 31040 | |
| Version | PR #25226 | |
| Bundle ID | org.wordpress.alpha | |
| Commit | e5828fb | |
| Installation URL | 2p6oihttvab90 |
|
| App Name | Jetpack | |
| Configuration | Release-Alpha | |
| Build Number | 31040 | |
| Version | PR #25226 | |
| Bundle ID | com.jetpack.alpha | |
| Commit | e5828fb | |
| Installation URL | 4avv1csbp8d00 |
Add a thread-safe value wrapper for single values and use it to fix the Swift 6 warning on `_lastPluginsFlagValue` in EditorDependencyManager.
Add warmUpEditor(for:) method that combines WebKit warmup with data prefetch, consolidating the warmup logic in a single location.
Call warmUpEditor from MySiteViewController so all site types get editor preloading, including self-hosted sites without Jetpack that display BlogDetailsViewController instead of the dashboard.
Remove warmUpEditorIfNeeded() since warmup is now handled by MySiteViewController through EditorDependencyManager.warmUpEditor().
Move editor cache invalidation from BlogDashboardViewController to MySiteViewController so all site types get cache invalidation on pull-to-refresh. Previously, cache invalidation only happened in BlogDashboardViewController.pulledToRefresh(), which calls viewModel.clearEditorCache(). Non-Jetpack self-hosted sites show BlogDetailsViewController (Site Menu) instead of the dashboard, so the cache invalidation never occurred for these users. Now MySiteViewController.pulledToRefresh() handles cache invalidation for both dashboard and site menu sections, ensuring consistent behavior across all site types.
Add comprehensive tests for LockingValue including: - Initialization with various types (primitives, optionals, complex types) - Basic value access (get/set) - withLock operations (read, modify, return results, conditional updates) - Thread safety (concurrent reads, writes, increments, compare-and-swap)
7dadca0 to
e90b2ff
Compare
| } | ||
|
|
||
| /// Tracks the last blog for which WebKit warmup was performed. | ||
| private let lastWarmedUpBlogID = LockingValue<NSManagedObjectID?>(nil) |
There was a problem hiding this comment.
If you were to move this into State and use TaggedManagedObjectID<Blog>? you shouldn't need LockingValue at all.
There was a problem hiding this comment.
Should this be reset on a pull-to-refresh?
There was a problem hiding this comment.
Additionally, in e5828fb, I also cleared lingering slow path or "organic" caches created from opening the editor without a dependency cache.
Those caches are currently not exposed or tracked in EditorDependencyManger. We might consider changing how GutenbergKit manages this class of caches, potentially providing host apps access to them.
| } | ||
|
|
||
| @objc | ||
| private func pulledToRefresh() { |
There was a problem hiding this comment.
Is it possible to get a completion handler here that we can call from the Task so we can keep the loading state until the task is complete?
There was a problem hiding this comment.
@jkmassel possibly. I'm not sure it is worthwhile currently. I'll let Claude communicate what I struggled to put into words. WDYT?
Since pull-to-refresh only invalidates the cache (no re-prefetch), the invalidate operation is purely local I/O (deleting a directory and clearing a
URLCache) with no network calls. It completes near-instantly, so tying it to the loading state wouldn't provide meaningful UX benefit.If we later add re-prefetching after invalidation on pull-to-refresh, it would make sense to revisit this and keep the spinner active until the prefetch completes. The data prefetch is fully async and awaitable. However,
EditorViewController.warmup()in GutenbergKit is fire-and-forget with no completion API, so we'd need to add one upstream to cover the full warmup flow.
jkmassel
left a comment
There was a problem hiding this comment.
I left a few small suggestions, but the code generally looks ok to me.
When pull-to-refresh invalidates the editor cache, also reset the lastWarmedUpBlogID so the next warmUpEditor call re-runs WebKit warmup instead of skipping it.
Move lastWarmedUpBlogID from a standalone LockingValue<NSManagedObjectID?> into the existing OSAllocatedUnfairLock-backed State struct as TaggedManagedObjectID<Blog>?. This consolidates all mutable state behind a single lock and eliminates the LockingValue utility, which had no other consumers.
GutenbergKit populates its on-disk asset cache whenever the editor loads, not just through EditorDependencyManager's prefetch path. When the in-memory cache had no entries for a blog, purge() was never called, leaving stale on-disk assets served on subsequent editor opens. Fall back to purging for .post when there are no in-memory cache keys to ensure the on-disk cache is always cleared.
|





Description
This PR fixes editor preloading and cache invalidation for non-Jetpack self-hosted sites. Previously, these features only worked for Jetpack-connected sites because the logic was in
BlogDashboardViewModel, which is only used when displaying the dashboard. Non-Jetpack sites showBlogDetailsViewController(Site Menu) instead.Changes
Add
LockingValue<T>utility - Thread-safe wrapper for single values that aren'tSendable(e.g.,NSManagedObjectID), used forlastWarmedUpBlogIDinEditorDependencyManagerConsolidate editor warmup in
EditorDependencyManager- AddwarmUpEditor(for:)method that combines WebKit warmup with data prefetchMove editor preloading to
MySiteViewController- CallwarmUpEditorfromMySiteViewController.configure(for:)so all site types get editor preloadingMove cache invalidation to
MySiteViewController- CallEditorDependencyManager.invalidate(for:)inpulledToRefresh()so all site types get cache invalidation on pull-to-refreshRemove duplicate code from
BlogDashboardViewModel- RemovewarmUpEditorIfNeeded()andclearEditorCache()methods since this logic is now inMySiteViewControllerRoot cause
Both issues stem from the same architectural problem: non-Jetpack self-hosted sites display
BlogDetailsViewController(Site Menu) instead ofBlogDashboardViewController(Dashboard). The editor warmup and cache invalidation logic was inBlogDashboardViewModel, which is never instantiated for non-Jetpack sites.Fix CMM-1214.
Testing instructions
1. Editor Preloading (Non-Jetpack)
2. Cache Invalidation (Non-Jetpack)
3. Jetpack Sites (Regression Test)