mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[ Widget Preview ] Pass DTD URI as a constant in a generated file (#179821)
Passing the DTD URI via a Dart define results in a new `<hash>.cache.dill.track.dill` being created on each run as the DTD URI is never the same and the `cache.dill.track.dill` hash is partly based on the set of Dart defines. These files are not cleaned up automatically, so they could take up a significant amount of memory over time. This change adds an additional code generation step to the widget previewer which populates `widget_preview_scaffold/lib/src/dtd/dtd_connection_info.dart` with a constant containing the DTD URI provided by the tool. Fixes https://github.com/flutter/flutter/issues/179139
This commit is contained in:
parent
a588c85d8d
commit
a78aefa9bc
@ -401,6 +401,7 @@ final class WidgetPreviewStartCommand extends WidgetPreviewSubCommandBase with C
|
||||
logger.printTrace('Connecting to existing DTD instance at: $existingDtdUri...');
|
||||
await _dtdService.connect(dtdWsUri: existingDtdUri);
|
||||
}
|
||||
_previewCodeGenerator.populateDtdConnectionInfo(_dtdService.dtdUri!);
|
||||
}
|
||||
|
||||
Future<int> runPreviewEnvironment({required FlutterProject widgetPreviewScaffoldProject}) async {
|
||||
@ -463,12 +464,6 @@ 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: <String>['$kWidgetPreviewDtdUriEnvVar=${_dtdService.dtdUri}'],
|
||||
packageConfigPath: widgetPreviewScaffoldProject.packageConfig.path,
|
||||
packageConfig: PackageConfig.parseBytes(
|
||||
widgetPreviewScaffoldProject.packageConfig.readAsBytesSync(),
|
||||
|
||||
@ -52,6 +52,35 @@ class PreviewCodeGenerator {
|
||||
static String getGeneratedPreviewFilePath(FileSystem fs) =>
|
||||
fs.path.join('lib', 'src', 'generated_preview.dart');
|
||||
|
||||
static String getGeneratedDtdConnectionInfoFilePath(FileSystem fs) =>
|
||||
fs.path.join('lib', 'src', 'dtd', 'dtd_connection_info.dart');
|
||||
|
||||
void populateDtdConnectionInfo(Uri dtdUri) {
|
||||
final emitter = cb.DartEmitter.scoped(useNullSafetySyntax: true);
|
||||
final lib = cb.Library(
|
||||
(cb.LibraryBuilder b) => b
|
||||
..ignoreForFile.add('implementation_imports')
|
||||
..body.addAll(<cb.Spec>[
|
||||
cb.Field((b) {
|
||||
b
|
||||
..name = 'kWidgetPreviewDtdUri'
|
||||
..modifier = cb.FieldModifier.constant
|
||||
..type = cb.refer('String')
|
||||
..assignment = cb.literalString(dtdUri.toString()).code;
|
||||
}),
|
||||
]),
|
||||
);
|
||||
final File generatedDtdConnectionInfoFile = fs.file(
|
||||
widgetPreviewScaffoldProject.directory.uri.resolve(getGeneratedDtdConnectionInfoFilePath(fs)),
|
||||
);
|
||||
generatedDtdConnectionInfoFile.writeAsStringSync(
|
||||
// Format the generated file for readability, particularly during feature development.
|
||||
// Note: we don't really care _how_ this is formatted, just that it's formatted, so we don't
|
||||
// specify a language version.
|
||||
DartFormatter(languageVersion: Version.none).format(lib.accept(emitter).toString()),
|
||||
);
|
||||
}
|
||||
|
||||
// TODO(bkonyi): update generated example now that we're computing constants
|
||||
/// Generates code used by the widget preview scaffold based on the preview instances listed in
|
||||
/// [previews].
|
||||
|
||||
@ -361,6 +361,7 @@
|
||||
"templates/widget_preview_scaffold/lib/src/controls.dart.tmpl",
|
||||
"templates/widget_preview_scaffold/lib/src/split.dart.tmpl",
|
||||
"templates/widget_preview_scaffold/lib/src/dtd/utils.dart.tmpl",
|
||||
"templates/widget_preview_scaffold/lib/src/dtd/dtd_connection_info.dart.tmpl",
|
||||
"templates/widget_preview_scaffold/lib/src/dtd/dtd_services.dart.tmpl",
|
||||
"templates/widget_preview_scaffold/lib/src/dtd/editor_service.dart.tmpl",
|
||||
"templates/widget_preview_scaffold/lib/src/generated_preview.dart.tmpl",
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
// 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.
|
||||
|
||||
const String kWidgetPreviewDtdUri = '';
|
||||
@ -6,14 +6,12 @@ import 'dart:async';
|
||||
|
||||
import 'package:dtd/dtd.dart';
|
||||
import 'package:json_rpc_2/json_rpc_2.dart';
|
||||
import 'package:widget_preview_scaffold/src/dtd/dtd_connection_info.dart';
|
||||
import 'package:widget_preview_scaffold/src/dtd/editor_service.dart';
|
||||
import 'package:widget_preview_scaffold/src/dtd/utils.dart';
|
||||
|
||||
/// Provides services, streams, and RPC invocations to interact with Flutter developer tooling.
|
||||
class WidgetPreviewScaffoldDtdServices with DtdEditorService {
|
||||
/// Environment variable for the DTD URI.
|
||||
static const String kWidgetPreviewDtdUriEnvVar = 'WIDGET_PREVIEW_DTD_URI';
|
||||
|
||||
// WARNING: Keep these constants and services in sync with those defined in the widget preview
|
||||
// scaffold's dtd_services.dart.
|
||||
//
|
||||
@ -38,9 +36,7 @@ class WidgetPreviewScaffoldDtdServices with DtdEditorService {
|
||||
/// 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<void> connect({Uri? dtdUri}) async {
|
||||
final Uri dtdWsUri =
|
||||
dtdUri ??
|
||||
Uri.parse(const String.fromEnvironment(kWidgetPreviewDtdUriEnvVar));
|
||||
final Uri dtdWsUri = dtdUri ?? Uri.parse(kWidgetPreviewDtdUri);
|
||||
dtd = await DartToolingDaemon.connect(dtdWsUri);
|
||||
unawaited(
|
||||
dtd.postEvent(
|
||||
|
||||
@ -245,7 +245,12 @@ void main() {
|
||||
onChangeDetected: (_) {},
|
||||
onPubspecChangeDetected: (String path) {},
|
||||
);
|
||||
codeGenerator = PreviewCodeGenerator(widgetPreviewScaffoldProject: project, fs: fs);
|
||||
codeGenerator = PreviewCodeGenerator(
|
||||
widgetPreviewScaffoldProject: FlutterProject.fromDirectoryTest(
|
||||
project.widgetPreviewScaffold,
|
||||
),
|
||||
fs: fs,
|
||||
);
|
||||
final pub = Pub.test(
|
||||
fileSystem: fs,
|
||||
logger: logger,
|
||||
@ -267,15 +272,15 @@ void main() {
|
||||
'correctly generates ${PreviewCodeGenerator.getGeneratedPreviewFilePath(fs)}',
|
||||
() async {
|
||||
// Check that the generated preview file doesn't exist yet.
|
||||
final File generatedPreviewFile = project.directory.childFile(
|
||||
final File generatedPreviewFile = project.widgetPreviewScaffold.childFile(
|
||||
PreviewCodeGenerator.getGeneratedPreviewFilePath(fs),
|
||||
);
|
||||
expect(generatedPreviewFile, isNot(exists));
|
||||
generatedPreviewFile.createSync(recursive: true);
|
||||
final PreviewDependencyGraph details = await previewDetector.initialize();
|
||||
|
||||
// Populate the generated preview file.
|
||||
codeGenerator.populatePreviewsInGeneratedPreviewScaffold(details);
|
||||
expect(generatedPreviewFile, exists);
|
||||
|
||||
const expectedGeneratedPreviewFileContents = '''
|
||||
// ignore_for_file: implementation_imports
|
||||
@ -385,7 +390,6 @@ List<_i1.WidgetPreview> previews() => [
|
||||
codeGenerator.populatePreviewsInGeneratedPreviewScaffold(
|
||||
const <PreviewPath, LibraryPreviewNode>{},
|
||||
);
|
||||
expect(generatedPreviewFile, exists);
|
||||
|
||||
// The generated file should only contain:
|
||||
// - An import of the widget preview library
|
||||
@ -401,5 +405,29 @@ List<_i1.WidgetPreview> previews() => [];
|
||||
expect(generatedPreviewFile.readAsStringSync(), emptyGeneratedPreviewFileContents);
|
||||
},
|
||||
);
|
||||
|
||||
testUsingContext(
|
||||
'correctly generates ${PreviewCodeGenerator.getGeneratedDtdConnectionInfoFilePath(fs)}',
|
||||
() async {
|
||||
// Check that the generated preview file doesn't exist yet.
|
||||
final File generatedDtdConnectionInfoFile = project.widgetPreviewScaffold.childFile(
|
||||
PreviewCodeGenerator.getGeneratedDtdConnectionInfoFilePath(fs),
|
||||
);
|
||||
expect(generatedDtdConnectionInfoFile, isNot(exists));
|
||||
generatedDtdConnectionInfoFile.createSync(recursive: true);
|
||||
|
||||
// Populate the DTD connection info.
|
||||
final Uri dtdUri = Uri.parse('ws://localhost:1234');
|
||||
codeGenerator.populateDtdConnectionInfo(dtdUri);
|
||||
|
||||
final expectedDtdConnectionInfo =
|
||||
'''
|
||||
// ignore_for_file: implementation_imports
|
||||
|
||||
const String kWidgetPreviewDtdUri = '$dtdUri';
|
||||
''';
|
||||
expect(generatedDtdConnectionInfoFile.readAsStringSync(), expectedDtdConnectionInfo);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
// 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.
|
||||
|
||||
const String kWidgetPreviewDtdUri = '';
|
||||
@ -6,14 +6,12 @@ import 'dart:async';
|
||||
|
||||
import 'package:dtd/dtd.dart';
|
||||
import 'package:json_rpc_2/json_rpc_2.dart';
|
||||
import 'package:widget_preview_scaffold/src/dtd/dtd_connection_info.dart';
|
||||
import 'package:widget_preview_scaffold/src/dtd/editor_service.dart';
|
||||
import 'package:widget_preview_scaffold/src/dtd/utils.dart';
|
||||
|
||||
/// Provides services, streams, and RPC invocations to interact with Flutter developer tooling.
|
||||
class WidgetPreviewScaffoldDtdServices with DtdEditorService {
|
||||
/// Environment variable for the DTD URI.
|
||||
static const String kWidgetPreviewDtdUriEnvVar = 'WIDGET_PREVIEW_DTD_URI';
|
||||
|
||||
// WARNING: Keep these constants and services in sync with those defined in the widget preview
|
||||
// scaffold's dtd_services.dart.
|
||||
//
|
||||
@ -38,9 +36,7 @@ class WidgetPreviewScaffoldDtdServices with DtdEditorService {
|
||||
/// 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<void> connect({Uri? dtdUri}) async {
|
||||
final Uri dtdWsUri =
|
||||
dtdUri ??
|
||||
Uri.parse(const String.fromEnvironment(kWidgetPreviewDtdUriEnvVar));
|
||||
final Uri dtdWsUri = dtdUri ?? Uri.parse(kWidgetPreviewDtdUri);
|
||||
dtd = await DartToolingDaemon.connect(dtdWsUri);
|
||||
unawaited(
|
||||
dtd.postEvent(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user