Skip to content

Commit 8bce65a

Browse files
committed
Merge branch 'main' into websocketproxyservice
2 parents 4937508 + e95af5f commit 8bce65a

17 files changed

+250
-147
lines changed

dwds/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
- Implemented a WebSocket-based communication protocol that provides essential developer tooling (hot reload, service extensions) when Chrome debugger access is unavailable. - [#2605](https://github.com/dart-lang/webdev/issues/2605)
44
- Added WebSocket-based hot reload and service extension support via new `WebSocketProxyService` class that implements VM service protocol over WebSockets.
55
- Enhanced `DevHandler` with `useWebSocketConnection` flag to toggle between Chrome-based and WebSocket-based communication protocols.
6+
- Fixed an issue where we didn't wait until all scripts were parsed before
7+
recomputing metadata on a hot reload.
68

79
## 24.4.0
810

dwds/lib/src/debugging/debugger.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ class Debugger extends Domain {
5656

5757
int _frameErrorCount = 0;
5858

59+
final StreamController<String> parsedScriptsController =
60+
StreamController.broadcast();
61+
5962
Debugger._(
6063
this._remoteDebugger,
6164
this._streamNotify,
@@ -489,6 +492,9 @@ class Debugger extends Domain {
489492
final scriptPath = _pathForChromeScript(e.script.url);
490493
if (scriptPath != null) {
491494
chromePathToRuntimeScriptId[scriptPath] = e.script.scriptId;
495+
if (parsedScriptsController.hasListener) {
496+
parsedScriptsController.sink.add(e.script.url);
497+
}
492498
}
493499
}
494500

dwds/lib/src/debugging/modules.dart

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,6 @@ class Modules {
9898
) async {
9999
final serverPath = await globalToolConfiguration.loadStrategy
100100
.serverPathForModule(entrypoint, module);
101-
// TODO(srujzs): We should wait until all scripts are parsed before
102-
// accessing after a hot reload. See
103-
// https://github.com/dart-lang/webdev/issues/2640.
104101
return chromePathToRuntimeScriptId[serverPath];
105102
}
106103

dwds/lib/src/injected/client.js

Lines changed: 11 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dwds/lib/src/loaders/ddc_library_bundle.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,16 @@ class DdcLibraryBundleStrategy extends LoadStrategy {
110110
/// ```json
111111
/// [
112112
/// {
113-
/// "src": "<file_name>",
113+
/// "src": "<base_uri>/<file_name>",
114+
/// "module": "<module_name>",
114115
/// "libraries": ["<lib1>", "<lib2>"],
115116
/// },
116117
/// ]
117118
/// ```
118119
///
119120
/// `src`: A string that corresponds to the file path containing a DDC library
120121
/// bundle.
122+
/// `module`: The name of the library bundle in `src`.
121123
/// `libraries`: An array of strings containing the libraries that were
122124
/// compiled in `src`.
123125
///

dwds/lib/src/services/chrome_proxy_service.dart

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,15 +1068,42 @@ class ChromeProxyService extends ProxyService {
10681068
Future<void> _performClientSideHotReload(String isolateId) async {
10691069
_logger.info('Attempting a hot reload');
10701070

1071+
final debugger = await debuggerFuture;
1072+
final reloadedSrcs = <String>{};
1073+
final computedReloadedSrcs = Completer<void>();
1074+
final parsedAllReloadedSrcs = Completer<void>();
1075+
// Wait until all the reloaded scripts are parsed before we reinitialize
1076+
// metadata below.
1077+
final parsedScriptsSubscription = debugger.parsedScriptsController.stream
1078+
.listen((url) {
1079+
computedReloadedSrcs.future.then((_) {
1080+
reloadedSrcs.remove(Uri.parse(url).normalizePath().path);
1081+
if (reloadedSrcs.isEmpty) {
1082+
parsedAllReloadedSrcs.complete();
1083+
}
1084+
});
1085+
});
1086+
10711087
// Initiate a hot reload.
10721088
_logger.info('Issuing \$dartHotReloadStartDwds request');
10731089
final remoteObject = await inspector.jsEvaluate(
10741090
'\$dartHotReloadStartDwds();',
10751091
awaitPromise: true,
10761092
returnByValue: true,
10771093
);
1078-
final reloadedModulesToLibraries =
1079-
(remoteObject.value as Map).cast<String, List>();
1094+
final reloadedSrcModuleLibraries = (remoteObject.value as List).cast<Map>();
1095+
final reloadedModulesToLibraries = <String, List<String>>{};
1096+
for (final srcModuleLibrary in reloadedSrcModuleLibraries) {
1097+
final srcModuleLibraryCast = srcModuleLibrary.cast<String, Object>();
1098+
reloadedSrcs.add(
1099+
Uri.parse(srcModuleLibraryCast['src'] as String).normalizePath().path,
1100+
);
1101+
reloadedModulesToLibraries[srcModuleLibraryCast['module'] as String] =
1102+
(srcModuleLibraryCast['libraries'] as List).cast<String>();
1103+
}
1104+
computedReloadedSrcs.complete();
1105+
if (reloadedSrcs.isNotEmpty) await parsedAllReloadedSrcs.future;
1106+
await parsedScriptsSubscription.cancel();
10801107

10811108
if (!pauseIsolatesOnStart) {
10821109
// Finish hot reload immediately.

dwds/test/common/chrome_proxy_service_common.dart

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2225,27 +2225,6 @@ void runTests({
22252225
);
22262226
});
22272227

2228-
test('reloadSources', () async {
2229-
final service = context.service;
2230-
final vm = await service.getVM();
2231-
final isolateId = vm.isolates!.first.id!;
2232-
final report = await service.reloadSources(isolateId);
2233-
// TODO(srujzs): This naturally fails regardless of the module format
2234-
// because we didn't set up prerequisite state (the reload scripts). We
2235-
// should create new tests for hot reload within DWDS and remove this
2236-
// test.
2237-
expect(report.success, false);
2238-
// Make sure that a notice was provided in the expected format.
2239-
final notices = report.json?['notices'];
2240-
expect(notices, isNotNull);
2241-
expect(notices is List, isTrue);
2242-
final noticeList = (notices as List).cast<Map>();
2243-
expect(noticeList, isNotEmpty);
2244-
final message = noticeList[0]['message'];
2245-
expect(message, isNotNull);
2246-
expect(message is String && message.isNotEmpty, isTrue);
2247-
});
2248-
22492228
test('setIsolatePauseMode', () async {
22502229
final service = context.service;
22512230
final vm = await service.getVM();

dwds/test/fixtures/context.dart

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -339,11 +339,9 @@ class TestContext {
339339
_hostname = appMetadata.hostname;
340340
await webRunner.run(
341341
frontendServerFileSystem,
342-
_hostname,
343-
assetServerPort,
344-
filePathToServe,
345-
initialCompile: true,
346-
fullRestart: false,
342+
hostname: _hostname,
343+
port: assetServerPort,
344+
index: filePathToServe,
347345
);
348346

349347
if (testSettings.enableExpressionEvaluation) {
@@ -433,6 +431,10 @@ class TestContext {
433431
final appConnectionCompleter = Completer();
434432
final connection = ChromeConnection('localhost', debugPort);
435433

434+
// TODO(srujzs): In the case of the frontend server, it doesn't make sense
435+
// that we initialize a new HTTP server instead of reusing the one in
436+
// `TestAssetServer`. We should instead use that one to align with Flutter
437+
// tools.
436438
_testServer = await TestServer.start(
437439
debugSettings: debugSettings.copyWith(
438440
expressionCompiler: expressionCompiler,
@@ -590,13 +592,9 @@ class TestContext {
590592
}
591593

592594
Future<void> recompile({required bool fullRestart}) async {
593-
await webRunner.run(
594-
frontendServerFileSystem,
595-
_hostname,
596-
await findUnusedPort(),
597-
webCompatiblePath([project.directoryToServe, project.filePathToServe]),
598-
initialCompile: false,
595+
await webRunner.rerun(
599596
fullRestart: fullRestart,
597+
fileServerUri: Uri.parse('http://${testServer.host}:${testServer.port}'),
600598
);
601599
return;
602600
}

0 commit comments

Comments
 (0)