Repository navigation
fix: honour --no-web-resources-cdn instead of probing the CDN - #24
Merged
mike-doctorina merged 2 commits intoOct 29, 2026
Merged
Conversation
`flutter build web --no-web-resources-cdn` records its choice as "useLocalCanvasKit": true in _flutter.buildConfig, but the generator dropped it and the bootstrap always tried Google's CDN first. On every load it sent a cache: "no-store" Range request for the variant's .js to gstatic.com, a network round trip that returning visitors paid too and that ran before the engine download could start, then loaded the engine from the CDN whenever that answered. Where gstatic.com is blocked or slow the probe could hold the loading screen for up to two 8 s timeouts. The canvaskit/ files the app chose to serve were never used, so the service worker never cached them either. - extractFlutterBuildInfo reads useLocalCanvasKit (false when absent), and injectBootstrapConfig passes it to the bootstrap config only when it is true, so output for other builds is unchanged. The generator's summary reports which source the bootstrap will use. - loadCanvasKit returns the local canvaskit/ path straight away when the flag is set, and the pipeline passes it in. Builds without the flag keep the CDN-first behaviour. The variant in use is cached lazily on first load, like any other Optional file. - bootstrap_template.dart is regenerated with npm run build:all. - README, docs/architecture.md, docs/bootstrap-pipeline.md, CLAUDE.md and the categoriser's comment describe the local path; CHANGELOG has an Unreleased entry. Tests: Vitest covers loadCanvasKit making no request with the flag and the pipeline passing true, and false when the config omits it; all three fail without the fix. Dart covers parsing, the default, emitting the flag only when true, and an integration check that bootstrap.js carries whatever the example's flutter_bootstrap.js recorded, so it holds for builds with and without the flag. Checked in Chromium 152 against the same --no-web-resources-cdn example build: 0.2.0 sent the one-byte gstatic.com probe and loaded canvaskit.js and canvaskit.wasm from the CDN; with the fix there is no gstatic.com request and both load from canvaskit/.
For the canvaskit renderer, cleanup's keep-set kept canvaskit/chromium/canvaskit.wasm but pruned canvaskit/chromium/canvaskit.js. getCanvasKitVariant loads that pair on Chromium-class browsers. While the engine always came from the CDN the missing half went unnoticed, but with useLocalCanvasKit the bootstrap loads it from canvaskit/, where the script is gone; on hosts with an SPA rewrite the request is answered with index.html and the app never starts. The keep-set now lists both files of the Chromium variant. Tests: a generate() test over a synthetic canvaskit build checks that both files of the standard and Chromium variants survive cleanup and a file no variant uses is pruned; it fails without the fix. Upstream's Playwright suite passes (17) against the example built with and without --no-web-resources-cdn; with the local build and the keep-set unfixed, "page loads without errors" and the wedged-queue boot test failed on the missing script.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What happened
An app built with
flutter build web --no-web-resources-cdnstill loaded its engine from Google's CDN. Every load, returning visits included, began with acache: "no-store"Range: bytes=0-0request towww.gstatic.com/flutter-canvaskit/<engineRevision>/<variant>.jsbefore the engine download could start (175 ms in a production trace), and the engine then came from gstatic anyway. Thecanvaskit/files the build deploys were never requested, so the service worker never cached them.Root cause
Flutter records the flag as
"useLocalCanvasKit": truein_flutter.buildConfig.extractFlutterBuildInfoonly readengineRevisionandbuilds, so the flag never reachedbootstrap.js, andloadCanvasKitalways probes the CDN when an engine revision is present. Because the probe isno-store, it is a network round trip on every load, and wheregstatic.comis blocked or slow it can hold the loading screen for up to two 8 s attempts before falling back. The repo's own example is affected:CONTRIBUTING.mdbuilds it with--no-web-resources-cdn.Serving the engine locally exposed a second, latent problem. For the
canvaskitrenderer, cleanup's keep-set keptcanvaskit/chromium/canvaskit.wasmbut prunedcanvaskit/chromium/canvaskit.js, the pairgetCanvasKitVariantloads on Chromium-class browsers. While the engine came from the CDN the missing half went unnoticed; loaded locally, the script is gone, and on hosts with an SPA rewrite the request is answered withindex.htmland the app never starts.The fix
FlutterBuildInfo.useLocalCanvasKit, parsed frombuildConfig(false when absent).injectBootstrapConfigemits"useLocalCanvasKit": trueonly when set, so output for CDN builds is byte-identical. The generator's summary prints which source the bootstrap will use.BuildConfig.useLocalCanvasKit?;loadCanvasKitreturnscanvaskit/straight away when it is set, and the pipeline passes it in. CDN-first behaviour is unchanged for every other build.canvaskitrenderer's keep-set lists both files of the Chromium variant.Optional, so in a local build the one variant the browser picks is cached on first load.bootstrap_template.dartregenerated withnpm run build:all; README,docs/architecture.md,docs/bootstrap-pipeline.md,CLAUDE.mdand the categoriser comment describe the local path; CHANGELOG entry under Unreleased.Verification
generate()test over a synthetic CanvasKit build fails without the keep-set fix; the new integration test comparesbootstrap.jswith whatever the example'sflutter_bootstrap.jsrecorded, so it holds for builds with and without the flag.--no-web-resources-cdn. With the local build and the keep-set unfixed, "page loads without errors" and the wedged-queue boot test fail on the missingchromium/canvaskit.js.npm run verify: committed Dart assets match the build output.--no-web-resources-cdn: before, the one-byte probe and thencanvaskit.jsandcanvaskit.wasmfrom gstatic; after, no gstatic request, both fromcanvaskit/.swpinned to this branch: the bootstrap logsUsing local: canvaskit/ (built with --no-web-resources-cdn), no request goes to gstatic, and the engine loads from the origin and then from the service worker's cache on later loads.