Skip to content

refactor(web): use singular requestFileHandle() and stream Wasm through COS - #188010

Merged
auto-submit[bot] merged 16 commits into
flutter:masterfrom
tomayac:refactor/cos-singular-requestFileHandle
Sep 24, 2026
Merged

auto-submit[bot] merged 16 commits into
flutter:masterfrom
tomayac:refactor/cos-singular-requestFileHandle

Conversation

@tomayac

@tomayac tomayac commented Jun 15, 2026 •

Copy link
Copy Markdown
Contributor

Two changes to the Cross-Origin Storage (COS) path in instantiate_wasm.js.

1. Singular requestFileHandle()

Switches from the deprecated plural requestFileHandles([hash]) to the singular requestFileHandle(hash), which returns a FileSystemFileHandle directly rather than a single-element array, and updates the feature detection accordingly. The rename was adopted in the COS spec: WICG/cross-origin-storage#61

origins: '*' is passed on create. CanvasKit and Skwasm are the same bytes for every app built against a given engine revision, and without it the stored file is readable only by same-site origins, which is the one case where a shared cache buys nothing.

2. Stream the module instead of buffering it

The store path used to clone() the response, await .blob() on the clone, and write that Blob in a single write(). Nothing can be written until the last byte has arrived, and the whole module sits in memory first (5.4 MB for chromium/canvaskit.wasm, 3.6 MB for skwasm.wasm).

On a cache miss the body is now tee()d: one branch goes to WebAssembly.compileStreaming(), the other is piped into COS in the background. pipeTo() closes the writable stream once the body is exhausted, which is when the user agent verifies the bytes against the declared hash, so there is no explicit write()/close() to make. If the write cannot start (denied, quota exceeded, …) the store branch is canceled, otherwise tee() keeps buffering the whole module for a reader that will never read it.

On a cache hit the stored file is read as file.stream() rather than as a whole File. Both paths give the response a fixed Content-Type: application/wasm; COS verifies the bytes against the hash on write, so the stored MIME type is never consulted.

This is the shape the explainer recommends: https://github.com/WICG/cross-origin-storage#example-streaming-a-file-into-cos-while-using-it

Testing

Tested against the Cross-Origin Storage extension v0.1.25 in Chrome 156, with flutter create output built both ways and served from two ports so the second origin exercises a cross-origin COS hit. The bundled flutter.js was rebuilt from these sources with the same esbuild --bundle --minify step the engine's BUILD.gn runs.

COS available COS unavailable
flutter build web (CanvasKit) chromium/canvaskit.wasm stored on first load, served from COS on the second origin with no network request for it loads from the network, renders, no console errors
flutter build web --wasm (Skwasm) skwasm.wasm stored on first load, served from COS on the second origin with no network request for it loads from the network, renders, no console errors

All four combinations render the counter app and increment on tap.

Instrumenting WritableStream in the page shows the difference directly. Before, no tee() and one write() carrying a single 5,447,033-byte Blob. After, tee() called once and the same 5,447,033 bytes arriving as chunked writes: 3 when the module comes from the HTTP cache, 7 when it comes over the network.

Failure path: with a deliberately corrupted hash in wasmHashes, the write rejects with DataError on close, one warning is logged, nothing is left in COS, and the app still starts and is interactive, because the compile branch is independent of the store branch.

@flutter-dashboard

Copy link
Copy Markdown

It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group.

@github-actions github-actions Bot added engine flutter/engine related. See also e: labels. platform-web Web applications specifically team-web Owned by Web platform team labels Jun 15, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates the WASM instantiator to support Cross-Origin Storage (COS) by attempting to retrieve and cache WASM modules using their hashes. Feedback points out potential TypeError risks: one when checking filename.includes('/') if filename is undefined, and another when using the in operator on navigator.crossOriginStorage if it is null or undefined. Both issues can be resolved using optional chaining as suggested.

Comment thread engine/src/flutter/lib/web_ui/flutter_js/src/instantiate_wasm.js Outdated
Comment thread engine/src/flutter/lib/web_ui/flutter_js/src/instantiate_wasm.js Outdated
@kevmoo

kevmoo commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Looks like we need to do a rebase dance

@tomayac
tomayac force-pushed the refactor/cos-singular-requestFileHandle branch from ac9a210 to e3f3b0d Compare June 15, 2026 16:47
@tomayac

tomayac commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Thanks, @kevmoo. Rebased.

@kevmoo

kevmoo commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

