Skip to content

feat(web): resolve raw asset keys via content-hashed manifests and unhide --web-content-hash - #193040

Merged
auto-submit[bot] merged 10 commits into
flutter:masterfrom
kevmoo:web-content-hash-phase-2-5
Sep 23, 2026
Merged

auto-submit[bot] merged 10 commits into
flutter:masterfrom
kevmoo:web-content-hash-phase-2-5

Conversation

@kevmoo

@kevmoo kevmoo commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Description

Completes the --web-content-hash architecture by adding runtime raw-key asset resolution in web_ui, achieving 100% content-hashing coverage across all files in build/web/assets/ (eliminating manifest and shader exclusions), preserving AssetManifest.listAssets() and AssetMetadata.main, validating custom web/flutter_bootstrap.js / web/index.html templates, and un-hiding --web-content-hash (--no-web-content-hash) in flutter build web --help.

Why this is needed

Phase 2 (#191919) and Phase 3 (#192953) renamed physical asset files on disk (<name>.<hash>.<ext>), rewrote target values inside AssetManifest.bin, AssetManifest.bin.json, AssetManifest.json, and FontManifest.json, and emitted precache_manifest.json. Two critical gaps remained before exposing --web-content-hash to users:

  1. Cold-cache 404s on raw-key asset requests:
    • While Image.asset resolves variant paths via AssetManifest before calling rootBundle.load(variant.key), direct callers of rootBundle.load(key) / rootBundle.loadString(key) (PlatformAssetBundle) and third-party web plugins (vector_graphics / flutter_svg AssetBytesLoader, lottie, rive, video_player_web, audioplayers_web) pass the raw declared key (assets/data/config.json) directly to ui_web.AssetManager.getAssetUrl(String asset).
    • Without runtime key translation in ui_web.AssetManager.getAssetUrl(asset), raw-key asset fetches requested un-hashed paths (assets/assets/data/config.json) and 404'd on cold caches.
  2. Un-hashed manifest and shader files under build/web/assets/:
    • AssetManifest.*, FontManifest.json, NOTICES, NOTICES.Z, and shaders/** were previously excluded from hashing, which meant a single "source": "assets/**" -> Cache-Control: public, max-age=31536000, immutable CDN rule would freeze AssetManifest.bin.json and FontManifest.json across deployments (v1 -> v2).

What this PR changes

  1. 100% build/web/assets/ Immutability & Clean AssetManifest.listAssets() (packages/flutter_tools/lib/src/web/content_hash.dart):
    • Removes _excludedFilenames and _excludedDirPrefixes so every file under build/web/assets/ (including shaders/**, NOTICES, NOTICES.Z, FontManifest.json, AssetManifest.json, AssetManifest.bin, and AssetManifest.bin.json) is content-hashed on disk.
    • Keeps AssetManifest.bin and AssetManifest.json strictly limited to user/package manifest entries (storing Uri.decodeFull variant paths so Image.asset on spaced filenames encodes cleanly to %2520 rather than triple-encoding to %252520), and passes non-manifest SDK files (NOTICES, shaders/ink_sparkle.frag, shaders/stretch_effect.frag, AssetManifest.bin, AssetManifest.json) via _flutter.buildConfig.extraAssets (~200 bytes) alongside "assetManifest" and "fontManifest".
    • Sorts discovered asset paths deterministically before manifest assembly so incremental and clean builds emit identical manifest hashes.
    • Fails fast (throwToolExit) if custom web/flutter_bootstrap.js or web/index.html templates omit {{flutter_build_config}} or contain malformed _flutter.buildConfig assignments.
  2. Preserve AssetMetadata.main (packages/flutter/lib/src/services/asset_manifest.dart):
    • Updates _AssetManifestBin (asset_manifest.dart) so AssetMetadata.main remains true for the primary 1.0x asset variant when content hashes are embedded in variant filenames.
  3. Incremental Build .filecache Tracking (packages/flutter_tools/lib/src/build_system/targets/web.dart):
    • Declares {OUTPUT_DIR}/*/index.html and {OUTPUT_DIR}/flutter_bootstrap.js in WebReleaseBundle.inputs and WebReleaseBundle.outputs when webContentHash is enabled so .filecache records post-injection file hashes.
  4. Synchronous Engine-Private Runtime Key Translation (web_ui):
    • Extends FlutterJS with JSBuildConfig (assetManifest, fontManifest, extraAssets) in js_loader.dart.
    • Updates fetchFontManifest in fonts.dart to fetch flutter?.buildConfig?.fontManifest?.toDart ?? 'FontManifest.json'.
    • Adds _loadContentHashedAssetManifest(ui_web.assetManager) inside initializeEngineServices() Future.wait in initialization.dart to register assetManifest, fontManifest, extraAssets, and decoded AssetManifest.bin.<hash>.json mappings in engine-private setContentHashedAssetMap / resolveContentHashedAsset (keeping the public dart:ui_web AssetManager API unchanged).
    • Resolves logical keys and variant paths synchronously inside ui_web.AssetManager.getAssetUrl(String asset).
  5. Un-hide --web-content-hash (packages/flutter_tools/lib/src/web/web_options.dart & build_web.dart):
    • Removes hide: true from WebOptions.webContentHash and notes that local canvaskit/** (--no-web-resources-cdn) remains un-hashed (urlHashed: false in precache_manifest.json).

Related Issues

Tests

  • packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart
  • packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart & args_test.dart
  • packages/flutter/test/services/asset_manifest_test.dart
  • engine/src/flutter/lib/web_ui/test/engine/assets_test.dart

Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I signed the [CLA].
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is [test-exempt].
  • All existing and new tests are passing.

…bled

- Emit build/web/precache_manifest.json in WebServiceWorker when --web-content-hash is enabled, providing deterministic URL, SHA-256 prefix hash, byte size, and urlHashed metadata for custom service workers and PWAs.

- Filter non-runtime build artifacts (*.map, *.symbols, *.info.json, dotfiles, flutter_service_worker.js, precache_manifest.json, and canvaskit/** when --web-resources-cdn is active).

- Clean up stale precache_manifest.json when --web-content-hash is disabled and prevent Depfile input/output cycles.

- Keep --web-content-hash hidden while runtime raw-key asset resolution (rootBundle.load) is completed.

Fixes flutter#191916

Part of flutter#149031
…hide --web-content-hash

- Content-hash all remaining unhashed files under build/web/assets/ (FontManifest.json, AssetManifest.json, AssetManifest.bin, AssetManifest.bin.json, NOTICES, NOTICES.Z, and shaders/**) in Pass 2 of hashWebAssets.
- Inject hashed assetManifest and fontManifest filenames into _flutter.buildConfig in flutter_bootstrap.js and index.html.
- Add JSBuildConfig (assetManifest, fontManifest) to JS interop and update fetchFontManifest in web_ui to read _flutter.buildConfig.fontManifest.
- Populate ui_web.AssetManager with the content-hashed asset map during initializeEngineServices so raw logical asset keys (rootBundle.load, FragmentProgram.fromAsset, HtmlElementView, custom fetch(assetManager.getAssetUrl(...))) resolve to content-hashed filenames.
- Unhide the --web-content-hash CLI flag in flutter build web.

Fixes flutter#193031
@github-actions github-actions Bot added tool Affects the "flutter" command-line tool. See also t: labels. engine flutter/engine related. See also e: labels. platform-web Web applications specifically team-web Owned by Web platform team labels Sep 19, 2026
@github-actions github-actions Bot added the framework flutter/packages/flutter repository. See also f: labels. label Sep 19, 2026
…ase-2-5

# Conflicts:
#	packages/flutter_tools/lib/src/web/web_options.dart
#	packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart
@kevmoo
kevmoo marked this pull request as ready for review September 21, 2026 18:04

@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 implements runtime asset resolution for web content hashing in Flutter. It updates the web engine to load content-hashed manifests and extra assets from _flutter.buildConfig, and modifies flutter_tools to inject these hashed filenames during release builds. Feedback on the changes suggests supporting single quotes and backticks when parsing JavaScript string literals in _findMatchingClosingBrace, updating the glob patterns in WebReleaseBundle to match the root index.html file, and optimizing JSON decoding in the engine by fusing the UTF-8 and JSON decoders to avoid intermediate string allocations.

Comment thread packages/flutter_tools/lib/src/web/content_hash.dart
Comment thread packages/flutter_tools/lib/src/build_system/targets/web.dart Outdated
Comment thread packages/flutter_tools/lib/src/build_system/targets/web.dart Outdated
Comment thread engine/src/flutter/lib/web_ui/lib/src/engine/initialization.dart Outdated
mdebbar
mdebbar previously approved these changes Sep 22, 2026
…t on deferred wasm modules with --web-content-hash
@kevmoo

kevmoo commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

@mdebbar one more nod, please!

@kevmoo kevmoo added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 22, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Sep 22, 2026
Merged via the queue into flutter:master with commit 66a0e30 Sep 23, 2026
23 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Sep 23, 2026
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. framework flutter/packages/flutter repository. See also f: labels. platform-web Web applications specifically team-web Owned by Web platform team tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

2 participants