Skip to content

Add support for WASM deferred loading.#189308

Merged
biggs0125 merged 9 commits into
flutter:masterfrom
biggs0125:deferred-loading
Jul 15, 2026
Merged

Add support for WASM deferred loading.#189308
biggs0125 merged 9 commits into
flutter:masterfrom
biggs0125:deferred-loading

Conversation

@biggs0125

Copy link
Copy Markdown
Contributor

The dart2wasm compiler supports deferred loading now producing multiple wasm modules when deferred imports are present.

This change exposes wasm deferred loading for Flutter apps as well. It adds a few things:

  1. Add a --enable-wasm-deferred-loading flag that gets plumbed through to the compiler.
  2. Add a loader config entry that allows the user to specify custom module loading logic. Provide a default implementation that works for standard Flutter builds.
  3. Add tests for all of this code.

@flutter-dashboard flutter-dashboard Bot added the CICD Run CI/CD label Jul 11, 2026
@biggs0125
biggs0125 requested a review from harryterkelsen July 11, 2026 02:03
@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 Jul 11, 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 adds support for multi-module deferred loading in Dart2Wasm. It introduces a wasmDeferredModulesLoader configuration option, adds the --enable-wasm-deferred-loading flag to the web build command, and updates the build system to include deferred Wasm modules and their source maps. Unit tests are also added to verify these changes. Feedback recommends optimizing the default JavaScript loader to enable streaming compilation by passing the fetch promise directly, and hoisting regular expression instantiations out of the file-filtering loop in the build target to prevent performance overhead.

Comment thread engine/src/flutter/lib/web_ui/flutter_js/src/entrypoint_loader.js Outdated
Comment thread packages/flutter_tools/lib/src/build_system/targets/web.dart
Comment thread engine/src/flutter/lib/web_ui/test/engine/deferred_loader_test.dart
Comment thread engine/src/flutter/lib/web_ui/test/engine/deferred_loader_test.dart
Apply suggestions

Co-authored-by: Harry Terkelsen <[email protected]>
@biggs0125
biggs0125 requested a review from harryterkelsen July 13, 2026 21:35
Comment on lines +416 to +417
static final RegExp _partWasmRegex = RegExp(r'main\.dart_module[0-9].*\.wasm');
static final RegExp _partWasmMapRegex = RegExp(r'main\.dart_module[0-9].*\.wasm\.map');

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.

Since these regular expressions are not anchored, _partWasmRegex.hasMatch('main.dart_module1.wasm.map') will return true because the filename starts with main.dart_module1.wasm.

This means that when compilerConfig.sourceMaps is false, the .wasm.map files will still be incorrectly matched and included in buildFiles by the _partWasmRegex check.

We should anchor them with ^ and $ to prevent substring matches.

Suggested change
static final RegExp _partWasmRegex = RegExp(r'main\.dart_module[0-9].*\.wasm');
static final RegExp _partWasmMapRegex = RegExp(r'main\.dart_module[0-9].*\.wasm\.map');
static final RegExp _partWasmRegex = RegExp(r'^main\.dart_module[0-9].*\.wasm$');
static final RegExp _partWasmMapRegex = RegExp(r'^main\.dart_module[0-9].*\.wasm\.map$');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch, I updated the regexes, thanks!

@harryterkelsen harryterkelsen 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.

Thanks for the contribution! I've left a few inline comments on the JS loader options and test structure.

Additionally, I noticed a bug in packages/flutter_tools/lib/src/build_system/targets/web.dart where the regular expressions for matching dynamic modules were unanchored, causing .wasm.map files to be matched as .wasm files. This causes source map files to be included in the build output even when source maps are disabled. I left an inline suggestion to anchor them with ^ and $.

We should also add a test to packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart to verify this behavior and prevent regression:

  test('Dart2WasmTarget.buildFiles respects compilerConfig.sourceMaps and matches modules', () {
    final File wasmFile = environment.buildDir.childFile('main.dart.wasm')..createSync();
    final File mjsFile = environment.buildDir.childFile('main.dart.mjs')..createSync();
    final File mapFile = environment.buildDir.childFile('main.dart.wasm.map')..createSync();
    
    final File partWasmFile = environment.buildDir.childFile('main.dart_module1.wasm')..createSync();
    final File partMapFile = environment.buildDir.childFile('main.dart_module1.wasm.map')..createSync();

    final targetWithMaps = Dart2WasmTarget(const WasmCompilerConfig(sourceMaps: true), const NoOpAnalytics());
    expect(targetWithMaps.buildFiles(environment), containsAll(<File>[wasmFile, mjsFile, mapFile, partWasmFile, partMapFile]));

    final targetWithoutMaps = Dart2WasmTarget(const WasmCompilerConfig(sourceMaps: false), const NoOpAnalytics());
    expect(targetWithoutMaps.buildFiles(environment), containsAll(<File>[wasmFile, mjsFile, partWasmFile]));
    expect(targetWithoutMaps.buildFiles(environment), isNot(contains(mapFile)));
    expect(targetWithoutMaps.buildFiles(environment), isNot(contains(partMapFile)));
  });

@biggs0125
biggs0125 requested a review from harryterkelsen July 13, 2026 23:03
harryterkelsen
harryterkelsen previously approved these changes Jul 13, 2026

@harryterkelsen harryterkelsen 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

@flutter-dashboard

Copy link
Copy Markdown

CI had a failure that stopped further tests from running. We need to investigate to determine the root cause.

