Skip to content

Commit c4aaa39

Browse files
authored
[tool][web] Create an early web plugin_registrant for dartpad. (#106921)
1 parent ed37c83 commit c4aaa39

File tree

3 files changed

+106
-12
lines changed

3 files changed

+106
-12
lines changed

packages/flutter_tools/lib/src/flutter_plugins.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,11 @@ Future<void> refreshPluginsList(
11061106
///
11071107
/// In the Web platform, `destination` can point to a real filesystem (`flutter build`)
11081108
/// or an in-memory filesystem (`flutter run`).
1109+
///
1110+
/// This method is also used by [WebProject.ensureReadyForPlatformSpecificTooling]
1111+
/// to inject a copy of the plugin registrant for web into .dart_tool/dartpad so
1112+
/// dartpad can get the plugin registrant without needing to build the complete
1113+
/// project. See: https://github.com/dart-lang/dart-services/pull/874
11091114
Future<void> injectBuildTimePluginFiles(
11101115
FlutterProject project, {
11111116
required Directory destination,

packages/flutter_tools/lib/src/project.dart

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,20 @@ class WebProject extends FlutterProjectPlatform {
734734
.childDirectory('web')
735735
.childFile('index.html');
736736

737-
Future<void> ensureReadyForPlatformSpecificTooling() async {}
737+
/// The .dart_tool/dartpad directory
738+
Directory get dartpadToolDirectory => parent.directory
739+
.childDirectory('.dart_tool')
740+
.childDirectory('dartpad');
741+
742+
Future<void> ensureReadyForPlatformSpecificTooling() async {
743+
/// Create .dart_tool/dartpad/web_plugin_registrant.dart.
744+
/// See: https://github.com/dart-lang/dart-services/pull/874
745+
await injectBuildTimePluginFiles(
746+
parent,
747+
destination: dartpadToolDirectory,
748+
webPlatform: true,
749+
);
750+
}
738751
}
739752

740753
/// The Fuchsia sub project.

packages/flutter_tools/test/integration.shard/web_plugin_registrant_test.dart

Lines changed: 87 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,10 @@ void main() {
4343

4444
testUsingContext('generated plugin registrant passes analysis', () async {
4545
await _createProject(projectDir, <String>[]);
46-
// We need to add a dependency with web support to trigger
47-
// the generated_plugin_registrant generation.
46+
// We need a dependency so the plugin registrant is not completely empty.
4847
await _addDependency(projectDir, 'shared_preferences',
4948
version: '^2.0.0');
50-
// The plugin registrant is only created after a build...
49+
// The plugin registrant is created on build...
5150
await _buildWebProject(projectDir);
5251

5352
// Find the web_plugin_registrant, now that it lives outside "lib":
@@ -56,11 +55,77 @@ void main() {
5655
.listSync()
5756
.firstWhere((FileSystemEntity entity) => entity is Directory) as Directory;
5857

59-
expect(
60-
buildDir.childFile('web_plugin_registrant.dart'),
61-
exists,
62-
);
63-
await _analyzeEntity(buildDir.childFile('web_plugin_registrant.dart'));
58+
// Ensure the file exists, and passes analysis.
59+
final File registrant = buildDir.childFile('web_plugin_registrant.dart');
60+
expect(registrant, exists);
61+
await _analyzeEntity(registrant);
62+
63+
// Ensure the contents match what we expect for a non-empty plugin registrant.
64+
final String contents = registrant.readAsStringSync();
65+
expect(contents, contains("import 'package:shared_preferences_web/shared_preferences_web.dart';"));
66+
expect(contents, contains('void registerPlugins([final Registrar? pluginRegistrar]) {'));
67+
expect(contents, contains('SharedPreferencesPlugin.registerWith(registrar);'));
68+
expect(contents, contains('registrar.registerMessageHandler();'));
69+
}, overrides: <Type, Generator>{
70+
Pub: () => Pub(
71+
fileSystem: globals.fs,
72+
logger: globals.logger,
73+
processManager: globals.processManager,
74+
usage: globals.flutterUsage,
75+
botDetector: globals.botDetector,
76+
platform: globals.platform,
77+
),
78+
});
79+
80+
testUsingContext('(no-op) generated plugin registrant passes analysis', () async {
81+
await _createProject(projectDir, <String>[]);
82+
// No dependencies on web plugins this time!
83+
await _buildWebProject(projectDir);
84+
85+
// Find the web_plugin_registrant, now that it lives outside "lib":
86+
final Directory buildDir = projectDir
87+
.childDirectory('.dart_tool/flutter_build')
88+
.listSync()
89+
.firstWhere((FileSystemEntity entity) => entity is Directory) as Directory;
90+
91+
// Ensure the file exists, and passes analysis.
92+
final File registrant = buildDir.childFile('web_plugin_registrant.dart');
93+
expect(registrant, exists);
94+
await _analyzeEntity(registrant);
95+
96+
// Ensure the contents match what we expect for an empty (noop) plugin registrant.
97+
final String contents = registrant.readAsStringSync();
98+
expect(contents, contains('void registerPlugins() {}'));
99+
}, overrides: <Type, Generator>{
100+
Pub: () => Pub(
101+
fileSystem: globals.fs,
102+
logger: globals.logger,
103+
processManager: globals.processManager,
104+
usage: globals.flutterUsage,
105+
botDetector: globals.botDetector,
106+
platform: globals.platform,
107+
),
108+
});
109+
110+
// See: https://github.com/dart-lang/dart-services/pull/874
111+
testUsingContext('generated plugin registrant for dartpad is created on pub get', () async {
112+
await _createProject(projectDir, <String>[]);
113+
await _addDependency(projectDir, 'shared_preferences',
114+
version: '^2.0.0');
115+
// The plugin registrant for dartpad is created on flutter pub get.
116+
await _doFlutterPubGet(projectDir);
117+
118+
final File registrant = projectDir
119+
.childDirectory('.dart_tool/dartpad')
120+
.childFile('web_plugin_registrant.dart');
121+
122+
// Ensure the file exists, and passes analysis.
123+
expect(registrant, exists);
124+
await _analyzeEntity(registrant);
125+
126+
// Assert the full build hasn't happened!
127+
final Directory buildDir = projectDir.childDirectory('.dart_tool/flutter_build');
128+
expect(buildDir, isNot(exists));
64129
}, overrides: <Type, Generator>{
65130
Pub: () => Pub(
66131
fileSystem: globals.fs,
@@ -258,6 +323,18 @@ Future<void> _analyzeEntity(FileSystemEntity target) async {
258323
}
259324

260325
Future<void> _buildWebProject(Directory workingDir) async {
326+
return _runFlutterSnapshot(<String>['build', 'web'], workingDir);
327+
}
328+
329+
Future<void> _doFlutterPubGet(Directory workingDir) async {
330+
return _runFlutterSnapshot(<String>['pub', 'get'], workingDir);
331+
}
332+
333+
// Runs a flutter command from a snapshot build.
334+
// `flutterCommandArgs` are the arguments passed to flutter, like: ['build', 'web']
335+
// to run `flutter build web`.
336+
// `workingDir` is the directory on which the flutter command will be run.
337+
Future<void> _runFlutterSnapshot(List<String> flutterCommandArgs, Directory workingDir) async {
261338
final String flutterToolsSnapshotPath = globals.fs.path.absolute(
262339
globals.fs.path.join(
263340
'..',
@@ -270,16 +347,15 @@ Future<void> _buildWebProject(Directory workingDir) async {
270347

271348
final List<String> args = <String>[
272349
flutterToolsSnapshotPath,
273-
'build',
274-
'web',
350+
...flutterCommandArgs
275351
];
276352

277353
final ProcessResult exec = await Process.run(
278354
globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path,
279355
args,
280356
workingDirectory: workingDir.path,
281357
);
282-
printOnFailure('Output of flutter build web:');
358+
printOnFailure('Output of flutter ${flutterCommandArgs.join(" ")}:');
283359
printOnFailure(exec.stdout.toString());
284360
printOnFailure(exec.stderr.toString());
285361
expect(exec.exitCode, 0);

0 commit comments

Comments
 (0)