From 30e53b0d9caadce80eff6d09f6975046b9a93033 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Tue, 8 Apr 2025 14:10:50 -0400 Subject: [PATCH] [ Widget Preview ] Add initial support for communications over the Dart Tooling Daemon (DTD) (#166698) This will eventually be used as the main communication channel between the widget preview scaffold, the Flutter tool, and other developer tooling (e.g., IDEs). Fixes #166417 --- packages/flutter_tools/lib/executable.dart | 2 + .../lib/src/commands/widget_preview.dart | 56 ++++++++++ .../src/runner/flutter_command_runner.dart | 7 ++ .../lib/src/widget_preview/dtd_services.dart | 101 ++++++++++++++++++ .../templates/template_manifest.json | 1 + .../lib/src/dtd_services.dart.tmpl | 33 ++++++ .../src/widget_preview_rendering.dart.tmpl | 3 + .../widget_preview_scaffold/pubspec.yaml.tmpl | 1 + .../widget_preview/widget_preview_test.dart | 3 + .../permeable/widget_preview_test.dart | 3 + .../widget_preview_test.dart | 48 ++++++++- .../lib/src/dtd_services.dart | 33 ++++++ .../lib/src/widget_preview_rendering.dart | 3 + .../widget_preview_scaffold/pubspec.yaml | 14 ++- 14 files changed, 305 insertions(+), 3 deletions(-) create mode 100644 packages/flutter_tools/lib/src/widget_preview/dtd_services.dart create mode 100644 packages/flutter_tools/templates/widget_preview_scaffold/lib/src/dtd_services.dart.tmpl create mode 100644 packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/dtd_services.dart diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart index 4cebf976dae..8165fe3c5e8 100644 --- a/packages/flutter_tools/lib/executable.dart +++ b/packages/flutter_tools/lib/executable.dart @@ -258,6 +258,8 @@ List generateCommands({required bool verboseHelp, required bool platform: globals.platform, shutdownHooks: globals.shutdownHooks, os: globals.os, + processManager: globals.processManager, + artifacts: globals.artifacts!, ), UpgradeCommand(verboseHelp: verboseHelp), SymbolizeCommand(stdio: globals.stdio, fileSystem: globals.fs), diff --git a/packages/flutter_tools/lib/src/commands/widget_preview.dart b/packages/flutter_tools/lib/src/commands/widget_preview.dart index abc7e66bbdb..8c94b70cf60 100644 --- a/packages/flutter_tools/lib/src/commands/widget_preview.dart +++ b/packages/flutter_tools/lib/src/commands/widget_preview.dart @@ -5,7 +5,9 @@ import 'package:args/args.dart'; import 'package:meta/meta.dart'; import 'package:package_config/package_config.dart'; +import 'package:process/process.dart'; +import '../artifacts.dart'; import '../base/common.dart'; import '../base/deferred_component.dart'; import '../base/file_system.dart'; @@ -24,6 +26,8 @@ import '../linux/build_linux.dart'; import '../macos/build_macos.dart'; import '../project.dart'; import '../runner/flutter_command.dart'; +import '../runner/flutter_command_runner.dart'; +import '../widget_preview/dtd_services.dart'; import '../widget_preview/preview_code_generator.dart'; import '../widget_preview/preview_detector.dart'; import '../widget_preview/preview_manifest.dart'; @@ -41,6 +45,8 @@ class WidgetPreviewCommand extends FlutterCommand { required Platform platform, required ShutdownHooks shutdownHooks, required OperatingSystemUtils os, + required ProcessManager processManager, + required Artifacts artifacts, }) { addSubcommand( WidgetPreviewStartCommand( @@ -52,6 +58,8 @@ class WidgetPreviewCommand extends FlutterCommand { platform: platform, shutdownHooks: shutdownHooks, os: os, + processManager: processManager, + artifacts: artifacts, ), ); addSubcommand( @@ -118,6 +126,8 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C required this.platform, required this.shutdownHooks, required this.os, + required this.processManager, + required this.artifacts, }) { addPubOptions(); argParser @@ -152,6 +162,9 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C static const String kHeadlessWeb = 'headless-web'; static const String kWidgetPreviewScaffoldOutputDir = 'scaffold-output-dir'; + /// Environment variable used to pass the DTD URI to the widget preview scaffold. + static const String kWidgetPreviewDtdUriEnvVar = 'WIDGET_PREVIEW_DTD_URI'; + @override Future> get requiredArtifacts async => const { // Ensure the Flutter Web SDK is installed. @@ -185,6 +198,10 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C final OperatingSystemUtils os; + final ProcessManager processManager; + + final Artifacts artifacts; + late final FlutterProject rootProject = getRootProject(); late final PreviewDetector _previewDetector = PreviewDetector( @@ -203,6 +220,12 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C cache: cache, ); + late final WidgetPreviewDtdServices _dtdService = WidgetPreviewDtdServices( + logger: logger, + shutdownHooks: shutdownHooks, + dtdLauncher: DtdLauncher(logger: logger, artifacts: artifacts, processManager: processManager), + ); + /// The currently running instance of the widget preview scaffold. AppInstance? _widgetPreviewApp; @@ -284,6 +307,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C shutdownHooks.addShutdownHook(() async { await _widgetPreviewApp?.stop(); }); + await configureDtd(); _widgetPreviewApp = await runPreviewEnvironment( widgetPreviewScaffoldProject: rootProject.widgetPreviewScaffoldProject, ); @@ -309,6 +333,31 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C _populatePreviewPubspec(rootProject: rootProject); } + /// Configures the Dart Tooling Daemon connection. + /// + /// If --dtd-uri is provided, the existing DTD instance will be used. If the tool fails to + /// connect to this URI, it will start its own DTD instance. + /// + /// If --dtd-uri is not provided, a DTD instance managed by the tool will be started. + Future configureDtd() async { + final String? existingDtdUriStr = stringArg(FlutterGlobalOptions.kDtdUrl, global: true); + Uri? existingDtdUri; + try { + if (existingDtdUriStr != null) { + existingDtdUri = Uri.parse(existingDtdUriStr); + } + } on FormatException { + logger.printWarning('Failed to parse value of --dtd-uri: $existingDtdUriStr.'); + } + if (existingDtdUri == null) { + logger.printTrace('Launching a fresh DTD instance...'); + await _dtdService.launchAndConnect(); + } else { + logger.printTrace('Connecting to existing DTD instance at: $existingDtdUri...'); + await _dtdService.connect(dtdWsUri: existingDtdUri); + } + } + /// Builds the application binary for the widget preview scaffold the first /// time the widget preview command is run. /// @@ -457,6 +506,12 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C BuildMode.debug, null, treeShakeIcons: false, + // Provide the DTD connection information directly to the preview scaffold. + // This could, in theory, be provided via a follow up call to a service extension + // registered by the preview scaffold, but there's some uncertainty around how service + // extensions will work with Flutter web embedded in VSCode without a Chrome debugger + // connection. + dartDefines: ['$kWidgetPreviewDtdUriEnvVar=${_dtdService.dtdUri}'], extraFrontEndOptions: isWeb ? ['--dartdevc-canary', '--dartdevc-module-format=ddc'] : null, packageConfigPath: widgetPreviewScaffoldProject.packageConfig.path, @@ -599,6 +654,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C if (offline) '--offline', '--directory', widgetPreviewScaffoldProject.directory.path, + 'dtd', 'flutter_lints', 'stack_trace', ], diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart index 158550c7cd3..d8f342d9b7f 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart @@ -36,6 +36,7 @@ abstract final class FlutterGlobalOptions { static const String kMachineFlag = 'machine'; static const String kPackagesOption = 'packages'; static const String kPrefixedErrorsFlag = 'prefixed-errors'; + static const String kDtdUrl = 'dtd-url'; static const String kPrintDtd = 'print-dtd'; static const String kQuietFlag = 'quiet'; static const String kShowTestDeviceFlag = 'show-test-device'; @@ -151,6 +152,12 @@ class FlutterCommandRunner extends CommandRunner { hide: !verboseHelp, help: 'Path to your "package_config.json" file.', ); + argParser.addOption( + FlutterGlobalOptions.kDtdUrl, + help: + 'The address of an existing Dart Tooling Daemon instance to be used by the Flutter CLI.', + hide: !verboseHelp, + ); argParser.addFlag( FlutterGlobalOptions.kPrintDtd, negatable: false, diff --git a/packages/flutter_tools/lib/src/widget_preview/dtd_services.dart b/packages/flutter_tools/lib/src/widget_preview/dtd_services.dart new file mode 100644 index 00000000000..1a28fa6c080 --- /dev/null +++ b/packages/flutter_tools/lib/src/widget_preview/dtd_services.dart @@ -0,0 +1,101 @@ +// Copyright 2014 The Flutter Authors. 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:async'; + +import 'package:dtd/dtd.dart'; +import 'package:process/process.dart'; + +import '../artifacts.dart'; +import '../base/common.dart'; +import '../base/io.dart'; +import '../base/logger.dart'; +import '../base/process.dart'; +import '../convert.dart'; + +/// Provides services, streams, and RPC invocations to interact with the Widget Preview Scaffold. +class WidgetPreviewDtdServices { + WidgetPreviewDtdServices({ + required this.logger, + required this.shutdownHooks, + required this.dtdLauncher, + }) { + shutdownHooks.addShutdownHook(() async { + await _dtd?.close(); + await dtdLauncher.dispose(); + }); + } + + final Logger logger; + final ShutdownHooks shutdownHooks; + final DtdLauncher dtdLauncher; + + DartToolingDaemon? _dtd; + + /// The [Uri] pointing to the currently connected DTD instance. + /// + /// Returns `null` if there is no DTD connection. + Uri? get dtdUri => _dtdUri; + Uri? _dtdUri; + + /// Starts DTD in a child process before invoking [connect] with a [Uri] pointing to the new + /// DTD instance. + Future launchAndConnect() async { + // Connect to the new DTD instance. + await connect(dtdWsUri: await dtdLauncher.launch()); + } + + /// Connects to an existing DTD instance and registers any relevant services. + Future connect({required Uri dtdWsUri}) async { + _dtdUri = dtdWsUri; + _dtd = await DartToolingDaemon.connect(dtdWsUri); + // TODO(bkonyi): register services. + logger.printTrace('Connected to DTD and registered services.'); + } +} + +/// Manages the lifecycle of a Dart Tooling Daemon (DTD) instance. +class DtdLauncher { + DtdLauncher({required this.logger, required this.artifacts, required this.processManager}); + + /// Starts a new DTD instance and returns the web socket URI it's available on. + Future launch() async { + if (_dtdProcess != null) { + throw StateError('Attempted to launch DTD twice.'); + } + + // Start DTD. + _dtdProcess = await processManager.start([ + artifacts.getArtifactPath(Artifact.engineDartBinary), + 'tooling-daemon', + '--machine', + ]); + + // Wait for the DTD connection information. + final Completer dtdUri = Completer(); + late final StreamSubscription sub; + sub = _dtdProcess!.stdout.transform(const Utf8Decoder()).listen((String data) async { + await sub.cancel(); + final Map jsonData = json.decode(data) as Map; + if (jsonData case {'tooling_daemon_details': {'uri': final String dtdUriString}}) { + dtdUri.complete(Uri.parse(dtdUriString)); + } else { + throwToolExit('Unable to start the Dart Tooling Daemon.'); + } + }); + return dtdUri.future; + } + + /// Kills the spawned DTD instance. + Future dispose() async { + _dtdProcess?.kill(); + _dtdProcess = null; + } + + final Logger logger; + final Artifacts artifacts; + final ProcessManager processManager; + + Process? _dtdProcess; +} diff --git a/packages/flutter_tools/templates/template_manifest.json b/packages/flutter_tools/templates/template_manifest.json index 04f74048daf..454040e21ab 100644 --- a/packages/flutter_tools/templates/template_manifest.json +++ b/packages/flutter_tools/templates/template_manifest.json @@ -356,6 +356,7 @@ "templates/widget_preview_scaffold/lib/src/widget_preview.dart.tmpl", "templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl", "templates/widget_preview_scaffold/lib/src/controls.dart.tmpl", + "templates/widget_preview_scaffold/lib/src/dtd_services.dart.tmpl", "templates/widget_preview_scaffold/lib/src/generated_preview.dart.tmpl", "templates/widget_preview_scaffold/lib/src/utils.dart.tmpl", "templates/widget_preview_scaffold/pubspec.yaml.tmpl", diff --git a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/dtd_services.dart.tmpl b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/dtd_services.dart.tmpl new file mode 100644 index 00000000000..eaff8e7fb08 --- /dev/null +++ b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/dtd_services.dart.tmpl @@ -0,0 +1,33 @@ +// Copyright 2014 The Flutter Authors. 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:async'; + +import 'package:dtd/dtd.dart'; + +/// Provides services, streams, and RPC invocations to interact with Flutter developer tooling. +class WidgetPreviewScaffoldDtdServices { + /// Environment variable for the DTD URI. + static const String kWidgetPreviewDtdUriEnvVar = 'WIDGET_PREVIEW_DTD_URI'; + + /// Connects to the Dart Tooling Daemon (DTD) specified by the Flutter tool. + /// + /// If the connection is successful, the Widget Preview Scaffold will register services and + /// subscribe to various streams to interact directly with other tooling (e.g., IDEs). + Future connect() async { + final Uri dtdWsUri = Uri.parse( + const String.fromEnvironment(kWidgetPreviewDtdUriEnvVar), + ); + _dtd = await DartToolingDaemon.connect(dtdWsUri); + unawaited( + _dtd.postEvent( + 'WidgetPreviewScaffold', + 'Connected', + const {}, + ), + ); + } + + late final DartToolingDaemon _dtd; +} diff --git a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl index 8449dd0ec5b..568743d90ed 100644 --- a/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl +++ b/packages/flutter_tools/templates/widget_preview_scaffold/lib/src/widget_preview_rendering.dart.tmpl @@ -13,6 +13,7 @@ import 'package:flutter/services.dart'; import 'package:stack_trace/stack_trace.dart'; import 'controls.dart'; +import 'dtd_services.dart'; import 'generated_preview.dart'; import 'utils.dart'; import 'widget_preview.dart'; @@ -410,6 +411,8 @@ class PreviewAssetBundle extends PlatformAssetBundle { /// the preview scaffold project which prevents us from being able to use hot /// restart to iterate on this file. Future mainImpl() async { + // TODO(bkonyi): store somewhere. + await WidgetPreviewScaffoldDtdServices().connect(); runApp(_WidgetPreviewScaffold()); } diff --git a/packages/flutter_tools/templates/widget_preview_scaffold/pubspec.yaml.tmpl b/packages/flutter_tools/templates/widget_preview_scaffold/pubspec.yaml.tmpl index ca4a8ecee5b..c74199d7ab5 100644 --- a/packages/flutter_tools/templates/widget_preview_scaffold/pubspec.yaml.tmpl +++ b/packages/flutter_tools/templates/widget_preview_scaffold/pubspec.yaml.tmpl @@ -12,6 +12,7 @@ dependencies: flutter_test: sdk: flutter # These will be replaced with proper constraints after the template is hydrated. + dtd: any flutter_lints: any stack_trace: any diff --git a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/widget_preview_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/widget_preview_test.dart index cbfaf3b439f..b624e5917bd 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/widget_preview_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/widget_preview/widget_preview_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:file/memory.dart'; +import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/os.dart'; @@ -47,6 +48,8 @@ void main() { platform: platform, processManager: processManager, ), + processManager: FakeProcessManager.any(), + artifacts: Artifacts.test(fileSystem: fileSystem), ); rootProject = FakeFlutterProject( projectRoot: 'some_project', diff --git a/packages/flutter_tools/test/commands.shard/permeable/widget_preview_test.dart b/packages/flutter_tools/test/commands.shard/permeable/widget_preview_test.dart index d5e4cc81d81..7a90ec27720 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/widget_preview_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/widget_preview_test.dart @@ -6,6 +6,7 @@ import 'dart:io' as io show IOOverrides; import 'package:args/command_runner.dart'; import 'package:file_testing/file_testing.dart'; +import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/bot_detector.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -80,6 +81,8 @@ void main() { logger: logger, platform: platform, ), + artifacts: Artifacts.test(), + processManager: FakeProcessManager.any(), ), ); await runner.run(['widget-preview', ...arguments]); diff --git a/packages/flutter_tools/test/integration.shard/widget_preview_test.dart b/packages/flutter_tools/test/integration.shard/widget_preview_test.dart index 14cfc1c6ae1..f080f6b0514 100644 --- a/packages/flutter_tools/test/integration.shard/widget_preview_test.dart +++ b/packages/flutter_tools/test/integration.shard/widget_preview_test.dart @@ -5,12 +5,18 @@ import 'dart:async'; import 'dart:convert'; +import 'package:dtd/dtd.dart'; import 'package:file/file.dart'; import 'package:flutter_tools/src/base/io.dart'; +import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/commands/widget_preview.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/runner/flutter_command_runner.dart'; +import 'package:flutter_tools/src/widget_preview/dtd_services.dart'; import 'package:process/process.dart'; import '../src/common.dart'; +import '../src/context.dart'; import 'test_data/basic_project.dart'; import 'test_utils.dart'; @@ -43,10 +49,13 @@ const List subsequentLaunchMessagesWeb = [ void main() { late Directory tempDir; Process? process; + Logger? logger; + DtdLauncher? dtdLauncher; final BasicProject project = BasicProject(); const ProcessManager processManager = LocalProcessManager(); setUp(() async { + logger = BufferLogger.test(); tempDir = createResolvedTempDirectorySync('widget_preview_test.'); await project.setUpIn(tempDir); }); @@ -54,12 +63,15 @@ void main() { tearDown(() async { process?.kill(); process = null; + await dtdLauncher?.dispose(); + dtdLauncher = null; tryToDelete(tempDir); }); Future runWidgetPreview({ required List expectedMessages, bool useWeb = false, + Uri? dtdUri, }) async { expect(expectedMessages, isNotEmpty); int i = 0; @@ -72,6 +84,7 @@ void main() { '--${WidgetPreviewStartCommand.kHeadlessWeb}' else '--${WidgetPreviewStartCommand.kUseFlutterDesktop}', + if (dtdUri != null) '--${FlutterGlobalOptions.kDtdUrl}=$dtdUri', ], workingDirectory: tempDir.path); final Completer completer = Completer(); @@ -103,8 +116,6 @@ void main() { }), ); await completer.future; - process!.kill(); - process = null; } group('flutter widget-preview start', () { @@ -132,5 +143,38 @@ void main() { // We shouldn't regenerate the scaffold after the initial run. await runWidgetPreview(expectedMessages: subsequentLaunchMessagesWeb, useWeb: true); }); + + testUsingContext('can connect to an existing DTD instance', () async { + dtdLauncher = DtdLauncher( + logger: logger!, + artifacts: globals.artifacts!, + processManager: globals.processManager, + ); + + // Start a DTD instance. + final Uri dtdUri = await dtdLauncher!.launch(); + + // Connect to it and listen to the WidgetPreviewScaffold stream. + // + // The preview scaffold will send a 'Connected' event on this stream once it has initialized + // and is ready. + final DartToolingDaemon dtdConnection = await DartToolingDaemon.connect(dtdUri); + const String kWidgetPreviewScaffoldStream = 'WidgetPreviewScaffold'; + final Completer completer = Completer(); + dtdConnection.onEvent(kWidgetPreviewScaffoldStream).listen((DTDEvent event) { + expect(event.stream, kWidgetPreviewScaffoldStream); + expect(event.kind, 'Connected'); + completer.complete(); + }); + await dtdConnection.streamListen(kWidgetPreviewScaffoldStream); + + // Start the widget preview and wait for the 'Connected' event. + await runWidgetPreview( + expectedMessages: firstLaunchMessagesWeb, + useWeb: true, + dtdUri: dtdUri, + ); + await completer.future; + }); }); } diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/dtd_services.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/dtd_services.dart new file mode 100644 index 00000000000..eaff8e7fb08 --- /dev/null +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/dtd_services.dart @@ -0,0 +1,33 @@ +// Copyright 2014 The Flutter Authors. 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:async'; + +import 'package:dtd/dtd.dart'; + +/// Provides services, streams, and RPC invocations to interact with Flutter developer tooling. +class WidgetPreviewScaffoldDtdServices { + /// Environment variable for the DTD URI. + static const String kWidgetPreviewDtdUriEnvVar = 'WIDGET_PREVIEW_DTD_URI'; + + /// Connects to the Dart Tooling Daemon (DTD) specified by the Flutter tool. + /// + /// If the connection is successful, the Widget Preview Scaffold will register services and + /// subscribe to various streams to interact directly with other tooling (e.g., IDEs). + Future connect() async { + final Uri dtdWsUri = Uri.parse( + const String.fromEnvironment(kWidgetPreviewDtdUriEnvVar), + ); + _dtd = await DartToolingDaemon.connect(dtdWsUri); + unawaited( + _dtd.postEvent( + 'WidgetPreviewScaffold', + 'Connected', + const {}, + ), + ); + } + + late final DartToolingDaemon _dtd; +} diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview_rendering.dart b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview_rendering.dart index 8449dd0ec5b..568743d90ed 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview_rendering.dart +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/lib/src/widget_preview_rendering.dart @@ -13,6 +13,7 @@ import 'package:flutter/services.dart'; import 'package:stack_trace/stack_trace.dart'; import 'controls.dart'; +import 'dtd_services.dart'; import 'generated_preview.dart'; import 'utils.dart'; import 'widget_preview.dart'; @@ -410,6 +411,8 @@ class PreviewAssetBundle extends PlatformAssetBundle { /// the preview scaffold project which prevents us from being able to use hot /// restart to iterate on this file. Future mainImpl() async { + // TODO(bkonyi): store somewhere. + await WidgetPreviewScaffoldDtdServices().connect(); runApp(_WidgetPreviewScaffold()); } diff --git a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.yaml b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.yaml index 598273ede0b..411eb4a65c2 100644 --- a/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.yaml +++ b/packages/flutter_tools/test/widget_preview_scaffold.shard/widget_preview_scaffold/pubspec.yaml @@ -12,6 +12,7 @@ dependencies: flutter_test: sdk: flutter # These will be replaced with proper constraints after the template is hydrated. + dtd: 2.5.0 flutter_lints: 5.0.0 stack_trace: 1.12.1 @@ -20,7 +21,13 @@ dependencies: characters: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.19.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + convert: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + crypto: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + file: 7.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + http: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + http_parser: 4.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + json_rpc_2: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" leak_tracker: 10.0.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" leak_tracker_flutter_testing: 3.0.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" leak_tracker_testing: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,10 +41,15 @@ dependencies: string_scanner: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.7.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + typed_data: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + unified_analytics: 7.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 15.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web_socket: 0.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web_socket_channel: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 367e +# PUBSPEC CHECKSUM: 4b12