Skip to content

Support running DWDS without a Chrome Debug Port (web-socket-based) #2639

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 37 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
1fe0895
implemented socket-based dwds
jyameo Jun 26, 2025
2707a41
fix issue with run main at start
jyameo Jun 26, 2025
489dbcc
updated changelog
jyameo Jun 26, 2025
a4e0dd0
simulate debugExtension in websocket-based execution flow
jyameo Jun 27, 2025
412bda3
added multiwindow support
jyameo Jul 11, 2025
8f7c645
refactoring and removing unused method
jyameo Jul 15, 2025
91c7b41
support page refresh from vsCode
jyameo Jul 16, 2025
871f388
refactor createisolate and resume method
jyameo Jul 17, 2025
d7dad51
implemented pause/resume logic
jyameo Jul 17, 2025
6f40567
improve canReuseConnection logic
jyameo Jul 17, 2025
b4d5cb1
comments cleanup
jyameo Jul 17, 2025
0edf3d8
fixed canReuseConnection logic
jyameo Jul 17, 2025
340baad
implemented _handleConnectionClosed and fix issue with getVM
jyameo Jul 18, 2025
fa5feb0
fix issue with handling isolate cleanup
jyameo Jul 18, 2025
6ba7f5b
jyameo Jul 21, 2025
afe9fc9
addressed comments regarding closing remoteDebugger
jyameo Jul 21, 2025
18617bd
code cleanup
jyameo Jul 21, 2025
32f165e
created common interface for debugService and webSocketDebugService
jyameo Jul 21, 2025
49b234a
remove use of _acceptNewConnections in WebSocketDebugService
jyameo Jul 22, 2025
af9763f
created proxy_service.dart and consolidated all duplicated code
jyameo Jul 22, 2025
a61bde1
consolidate webSocketAppDebugService and AppDebugServices
jyameo Jul 22, 2025
813765e
consolidate dwdsVmClient and WebSocketDwdsVmClient
jyameo Jul 22, 2025
14e2a2a
refactored can remove duplicate methods
jyameo Jul 22, 2025
dea7f56
remove use of dynamic
jyameo Jul 22, 2025
5340ab0
fix dev_handler error
jyameo Jul 22, 2025
be31caa
consolidate handleChromeMessages and handleWebSocketMessages created …
jyameo Jul 22, 2025
cf526af
updated logg message in _sendRequestToClients
jyameo Jul 22, 2025
4937508
updated dev_handler to throw error if proxy_service is not the right …
jyameo Jul 23, 2025
8bce65a
Merge branch 'main' into websocketproxyservice
jyameo Jul 23, 2025
3d0d4ea
addressing analyzer issues
jyameo Jul 23, 2025
3e919ce
removed unused variable
jyameo Jul 23, 2025
cd5b810
updated port to 44456
jyameo Jul 23, 2025
1c55263
refactored classes to and interface names to be more clear
jyameo Jul 23, 2025
956c323
fix variable name error
jyameo Jul 23, 2025
fb5057b
updated variable to be type
jyameo Jul 24, 2025
92b0f19
Merge branch 'main' into websocketproxyservice
jyameo Jul 28, 2025
a3e09a6
prepare version 24.4.1 for release
jyameo Jul 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion dwds/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## 24.4.1-wip
## 24.4.1

- 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)
- Added WebSocket-based hot reload and service extension support via new `WebSocketProxyService` class that implements VM service protocol over WebSockets.
- Enhanced `DevHandler` with `useWebSocketConnection` flag to toggle between Chrome-based and WebSocket-based communication protocols.
- Fixed an issue where we didn't wait until all scripts were parsed before
recomputing metadata on a hot reload.