When will there be a chrome version that supports this?

kevmoo
kevmoo previously approved these changes Jun 15, 2026
@kevmoo kevmoo added the autosubmit Merge PR when tree becomes green via auto submit App label Jun 15, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jun 15, 2026
@auto-submit

auto-submit Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/188010, because This PR has not met approval requirements for merging. The PR author is not a member of flutter-hackers and needs 1 more review(s) in order to merge this PR.

  • Merge guidelines: A PR needs at least one approved review if the author is already part of flutter-hackers or two member reviews if the author is not a member of flutter-hackers before re-applying the autosubmit label. Reviewers: If you left a comment approving, please use the "approve" review action instead.

@tomayac

tomayac commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

When will there be a chrome version that supports this?

I don't know, but there's a lot of work happening to make it happen ;-). You'll hear it first once it can be tested natively. For now, the extension was already updated so it accepts both variants, the singular (new) and the plural (old) version of the API, so we don't break any site.

mdebbar
mdebbar previously approved these changes Jun 16, 2026
@kevmoo

kevmoo commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Do we risk CRASHES in the overlap? That we certainly want to avoid. @tomayac

@tomayac

tomayac commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Do we risk CRASHES in the overlap? That we certainly want to avoid. @tomayac

Nope. I tested locally for both variants and it all worked fine. All tests are green.

@kevmoo kevmoo added the autosubmit Merge PR when tree becomes green via auto submit App label Jun 16, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jun 17, 2026
@auto-submit

auto-submit Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/188010, because - The status or check suite Google testing has failed. Please fix the issues identified (or deflake) before re-applying this label.

Replace the NotAllowedError / NotFoundError branches with a single
bare catch that silently falls through to the network fetch path.
This makes the code robust against any future renaming of the error
(see WICG/cross-origin-storage#62).
@tomayac
tomayac dismissed stale reviews from mdebbar and kevmoo via 9f4c303 June 18, 2026 15:49
mdebbar
mdebbar previously approved these changes Jun 24, 2026
@mdebbar mdebbar added the CICD Run CI/CD label Jun 24, 2026
yjbanov
yjbanov previously approved these changes Jun 24, 2026

@yjbanov yjbanov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lgtm

@tomayac
tomayac requested a review from yjbanov July 6, 2026 17:13
kevmoo
kevmoo previously approved these changes Jul 6, 2026
kevmoo and others added 4 commits July 7, 2026 22:17
On a cache miss, tee the network response body so one branch is compiled
as it arrives while the other is piped into COS, instead of buffering the
whole module into a Blob and writing it in one go. On a cache hit, read
the stored file as a stream rather than as a Blob.

`pipeTo()` closes the writable stream once the body is exhausted, which is
when the user agent verifies the bytes against the declared hash, so there
is no explicit `write()`/`close()` to make. The store branch is canceled
when the write cannot start, otherwise `tee()` keeps buffering the whole
module for a reader that will never read it.

This is the shape the explainer recommends:
https://github.com/WICG/cross-origin-storage#example-streaming-a-file-into-cos-while-using-it

Also restores the retrieval error messages that the previous commit
rewrote, since the rename did not require changing them.
@tomayac tomayac changed the title refactor(web): use singular crossOriginStorage.requestFileHandle() refactor(web): use singular requestFileHandle() and stream Wasm through COS Sep 23, 2026
The previous commit reverted the defensive `filename?.includes('/')`,
`navigator.crossOriginStorage?.requestFileHandle` and `err && err.name`
forms that earlier review feedback on this PR asked for. Restore them, so
that the streaming change is the only thing this commit series adds on top
of the rename.
@tomayac
tomayac requested review from kevmoo and mdebbar September 23, 2026 14:00
@kevmoo kevmoo added the CICD Run CI/CD label Sep 23, 2026
@kevmoo kevmoo added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 24, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Sep 24, 2026
@auto-submit

auto-submit Bot commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/flutter/188010, because This PR has not met approval requirements for merging. The PR author is not a member of flutter-hackers and needs 1 more review(s) in order to merge this PR.

  • Merge guidelines: A PR needs at least one approved review if the author is already part of flutter-hackers or two member reviews if the author is not a member of flutter-hackers before re-applying the autosubmit label. Reviewers: If you left a comment approving, please use the "approve" review action instead.

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

Labels

CICD Run CI/CD engine flutter/engine related. See also e: labels. platform-web Web applications specifically team-web Owned by Web platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants