Skip to content

Commit 5a9fa1e

Browse files
Dual compile reland (#143262)
This is an attempt at a reland of #141396 The main changes here that are different than the original PR is fixes to wire up the `flutter test` command properly with the web renderer.
1 parent 4f1fc5a commit 5a9fa1e

36 files changed

+989
-465
lines changed

dev/benchmarks/macrobenchmarks/web/index.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
66
<head>
77
<meta charset="UTF-8">
88
<title>Web Benchmarks</title>
9+
<script src="flutter.js"></script>
910
</head>
1011
<body>
11-
<script src="main.dart.js" type="application/javascript"></script>
12+
<script>
13+
{{flutter_build_config}}
14+
_flutter.loader.load();
15+
</script>
1216
</body>
1317
</html>

dev/devicelab/lib/tasks/web_benchmarks.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Future<TaskResult> runWebBenchmark(WebBenchmarkOptions benchmarkOptions) async {
3939
'--omit-type-checks',
4040
],
4141
'--dart-define=FLUTTER_WEB_ENABLE_PROFILING=true',
42-
'--web-renderer=${benchmarkOptions.webRenderer}',
42+
if (!benchmarkOptions.useWasm) '--web-renderer=${benchmarkOptions.webRenderer}',
4343
'--profile',
4444
'--no-web-resources-cdn',
4545
'-t',
@@ -125,7 +125,7 @@ Future<TaskResult> runWebBenchmark(WebBenchmarkOptions benchmarkOptions) async {
125125
return Response.internalServerError(body: '$error');
126126
}
127127
}).add(createBuildDirectoryHandler(
128-
path.join(macrobenchmarksDirectory, 'build', benchmarkOptions.useWasm ? 'web_wasm' : 'web'),
128+
path.join(macrobenchmarksDirectory, 'build', 'web'),
129129
));
130130

131131
server = await io.HttpServer.bind('localhost', benchmarkServerPort);

dev/integration_tests/web_e2e_tests/web/index.html

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@
55
<html>
66
<head>
77
<title>Web Integration Tests</title>
8-
<script>
9-
// Use the local CanvasKit bundle instead of the CDN to reduce test flakiness.
10-
window.flutterConfiguration = {
11-
canvasKitBaseUrl: "/canvaskit/"
12-
};
13-
</script>
8+
<script src="flutter.js"></script>
149
</head>
1510
<body>
16-
<script src="main.dart.js"></script>
11+
<script>
12+
{{flutter_build_config}}
13+
_flutter.loader.load({
14+
config: {
15+
// Use the local CanvasKit bundle instead of the CDN to reduce test flakiness.
16+
canvasKitBaseUrl: "/canvaskit/",
17+
},
18+
});
19+
</script>
1720
</body>
1821
</html>

packages/flutter_tools/lib/src/build_info.dart

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import 'base/os.dart';
1212
import 'base/utils.dart';
1313
import 'convert.dart';
1414
import 'globals.dart' as globals;
15-
import 'web/compile.dart';
1615