Expand Down
23 changes: 15 additions & 8 deletions dwds/lib/dart_web_debug_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ class Dwds {
final DevHandler _devHandler;
final AssetReader _assetReader;
final bool _enableDebugging;
final bool _useDwdsWebSocketConnection;

Dwds._(
this.middleware,
this._devTools,
this._devHandler,
this._assetReader,
this._enableDebugging,
this._useDwdsWebSocketConnection,
) : handler = _devHandler.handler;

Stream<AppConnection> get connectedApps => _devHandler.connectedApps;
Expand All @@ -53,12 +55,18 @@ class Dwds {
await _assetReader.close();
}

/// Creates a debug connection for the given app connection.
///
/// Returns a [DebugConnection] that wraps the appropriate debug services
/// based on the connection type (WebSocket or Chrome-based).
Future<DebugConnection> debugConnection(AppConnection appConnection) async {
if (!_enableDebugging) throw StateError('Debugging is not enabled.');
final appDebugServices = await _devHandler.loadAppServices(appConnection);
final chromeProxyService = appDebugServices.chromeProxyService;
await chromeProxyService.isInitialized;
return DebugConnection(appDebugServices);

if (_useDwdsWebSocketConnection) {
return await _devHandler.createDebugConnectionForWebSocket(appConnection);
} else {
return await _devHandler.createDebugConnectionForChrome(appConnection);
}
}

static Future<Dwds> start({
Expand Down Expand Up @@ -123,10 +131,7 @@ class Dwds {
_logger.info('Serving DevTools at $uri\n');
}

final injected = DwdsInjector(
extensionUri: extensionUri,
useDwdsWebSocketConnection: useDwdsWebSocketConnection,
);
final injected = DwdsInjector(extensionUri: extensionUri);

final devHandler = DevHandler(
chromeConnection,
Expand All @@ -143,6 +148,7 @@ class Dwds {
debugSettings.spawnDds,
debugSettings.ddsPort,
debugSettings.launchDevToolsInNewWindow,
useWebSocketConnection: useDwdsWebSocketConnection,
);

return Dwds._(
Expand All @@ -151,6 +157,7 @@ class Dwds {
devHandler,
assetReader,
debugSettings.enableDebugging,
useDwdsWebSocketConnection,
);
}
}
4 changes: 4 additions & 0 deletions dwds/lib/data/serializers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import 'error_response.dart';
import 'extension_request.dart';
import 'hot_reload_request.dart';
import 'hot_reload_response.dart';
import 'service_extension_request.dart';
import 'service_extension_response.dart';
import 'isolate_events.dart';
import 'register_event.dart';
import 'run_request.dart';
Expand All @@ -40,5 +42,7 @@ part 'serializers.g.dart';
ErrorResponse,
RegisterEvent,
RunRequest,
ServiceExtensionRequest,
ServiceExtensionResponse,
])
final Serializers serializers = _$serializers;
2 changes: 2 additions & 0 deletions dwds/lib/data/serializers.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions dwds/lib/data/service_extension_request.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2025, the Dart project authors. All rights reserved.
// Defines the request for service extension calls over WebSocket.

import 'dart:convert';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';

part 'service_extension_request.g.dart';

abstract class ServiceExtensionRequest
implements Built<ServiceExtensionRequest, ServiceExtensionRequestBuilder> {
String get id;
String get method;
String
get argsJson; // Store args as JSON string for built_value compatibility

// Helper method to get args as Map<String, dynamic>
Map<String, dynamic> get args =>
argsJson.isEmpty
? <String, dynamic>{}
: json.decode(argsJson) as Map<String, dynamic>;

ServiceExtensionRequest._();
factory ServiceExtensionRequest([
void Function(ServiceExtensionRequestBuilder) updates,
]) = _$ServiceExtensionRequest;

// Convenient factory method to create with args Map
factory ServiceExtensionRequest.fromArgs({
required String id,
required String method,
required Map<String, dynamic> args,
}) => ServiceExtensionRequest(
(b) =>
b
..id = id
..method = method
..argsJson = json.encode(args),
);

static Serializer<ServiceExtensionRequest> get serializer =>
_$serviceExtensionRequestSerializer;
}
228 changes: 228 additions & 0 deletions dwds/lib/data/service_extension_request.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading