EditorViewController.warmup(configuration:) is documented as loading the editor HTML without dependencies to prewarm WebKit. It does that, then falls through and does the full dependency fetch as well — ending in a second navigation that discards the prewarm it just performed.
Detail
ios/Sources/GutenbergKit/Sources/EditorViewController.swift:297-299:
if isWarmupMode {
self.loadEditorWithoutDependencies()
}
No return, no else. warmup() (:921) constructs with isWarmupMode: true and no dependencies, so the if let dependencies at :323 fails and execution continues into the ASYNC FLOW at :334. That runs prepareEditor() → a live authenticated REST fetch plus the asset-bundle download → loadEditor(dependencies:) → a second webView.loadFileURL at :422, superseding the navigation started at :298.
The file's own header diagram (:26-34) documents warmup as a mutually-exclusive third branch. The code contradicts it.
How it bites
A host follows docs/integration.md:107 and calls warmup(configuration:) at launch to "shave a couple of hundred milliseconds off the first load." What it gets instead is a full REST dependency fetch and asset download at launch, a progress view rendered into a view with no window, and a prewarm navigation cancelled by a second one — plus a second concurrent writer into the shared asset-bundle directory (#665).
warmup() retains the controller for 5 s via DispatchQueue.main.asyncAfter (:926-928), but the fetch task holds a strong self for as long as it runs, so the real lifetime is however long the fetch takes.
No caller in this repo, so it is latent rather than live.
Suggested fix
if isWarmupMode {
self.loadEditorWithoutDependencies()
return
}
Worth checking whether startUploadServer() should be reachable in warmup at all while there (it currently no-ops, since warmup sets neither handler).
Found while reviewing #651. Pre-existing and byte-identical in that PR's base; the removed cancellation never applied to warmup, since a warmup controller has no window and never receives viewDidDisappear.
EditorViewController.warmup(configuration:)is documented as loading the editor HTML without dependencies to prewarm WebKit. It does that, then falls through and does the full dependency fetch as well — ending in a second navigation that discards the prewarm it just performed.Detail
ios/Sources/GutenbergKit/Sources/EditorViewController.swift:297-299:No
return, noelse.warmup()(:921) constructs withisWarmupMode: trueand nodependencies, so theif let dependenciesat:323fails and execution continues into the ASYNC FLOW at:334. That runsprepareEditor()→ a live authenticated REST fetch plus the asset-bundle download →loadEditor(dependencies:)→ a secondwebView.loadFileURLat:422, superseding the navigation started at:298.The file's own header diagram (
:26-34) documents warmup as a mutually-exclusive third branch. The code contradicts it.How it bites
A host follows
docs/integration.md:107and callswarmup(configuration:)at launch to "shave a couple of hundred milliseconds off the first load." What it gets instead is a full REST dependency fetch and asset download at launch, a progress view rendered into a view with no window, and a prewarm navigation cancelled by a second one — plus a second concurrent writer into the shared asset-bundle directory (#665).warmup()retains the controller for 5 s viaDispatchQueue.main.asyncAfter(:926-928), but the fetch task holds a strongselffor as long as it runs, so the real lifetime is however long the fetch takes.No caller in this repo, so it is latent rather than live.
Suggested fix
Worth checking whether
startUploadServer()should be reachable in warmup at all while there (it currently no-ops, since warmup sets neither handler).Found while reviewing #651. Pre-existing and byte-identical in that PR's base; the removed cancellation never applied to warmup, since a warmup controller has no window and never receives
viewDidDisappear.