SHA at time of execution: b4e7870.

Possible causes:

  • Configuration Changes: The .ci.yaml file might have been modified between the creation of this pull request and the start of this test run. This can lead to ci yaml validation errors.
  • Infrastructure Issues: Problems with the CI environment itself (e.g., quota) could have caused the failure.

A blank commit, or merging to head, will be required to resume running CI for this PR.

Error Details:

GitHub Error: You have exceeded a secondary rate limit. Please wait a few minutes before you try again. For more on scraping GitHub and how it may affect your rights, please review our Terms of Service (https://docs.github.com/en/site-policy/github-terms/github-terms-of-service) If you reach out to GitHub Support for help, please include the request ID 9954:357F4E:9E85B:22311F:6A5587CC.

Stack trace:

#0      GitHub.handleStatusCode (package:github/src/common/github.dart:486:5)
#1      GitHub.request (package:github/src/common/github.dart:422:7)
<asynchronous suspension>
#2      GitHub.requestJson (package:github/src/common/github.dart:323:22)
<asynchronous suspension>
#3      RetryOptions.retry (package:retry/retry.dart:131:16)
<asynchronous suspension>
#4      LuciBuildService._scheduleTryBuilds (package:cocoon_service/src/service/luci_build_service.dart:322:26)
<asynchronous suspension>
#5      Scheduler._runCiTestingStage (package:cocoon_service/src/service/scheduler.dart:1466:7)
<asynchronous suspension>
#6      Scheduler.proceedToCiTestingStage (package:cocoon_service/src/service/scheduler.dart:1516:7)
<asynchronous suspension>
#7      Scheduler._closeSuccessfulEngineBuildStage (package:cocoon_service/src/service/scheduler.dart:1341:5)
<asynchronous suspension>
#8      Scheduler.processCheckRunCompleted (package:cocoon_service/src/service/scheduler.dart:1273:11)
<asynchronous suspension>
#9      PresubmitLuciSubscription.post (package:cocoon_service/src/request_handlers/presubmit_luci_subscription.dart:173:7)
<asynchronous suspension>
#10     RequestHandler.service (package:cocoon_service/src/request_handling/request_handler.dart:42:20)
<asynchronous suspension>
#11     SubscriptionHandler.service (package:cocoon_service/src/request_handling/subscription_handler.dart:134:5)
<asynchronous suspension>
#12     createServer.<anonymous closure> (package:cocoon_service/server.dart:448:7)
<asynchronous suspension>
#13     main.<anonymous closure>.<anonymous closure> (file:///app/app_dart/bin/gae_server.dart:187:9)
<asynchronous suspension>

@harryterkelsen harryterkelsen 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

@harryterkelsen harryterkelsen added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 14, 2026
@biggs0125
biggs0125 enabled auto-merge July 14, 2026 20:03
@biggs0125
biggs0125 added this pull request to the merge queue Jul 14, 2026
Merged via the queue into flutter:master with commit 80157ee Jul 15, 2026
195 of 196 checks passed
@biggs0125
biggs0125 deleted the deferred-loading branch July 15, 2026 00:47
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Jul 15, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Jul 15, 2026
flutter/flutter@846664b...fc1ad95

2026-07-15 [email protected] [iOS] Migrate FlutterKeyboardInsetManager to Swift (flutter/flutter#189425)
2026-07-15 [email protected] Roll Dart SDK from 05bf153370c4 to 0c408ff6dce9 (4 revisions) (flutter/flutter#189487)
2026-07-15 [email protected] Implement UberSDF lines to replace LineContents-based AA lines (flutter/flutter#188514)
2026-07-15 [email protected] Fix stale eagerWinner reference in GestureArenaManager when rejected before arena close (flutter/flutter#187008)
2026-07-15 [email protected] Disable some Windows tests that are flaking on CI (flutter/flutter#189477)
2026-07-15 dmgr Added unified check-run user manual (flutter/flutter#189453)
2026-07-15 [email protected] Roll Skia from 88954ef8f36d to ab2410bc857c (9 revisions) (flutter/flutter#189474)
2026-07-14 [email protected] [agents] Refactor shepherd-prs skill into a pure Markdown runbook using native gh CLI (flutter/flutter#189095)
2026-07-14 [email protected] Add missing name to mirroring workflow (flutter/flutter#189439)
2026-07-14 [email protected] Add support for WASM deferred loading. (flutter/flutter#189308)
2026-07-14 [email protected] fix `templateDefaultGradleVersion` todo (flutter/flutter#189466)
2026-07-14 [email protected] Roll Fuchsia Linux SDK from oOETA0ISPouDt2xBo... to lLFbh5kFWbUGgC9Ek... (flutter/flutter#189469)
2026-07-14 [email protected] Use ServicesBinding.instance.exitApplication instead of exit(0) in multiple_windows example (flutter/flutter#189364)
2026-07-14 [email protected] Add CpuArch to the Device class (flutter/flutter#189207)
2026-07-14 [email protected] Fix space formatting in cherry-pick label for flutter_cp.dart (flutter/flutter#189463)
2026-07-14 [email protected] Roll pub packages (flutter/flutter#189454)
2026-07-14 [email protected] [flutter_tools] Format plugin example template to match dart format (flutter/flutter#188382)
2026-07-14 [email protected] Move renamed x64->ARM benchmarks out of bringup (flutter/flutter#189400)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC [email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
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 tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants