From a3482f38f6e0bd2c63c79251319f5d1d31c107b0 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Wed, 3 Dec 2025 16:45:32 -0800 Subject: [PATCH 1/9] Plumbing changes required for DDC modules + hot reload, hidden behind a flag --- dwds/lib/src/loaders/ddc_library_bundle.dart | 8 - webdev/lib/src/command/build_command.dart | 3 +- webdev/lib/src/serve/dev_workflow.dart | 6 +- webdev/lib/src/serve/utils.dart | 24 +++ webdev/lib/src/serve/webdev_server.dart | 149 +++++++++++++++++-- webdev/pubspec.yaml | 15 ++ 6 files changed, 185 insertions(+), 20 deletions(-) diff --git a/dwds/lib/src/loaders/ddc_library_bundle.dart b/dwds/lib/src/loaders/ddc_library_bundle.dart index 58a0fc949..33d752579 100644 --- a/dwds/lib/src/loaders/ddc_library_bundle.dart +++ b/dwds/lib/src/loaders/ddc_library_bundle.dart @@ -2,8 +2,6 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -import 'dart:convert'; - import 'package:dwds/src/debugging/dart_runtime_debugger.dart'; import 'package:dwds/src/debugging/metadata/provider.dart'; import 'package:dwds/src/loaders/ddc.dart'; @@ -197,12 +195,6 @@ class DdcLibraryBundleStrategy extends LoadStrategy { }); return ''' $baseUrlScript -var scripts = ${const JsonEncoder.withIndent(" ").convert(scripts)}; -window.\$dartLoader.loadConfig.loadScriptFn = function(loader) { - loader.addScriptsToQueue(scripts, null); - loader.loadEnqueuedModules(); -}; -window.\$dartLoader.loader.nextAttempt(); '''; } diff --git a/webdev/lib/src/command/build_command.dart b/webdev/lib/src/command/build_command.dart index 7b68ffbf4..9a8a7c6f8 100644 --- a/webdev/lib/src/command/build_command.dart +++ b/webdev/lib/src/command/build_command.dart @@ -93,7 +93,8 @@ class BuildCommand extends Command { DefaultBuildTarget( (b) => b ..target = configuration.outputInput - ..outputLocation = outputLocation?.toBuilder(), + ..outputLocation = outputLocation?.toBuilder() + ..reportChangedAssets = true, ), ); client.startBuild(); diff --git a/webdev/lib/src/serve/dev_workflow.dart b/webdev/lib/src/serve/dev_workflow.dart index e950620f3..e7212eb6c 100644 --- a/webdev/lib/src/serve/dev_workflow.dart +++ b/webdev/lib/src/serve/dev_workflow.dart @@ -144,7 +144,8 @@ void _registerBuildTargets( DefaultBuildTarget( (b) => b ..target = target - ..outputLocation = outputLocation?.toBuilder(), + ..outputLocation = outputLocation?.toBuilder() + ..reportChangedAssets = true, ), ); } @@ -161,7 +162,8 @@ void _registerBuildTargets( DefaultBuildTarget( (b) => b ..target = '' - ..outputLocation = outputLocation.toBuilder(), + ..outputLocation = outputLocation.toBuilder() + ..reportChangedAssets = true, ), ); } diff --git a/webdev/lib/src/serve/utils.dart b/webdev/lib/src/serve/utils.dart index e6e062a67..7bde46c8c 100644 --- a/webdev/lib/src/serve/utils.dart +++ b/webdev/lib/src/serve/utils.dart @@ -106,3 +106,27 @@ String? findPackageConfigFilePath() { candidateDir = parentDir; } } + +/// Returns the absolute file path of the `package_config.json` file in the `.dart_tool` +/// directory, searching recursively from the current directory hierarchy. +Uri? findPackageConfigUri() { + var candidateDir = Directory(p.current).absolute; + + while (true) { + final candidatePackageConfigFile = File( + p.join(candidateDir.path, '.dart_tool', 'package_config.json'), + ); + + if (candidatePackageConfigFile.existsSync()) { + return candidatePackageConfigFile.uri; + } + + final parentDir = candidateDir.parent; + if (parentDir.path == candidateDir.path) { + // We've reached the root directory + return null; + } + + candidateDir = parentDir; + } +} diff --git a/webdev/lib/src/serve/webdev_server.dart b/webdev/lib/src/serve/webdev_server.dart index b1604d96c..228fd6073 100644 --- a/webdev/lib/src/serve/webdev_server.dart +++ b/webdev/lib/src/serve/webdev_server.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:async'; +import 'dart:convert'; import 'dart:io'; import 'package:build_daemon/data/build_status.dart' as daemon; @@ -10,6 +11,7 @@ import 'package:dds/devtools_server.dart'; import 'package:dwds/data/build_result.dart'; import 'package:dwds/dwds.dart'; import 'package:dwds/sdk_configuration.dart'; +import 'package:file/local.dart'; import 'package:http/http.dart' as http; import 'package:http/io_client.dart'; import 'package:http_multi_server/http_multi_server.dart'; @@ -21,10 +23,14 @@ import '../command/configuration.dart'; import '../util.dart'; import 'chrome.dart'; import 'handlers/favicon_handler.dart'; -import 'utils.dart' show findPackageConfigFilePath; +import 'utils.dart' show findPackageConfigFilePath, findPackageConfigUri; Logger _logger = Logger('WebDevServer'); +const reloadedSourcesFileName = 'reloaded_sources.json'; +const jsLibraryBundleExtension = '.ddc.js'; +const multiRootScheme = 'org-dartlang-app'; + class ServerOptions { final Configuration configuration; final int port; @@ -80,6 +86,7 @@ class WebDevServer { ServerOptions options, Stream buildResults, ) async { + final basePath = 'http://localhost:${options.port}'; var pipeline = const Pipeline(); if (options.configuration.logRequests) { @@ -88,8 +95,47 @@ class WebDevServer { pipeline = pipeline.addMiddleware(interceptFavicon); + /// JSON-ifiable list of sources that were reloaded in this restart and + /// follows the following format: + /// + /// `src`: A string that corresponds to the file path containing a DDC library + /// bundle. To support embedded libraries, the path should include the + /// `baseUri` of the web server. + /// `module`: The name of the library bundle in `src`. + /// `libraries`: An array of strings containing the libraries that were + /// compiled in `src`. + /// + /// For example: + /// ```json + /// [ + /// { + /// "src": "/", + /// "module": "", + /// "libraries": ["", ""], + /// }, + /// ] + /// ``` + /// + /// The path of the output file should stay consistent across the lifetime of + /// the app. + final reloadedSources = >[]; + // Only provide relevant build results final filteredBuildResults = buildResults.asyncMap((results) { + if (options.configuration.canaryFeatures) { + // Clear reloaded sources for the new build results. + reloadedSources.clear(); + results.changedAssets?.forEach((uri) { + if (uri.path.endsWith(jsLibraryBundleExtension)) { + final reloadedSource = { + 'src': ddcUriToSourceUrl(basePath, options.target, uri), + 'module': ddcUriToLibraryId(uri), + 'libraries': [ddcUriToLibraryId(uri)], + }; + reloadedSources.add(reloadedSource); + } + }); + } final result = results.results.firstWhere( (result) => result.target == options.target, ); @@ -132,20 +178,39 @@ class WebDevServer { // the load strategy? final buildSettings = BuildSettings( appEntrypoint: Uri.parse( - 'org-dartlang-app:///${options.target}/main.dart', + '$multiRootScheme:///${options.target}/main.dart', ), canaryFeatures: options.configuration.canaryFeatures, isFlutterApp: false, experiments: options.configuration.experiments, ); - final loadStrategy = BuildRunnerRequireStrategyProvider( - assetHandler, - options.configuration.reload, - assetReader, - buildSettings, - packageConfigPath: findPackageConfigFilePath(), - ).strategy; + final LoadStrategy loadStrategy; + if (options.configuration.canaryFeatures) { + final frontendServerFileSystem = LocalFileSystem(); + final packageUriMapper = await PackageUriMapper.create( + frontendServerFileSystem, + findPackageConfigUri()!, + useDebuggerModuleNames: false, + ); + loadStrategy = FrontendServerDdcLibraryBundleStrategyProvider( + options.configuration.reload, + assetReader, + packageUriMapper, + () async => {}, + buildSettings, + packageConfigPath: findPackageConfigFilePath(), + reloadedSourcesUri: Uri.parse('$basePath/$reloadedSourcesFileName'), + ).strategy; + } else { + loadStrategy = BuildRunnerRequireStrategyProvider( + assetHandler, + options.configuration.reload, + assetReader, + buildSettings, + packageConfigPath: findPackageConfigFilePath(), + ).strategy; + } if (options.configuration.enableExpressionEvaluation) { ddcService = ExpressionCompilerService( @@ -191,6 +256,18 @@ class WebDevServer { ); pipeline = pipeline.addMiddleware(dwds.middleware); cascade = cascade.add(dwds.handler); + if (options.configuration.canaryFeatures) { + // Add a handler to serve reloaded sources. + cascade = cascade.add((Request request) { + if (request.url.path == reloadedSourcesFileName) { + return Response.ok( + jsonEncode(reloadedSources), + headers: {'Content-Type': 'application/json'}, + ); + } + return Response.notFound(''); + }); + } cascade = cascade.add(assetHandler); } else { cascade = cascade.add(assetHandler); @@ -233,3 +310,57 @@ class WebDevServer { ); } } + +/// Transforms a package:build JS asset id [uri] into a source url compatible +/// with DDC's bootstrapper. +/// +/// [basePath] is the path from which JS files as served up to but not +/// including the path. +/// [target] is the path whose files will be served from [basePath]. +/// [uri] is the asset id's uri being transformed. +/// +/// Example: +/// basePath: http://localhost:8080 +/// target: web +/// +/// uri: asset:some_package/web/main.ddc.js +/// returns http://localhost:8080/main.ddc.js +/// +/// uri: package:some_package/src/sub_dir/file.ddc.js +/// returns http://localhost:8080/some_package/src/sub_dir/file.ddc.js +String ddcUriToSourceUrl(String basePath, String target, Uri uri) { + String jsPath; + if (uri.isScheme('asset')) { + // This indicates that this asset is the 'main' web asset. We directly + // serve all files under the package's [target] directory. + jsPath = uri.pathSegments.skip(1).join('/'); + } else if (uri.isScheme('package')) { + jsPath = 'packages/${uri.path}'; + } else { + jsPath = uri.path; + } + if (jsPath.startsWith(target)) { + jsPath = jsPath.substring(target.length); + } + return '$basePath/$jsPath'; +} + +/// Transforms a package:build JS asset id [uri] into a library id compatible +/// with DDC's bootstrapper. +/// +/// Example: +/// uri: asset:some_package/web/main.ddc.js +/// returns org-dartlang-app:///web/main.dart +/// +/// uri: package:some_package/src/sub_dir/file.ddc.js +/// returns package:some_package/src/sub_dir/file.dart +String ddcUriToLibraryId(Uri uri) { + final jsPath = uri.isScheme('package') + ? 'package:${uri.path}' + : '$multiRootScheme:///${uri.path}'; + final prefix = jsPath.substring( + 0, + jsPath.length - jsLibraryBundleExtension.length, + ); + return '$prefix.dart'; +} diff --git a/webdev/pubspec.yaml b/webdev/pubspec.yaml index 94e62e0dd..03a34c1a5 100644 --- a/webdev/pubspec.yaml +++ b/webdev/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: dds: ^4.1.0 # Pin DWDS to avoid dependency conflicts with vm_service: dwds: 24.3.11 + file: ^7.0.1 http: ^1.0.0 http_multi_server: ^3.2.0 io: ^1.0.3 @@ -53,5 +54,19 @@ dev_dependencies: test_process: ^2.0.2 webdriver: ^3.0.0 +dependency_overrides: + build_web_compilers: + path: /Users/markzipan/Projects/build/build_web_compilers + build_runner: + path: /Users/markzipan/Projects/build/build_runner + build_modules: + path: /Users/markzipan/Projects/build/build_modules + build: + path: /Users/markzipan/Projects/build/build + scratch_space: + path: /Users/markzipan/Projects/build/scratch_space + dwds: + path: /Users/markzipan/Projects/webdev/dwds + executables: webdev: From bd597ed66d1de30a4f08f03dd77f5297267e91da Mon Sep 17 00:00:00 2001 From: MarkZ Date: Wed, 3 Dec 2025 16:47:35 -0800 Subject: [PATCH 2/9] updating clogs --- dwds/CHANGELOG.md | 4 ++++ dwds/pubspec.yaml | 2 +- webdev/CHANGELOG.md | 4 ++++ webdev/pubspec.yaml | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index 814cfe500..eb3b9be26 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -1,3 +1,7 @@ +## 26.2.4-wip + +- Updating bootstrapper for DDC library bundler module format. + ## 26.2.3-wip - Bump `build_web_compilers` to ^4.4.1. diff --git a/dwds/pubspec.yaml b/dwds/pubspec.yaml index 4ef1378ca..a29118c5c 100644 --- a/dwds/pubspec.yaml +++ b/dwds/pubspec.yaml @@ -1,6 +1,6 @@ name: dwds # Every time this changes you need to run `dart run build_runner build`. -version: 26.2.3-wip +version: 26.2.4-wip description: >- A service that proxies between the Chrome debug protocol and the Dart VM diff --git a/webdev/CHANGELOG.md b/webdev/CHANGELOG.md index 52e8eef52..6f7aa961b 100644 --- a/webdev/CHANGELOG.md +++ b/webdev/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.8.1-wip + +- Adding initial DDC library bundler support behind the `canary` flag. + ## 3.8.0-wip - Bump minimum SDK constraint to 3.10.0 diff --git a/webdev/pubspec.yaml b/webdev/pubspec.yaml index 03a34c1a5..f2f32ec70 100644 --- a/webdev/pubspec.yaml +++ b/webdev/pubspec.yaml @@ -1,6 +1,6 @@ name: webdev # Every time this changes you need to run `dart run build_runner build`. -version: 3.8.0-wip +version: 3.8.1-wip # We should not depend on a dev SDK before publishing. # publish_to: none description: >- From 288c74e9ea0414e40d81ced719303b22cfb13293 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Wed, 3 Dec 2025 21:23:48 -0800 Subject: [PATCH 3/9] enabling hot reload on builders selectively --- webdev/lib/src/command/shared.dart | 18 ++++++++++++++++++ webdev/lib/src/serve/webdev_server.dart | 9 +++++---- webdev/lib/src/version.dart | 2 +- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/webdev/lib/src/command/shared.dart b/webdev/lib/src/command/shared.dart index b6c9f9f4d..132009c7a 100644 --- a/webdev/lib/src/command/shared.dart +++ b/webdev/lib/src/command/shared.dart @@ -126,6 +126,24 @@ List buildRunnerArgs(Configuration configuration) { arguments.add('--enable-experiment=$experiment'); } + if (configuration.canaryFeatures) { + arguments + ..add('--define') + ..add('build_web_compilers|sdk_js=web-hot-reload=true'); + arguments + ..add('--define') + ..add('build_web_compilers|entrypoint=web-hot-reload=true'); + arguments + ..add('--define') + ..add('build_web_compilers|entrypoint_marker=web-hot-reload=true'); + arguments + ..add('--define') + ..add('build_web_compilers|ddc=web-hot-reload=true'); + arguments + ..add('--define') + ..add('build_web_compilers|ddc_modules=web-hot-reload=true'); + } + return arguments; } diff --git a/webdev/lib/src/serve/webdev_server.dart b/webdev/lib/src/serve/webdev_server.dart index 228fd6073..18fb823bc 100644 --- a/webdev/lib/src/serve/webdev_server.dart +++ b/webdev/lib/src/serve/webdev_server.dart @@ -333,15 +333,16 @@ String ddcUriToSourceUrl(String basePath, String target, Uri uri) { if (uri.isScheme('asset')) { // This indicates that this asset is the 'main' web asset. We directly // serve all files under the package's [target] directory. - jsPath = uri.pathSegments.skip(1).join('/'); + var pathParts = uri.pathSegments.skip(1); + if (pathParts.first == target) { + pathParts = pathParts.skip(1); + } + jsPath = pathParts.join('/'); } else if (uri.isScheme('package')) { jsPath = 'packages/${uri.path}'; } else { jsPath = uri.path; } - if (jsPath.startsWith(target)) { - jsPath = jsPath.substring(target.length); - } return '$basePath/$jsPath'; } diff --git a/webdev/lib/src/version.dart b/webdev/lib/src/version.dart index f0d3ee90c..c65a75c91 100644 --- a/webdev/lib/src/version.dart +++ b/webdev/lib/src/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '3.8.0-wip'; +const packageVersion = '3.8.1-wip'; From 7781824a81f5dbfb52a700bd73aca83bc87d40eb Mon Sep 17 00:00:00 2001 From: MarkZ Date: Wed, 3 Dec 2025 21:46:54 -0800 Subject: [PATCH 4/9] updating ver --- dwds/lib/src/version.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwds/lib/src/version.dart b/dwds/lib/src/version.dart index 5c9bb9079..4d9545f40 100644 --- a/dwds/lib/src/version.dart +++ b/dwds/lib/src/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '26.2.3-wip'; +const packageVersion = '26.2.4-wip'; From 651ed198fdefb6dee628f937f12a46c2306fc537 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Thu, 4 Dec 2025 10:39:50 -0800 Subject: [PATCH 5/9] removing debug code --- webdev/pubspec.yaml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/webdev/pubspec.yaml b/webdev/pubspec.yaml index f2f32ec70..88e9868b2 100644 --- a/webdev/pubspec.yaml +++ b/webdev/pubspec.yaml @@ -54,19 +54,5 @@ dev_dependencies: test_process: ^2.0.2 webdriver: ^3.0.0 -dependency_overrides: - build_web_compilers: - path: /Users/markzipan/Projects/build/build_web_compilers - build_runner: - path: /Users/markzipan/Projects/build/build_runner - build_modules: - path: /Users/markzipan/Projects/build/build_modules - build: - path: /Users/markzipan/Projects/build/build - scratch_space: - path: /Users/markzipan/Projects/build/scratch_space - dwds: - path: /Users/markzipan/Projects/webdev/dwds - executables: webdev: From df25ba7bd9c4def5d1a3908bb51440c953405ada Mon Sep 17 00:00:00 2001 From: MarkZ Date: Thu, 4 Dec 2025 10:41:32 -0800 Subject: [PATCH 6/9] updating ver --- dwds/CHANGELOG.md | 5 +---- dwds/lib/src/version.dart | 2 +- dwds/pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index eb3b9be26..d0bc1447a 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -1,12 +1,9 @@ -## 26.2.4-wip - -- Updating bootstrapper for DDC library bundler module format. - ## 26.2.3-wip - Bump `build_web_compilers` to ^4.4.1. - Remove unused `clientFuture` arg from `DwdsVmClient` methods. - Fix pausing starting of `main` after the hot restart. +- Updating bootstrapper for DDC library bundler module format. ## 26.2.2 diff --git a/dwds/lib/src/version.dart b/dwds/lib/src/version.dart index 4d9545f40..5c9bb9079 100644 --- a/dwds/lib/src/version.dart +++ b/dwds/lib/src/version.dart @@ -1,2 +1,2 @@ // Generated code. Do not modify. -const packageVersion = '26.2.4-wip'; +const packageVersion = '26.2.3-wip'; diff --git a/dwds/pubspec.yaml b/dwds/pubspec.yaml index a29118c5c..4ef1378ca 100644 --- a/dwds/pubspec.yaml +++ b/dwds/pubspec.yaml @@ -1,6 +1,6 @@ name: dwds # Every time this changes you need to run `dart run build_runner build`. -version: 26.2.4-wip +version: 26.2.3-wip description: >- A service that proxies between the Chrome debug protocol and the Dart VM From 663f7d5171e7461ec907e04a15fe80332291fc63 Mon Sep 17 00:00:00 2001 From: MarkZ Date: Thu, 4 Dec 2025 10:48:05 -0800 Subject: [PATCH 7/9] bumping dwds dep ver for webdev --- webdev/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webdev/pubspec.yaml b/webdev/pubspec.yaml index 88e9868b2..9f429dad0 100644 --- a/webdev/pubspec.yaml +++ b/webdev/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: crypto: ^3.0.2 dds: ^4.1.0 # Pin DWDS to avoid dependency conflicts with vm_service: - dwds: 24.3.11 + dwds: ^25.0.0 file: ^7.0.1 http: ^1.0.0 http_multi_server: ^3.2.0 From ec75f7c2bae249c5e8b80ff3fdbd02f9280b120e Mon Sep 17 00:00:00 2001 From: MarkZ Date: Thu, 4 Dec 2025 11:48:24 -0800 Subject: [PATCH 8/9] adding deprecated member tags --- webdev/lib/src/serve/webdev_server.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/webdev/lib/src/serve/webdev_server.dart b/webdev/lib/src/serve/webdev_server.dart index 18fb823bc..91cf9d595 100644 --- a/webdev/lib/src/serve/webdev_server.dart +++ b/webdev/lib/src/serve/webdev_server.dart @@ -226,8 +226,10 @@ class WebDevServer { final debugSettings = DebugSettings( enableDebugExtension: options.configuration.debugExtension, enableDebugging: options.configuration.debug, + // ignore: deprecated_member_use spawnDds: !options.configuration.disableDds, expressionCompiler: ddcService, + // ignore: deprecated_member_use devToolsLauncher: shouldServeDevTools ? (String hostname) async { final server = await DevToolsServer().serveDevTools( From 2b010391d65b91d63922c7f2ade9be93302763ef Mon Sep 17 00:00:00 2001 From: MarkZ Date: Thu, 4 Dec 2025 15:55:10 -0800 Subject: [PATCH 9/9] Adding canary behavior to dwds bootstrapper --- dwds/CHANGELOG.md | 2 +- dwds/lib/src/loaders/ddc_library_bundle.dart | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/dwds/CHANGELOG.md b/dwds/CHANGELOG.md index d0bc1447a..a98ce7a95 100644 --- a/dwds/CHANGELOG.md +++ b/dwds/CHANGELOG.md @@ -3,7 +3,7 @@ - Bump `build_web_compilers` to ^4.4.1. - Remove unused `clientFuture` arg from `DwdsVmClient` methods. - Fix pausing starting of `main` after the hot restart. -- Updating bootstrapper for DDC library bundler module format. +- Updating bootstrapper for DDC library bundler module format + Frontend Server. ## 26.2.2 diff --git a/dwds/lib/src/loaders/ddc_library_bundle.dart b/dwds/lib/src/loaders/ddc_library_bundle.dart index 33d752579..bfe74b88e 100644 --- a/dwds/lib/src/loaders/ddc_library_bundle.dart +++ b/dwds/lib/src/loaders/ddc_library_bundle.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'dart:convert'; + import 'package:dwds/src/debugging/dart_runtime_debugger.dart'; import 'package:dwds/src/debugging/metadata/provider.dart'; import 'package:dwds/src/loaders/ddc.dart'; @@ -193,9 +195,19 @@ class DdcLibraryBundleStrategy extends LoadStrategy { modulePaths.forEach((name, path) { scripts.add({'src': '$path.js', 'id': name}); }); - return ''' -$baseUrlScript -'''; + // canary-mode uses the Frontend Server, which begins script loads via a + // separate pathway. + final scriptLoader = buildSettings.canaryFeatures + ? ''' +var scripts = ${const JsonEncoder.withIndent(" ").convert(scripts)}; +window.\$dartLoader.loadConfig.loadScriptFn = function(loader) { + loader.addScriptsToQueue(scripts, null); + loader.loadEnqueuedModules(); +}; +window.\$dartLoader.loader.nextAttempt(); +''' + : ''; + return '$baseUrlScript\n$scriptLoader'; } @override