1716
/// Whether icon font subsetting is enabled by default.
1817
const bool kIconTreeShakerEnabledDefault = true;
@@ -36,7 +35,6 @@ class BuildInfo {
3635
List<String>? dartDefines,
3736
this.bundleSkSLPath,
3837
List<String>? dartExperiments,
39-
this.webRenderer = WebRendererMode.auto,
4038
required this.treeShakeIcons,
4139
this.performanceMeasurementFile,
4240
this.packagesPath = '.dart_tool/package_config.json', // TODO(zanderso): make this required and remove the default.
@@ -131,9 +129,6 @@ class BuildInfo {
131129
/// A list of Dart experiments.
132130
final List<String> dartExperiments;
133131

134-
/// When compiling to web, which web renderer mode we are using (html, canvaskit, auto)
135-
final WebRendererMode webRenderer;
136-
137132
/// The name of a file where flutter assemble will output performance
138133
/// information in a JSON format.
139134
///
@@ -803,10 +798,6 @@ HostPlatform getCurrentHostPlatform() {
803798
return HostPlatform.linux_x64;
804799
}
805800

806-
FileSystemEntity getWebPlatformBinariesDirectory(Artifacts artifacts, WebRendererMode webRenderer) {
807-
return artifacts.getHostArtifact(HostArtifact.webPlatformKernelFolder);
808-
}
809-
810801
/// Returns the top-level build output directory.
811802
String getBuildDirectory([Config? config, FileSystem? fileSystem]) {
812803
// TODO(johnmccutchan): Stop calling this function as part of setting
@@ -849,8 +840,8 @@ String getMacOSBuildDirectory() {
849840
}
850841

851842
/// Returns the web build output directory.
852-
String getWebBuildDirectory([bool isWasm = false]) {
853-
return globals.fs.path.join(getBuildDirectory(), isWasm ? 'web_wasm' : 'web');
843+
String getWebBuildDirectory() {
844+
return globals.fs.path.join(getBuildDirectory(), 'web');
854845
}
855846

856847
/// Returns the Linux build output directory.

packages/flutter_tools/lib/src/build_system/build_system.dart

Lines changed: 105 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,15 @@ abstract class Target {
136136
/// A list of zero or more depfiles, located directly under {BUILD_DIR}.
137137
List<String> get depfiles => const <String>[];
138138

139+
/// A string that differentiates different build variants from each other
140+
/// with regards to build flags or settings on the target. This string should
141+
/// represent each build variant as a different unique value. If this value
142+
/// changes between builds, the target will be invalidated and rebuilt.
143+
///
144+
/// By default, this returns null, which indicates there is only one build
145+
/// variant, and the target won't invalidate or rebuild due to this property.
146+
String? get buildKey => null;
147+
139148
/// Whether this target can be executed with the given [environment].
140149
///
141150
/// Returning `true` will cause [build] to be skipped. This is equivalent
@@ -156,6 +165,7 @@ abstract class Target {
156165
<Node>[
157166
for (final Target target in dependencies) target._toNode(environment),
158167
],
168+
buildKey,
159169
environment,
160170
inputsFiles.containsNewDepfile,
161171
);
@@ -181,9 +191,11 @@ abstract class Target {
181191
for (final File output in outputs) {
182192
outputPaths.add(output.path);
183193
}
194+
final String? key = buildKey;
184195
final Map<String, Object> result = <String, Object>{
185196
'inputs': inputPaths,
186197
'outputs': outputPaths,
198+
if (key != null) 'buildKey': key,
187199
};
188200
if (!stamp.existsSync()) {
189201
stamp.createSync();
@@ -218,6 +230,7 @@ abstract class Target {
218230
/// This requires constants from the [Environment] to resolve the paths of
219231
/// inputs and the output stamp.
220232
Map<String, Object> toJson(Environment environment) {
233+
final String? key = buildKey;
221234
return <String, Object>{
222235
'name': name,
223236
'dependencies': <String>[
@@ -229,6 +242,7 @@ abstract class Target {
229242
'outputs': <String>[
230243
for (final File file in resolveOutputs(environment).sources) file.path,
231244
],
245+
if (key != null) 'buildKey': key,
232246
'stamp': _findStampFile(environment).absolute.path,
233247
};
234248
}
@@ -980,50 +994,86 @@ void verifyOutputDirectories(List<File> outputs, Environment environment, Target
980994

981995
/// A node in the build graph.
982996
class Node {
983-
Node(
984-
this.target,
985-
this.inputs,
986-
this.outputs,
987-
this.dependencies,
997+
factory Node(
998+
Target target,
999+
List<File> inputs,
1000+
List<File> outputs,
1001+
List<Node> dependencies,
1002+
String? buildKey,
9881003
Environment environment,
989-
this.missingDepfile,
1004+
bool missingDepfile,
9901005
) {
9911006
final File stamp = target._findStampFile(environment);
1007+
Map<String, Object?>? stampValues;
9921008

9931009
// If the stamp file doesn't exist, we haven't run this step before and
9941010
// all inputs were added.
995-
if (!stamp.existsSync()) {
996-
// No stamp file, not safe to skip.
997-
_dirty = true;
998-
return;
999-
}
1000-
final String content = stamp.readAsStringSync();
1001-
// Something went wrong writing the stamp file.
1002-
if (content.isEmpty) {
1003-
stamp.deleteSync();
1004-
// Malformed stamp file, not safe to skip.
1005-
_dirty = true;
1006-
return;
1007-
}
1008-
Map<String, Object?>? values;
1009-
try {
1010-
values = castStringKeyedMap(json.decode(content));
1011-
} on FormatException {
1012-
// The json is malformed in some way.
1013-
_dirty = true;
1014-
return;
1011+
if (stamp.existsSync()) {
1012+
final String content = stamp.readAsStringSync();
1013+
if (content.isEmpty) {
1014+
stamp.deleteSync();
1015+
} else {
1016+
try {
1017+
stampValues = castStringKeyedMap(json.decode(content));
1018+
} on FormatException {
1019+
// The json is malformed in some way.
1020+
}
1021+
}
10151022
}
1016-
final Object? inputs = values?['inputs'];
1017-
final Object? outputs = values?['outputs'];
1018-
if (inputs is List<Object?> && outputs is List<Object?>) {
1019-
inputs.cast<String?>().whereType<String>().forEach(previousInputs.add);
1020-
outputs.cast<String?>().whereType<String>().forEach(previousOutputs.add);
1021-
} else {
1022-
// The json is malformed in some way.
1023-
_dirty = true;
1023+
if (stampValues != null) {
1024+
final String? previousBuildKey = stampValues['buildKey'] as String?;
1025+
final Object? stampInputs = stampValues['inputs'];
1026+
final Object? stampOutputs = stampValues['outputs'];
1027+
if (stampInputs is List<Object?> && stampOutputs is List<Object?>) {
1028+
final Set<String> previousInputs = stampInputs.whereType<String>().toSet();
1029+
final Set<String> previousOutputs = stampOutputs.whereType<String>().toSet();
1030+
return Node.withStamp(
1031+
target,
1032+
inputs,
1033+
previousInputs,
1034+
outputs,
1035+
previousOutputs,
1036+
dependencies,
1037+
buildKey,
1038+
previousBuildKey,
1039+
missingDepfile,
1040+
);
1041+
}
10241042
}
1043+
return Node.withNoStamp(
1044+
target,
1045+
inputs,
1046+
outputs,
1047+
dependencies,
1048+
buildKey,
1049+
missingDepfile,
1050+
);
10251051
}
10261052

1053+
Node.withNoStamp(
1054+
this.target,
1055+
this.inputs,
1056+
this.outputs,
1057+
this.dependencies,
1058+
this.buildKey,
1059+
this.missingDepfile,
1060+
) : previousInputs = <String>{},
1061+
previousOutputs = <String>{},
1062+
previousBuildKey = null,
1063+
_dirty = true;
1064+
1065+
Node.withStamp(
1066+
this.target,
1067+
this.inputs,
1068+
this.previousInputs,
1069+
this.outputs,
1070+
this.previousOutputs,
1071+
this.dependencies,
1072+
this.buildKey,
1073+
this.previousBuildKey,
1074+
this.missingDepfile,
1075+
) : _dirty = false;
1076+
10271077
/// The resolved input files.
10281078
///
10291079
/// These files may not yet exist if they are produced by previous steps.
@@ -1034,6 +1084,11 @@ class Node {
10341084
/// These files may not yet exist if the target hasn't run yet.
10351085
final List<File> outputs;
10361086

1087+
/// The current build key of the target
1088+
///
1089+
/// See `buildKey` in the `Target` class for more information.
1090+
final String? buildKey;
1091+
10371092
/// Whether this node is missing a depfile.
10381093
///
10391094
/// This requires an additional pass of source resolution after the target
@@ -1047,10 +1102,15 @@ class Node {
10471102
final List<Node> dependencies;
10481103

10491104
/// Output file paths from the previous invocation of this build node.
1050-
final Set<String> previousOutputs = <String>{};
1105+
final Set<String> previousOutputs;
10511106

10521107
/// Input file paths from the previous invocation of this build node.
1053-
final Set<String> previousInputs = <String>{};
1108+
final Set<String> previousInputs;
1109+
1110+
/// The buildKey from the previous invocation of this build node.
1111+
///
1112+
/// See `buildKey` in the `Target` class for more information.
1113+
final String? previousBuildKey;
10541114

10551115
/// One or more reasons why a task was invalidated.
10561116
///
@@ -1074,6 +1134,10 @@ class Node {
10741134
FileSystem fileSystem,
10751135
Logger logger,
10761136
) {
1137+
if (buildKey != previousBuildKey) {
1138+
_invalidate(InvalidatedReasonKind.buildKeyChanged);
1139+
_dirty = true;
1140+
}
10771141
final Set<String> currentOutputPaths = <String>{
10781142
for (final File file in outputs) file.path,
10791143
};
@@ -1173,7 +1237,8 @@ class InvalidatedReason {
11731237
InvalidatedReasonKind.inputChanged => 'The following inputs have updated contents: ${data.join(',')}',
11741238
InvalidatedReasonKind.outputChanged => 'The following outputs have updated contents: ${data.join(',')}',
11751239
InvalidatedReasonKind.outputMissing => 'The following outputs were missing: ${data.join(',')}',
1176-
InvalidatedReasonKind.outputSetChanged => 'The following outputs were removed from the output set: ${data.join(',')}'
1240+
InvalidatedReasonKind.outputSetChanged => 'The following outputs were removed from the output set: ${data.join(',')}',
1241+
InvalidatedReasonKind.buildKeyChanged => 'The target build key changed.',
11771242
};
11781243
}
11791244
}
@@ -1195,4 +1260,7 @@ enum InvalidatedReasonKind {
11951260

11961261
/// The set of expected output files changed.
11971262
outputSetChanged,
1263+
1264+
/// The build key changed
1265+
buildKeyChanged,
11981266
}

packages/flutter_tools/lib/src/build_system/build_targets.dart

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// found in the LICENSE file.
44

55
import '../base/file_system.dart';
6-
import '../web/compile.dart';
6+
import '../web/compiler_config.dart';
77
import './build_system.dart';
88

99
/// Commonly used build [Target]s.
@@ -14,11 +14,7 @@ abstract class BuildTargets {
1414
Target get releaseCopyFlutterBundle;
1515
Target get generateLocalizationsTarget;
1616
Target get dartPluginRegistrantTarget;
17-
Target webServiceWorker(
18-
FileSystem fileSystem, {
19-
required WebRendererMode webRenderer,
20-
required bool isWasm
21-
});
17+
Target webServiceWorker(FileSystem fileSystem, List<WebCompilerConfig> compileConfigs);
2218
}
2319

2420
/// BuildTargets that return NoOpTarget for every action.
@@ -38,11 +34,7 @@ class NoOpBuildTargets extends BuildTargets {
3834
Target get dartPluginRegistrantTarget => const _NoOpTarget();
3935

4036
@override
41-
Target webServiceWorker(
42-
FileSystem fileSystem, {
43-
required WebRendererMode webRenderer,
44-
required bool isWasm,
45-
}) => const _NoOpTarget();
37+
Target webServiceWorker(FileSystem fileSystem, List<WebCompilerConfig> compileConfigs) => const _NoOpTarget();
4638
}
4739

4840
/// A [Target] that does nothing.

0 commit comments

Comments
 (0)