Skip to content

Commit 178898e

Browse files
authored
Disentangle and align flutter build web --wasm flags (#143517)
* Make `flutter build web` have one option that determins the optimization level: `-O<level>` / `--optimization-level=<level>` => Defaulting to -O4 => Will apply to both dart2js and dart2wasm * Deprecate `--dart2js-optimization=O<level>` * Disentagle concept of optimization from concept of static symbols => Add a `--strip-wasm` / `--no-strip-wasm` flag that determins whether static symbols are kept in the resulting wasm file. * Remove copy&past'ed code in the tests for wasm build tests * Cleanup some artifacts code, now that we no longer use `wasm-opt` inside flutter tools
1 parent 2d4f5a6 commit 178898e

File tree

7 files changed

+128
-303
lines changed

7 files changed

+128
-303
lines changed

dev/devicelab/lib/tasks/web_benchmarks.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ Future<TaskResult> runWebBenchmark(WebBenchmarkOptions benchmarkOptions) async {
3434
await evalFlutter('build', options: <String>[
3535
'web',
3636
if (benchmarkOptions.useWasm) ...<String>[
37+
'--O4',
3738
'--wasm',
38-
'--wasm-opt=debug',
39-
'--omit-type-checks',
39+
'--no-strip-wasm',
4040
],
4141
'--dart-define=FLUTTER_WEB_ENABLE_PROFILING=true',
4242
if (!benchmarkOptions.useWasm) '--web-renderer=${benchmarkOptions.webRenderer}',

packages/flutter_tools/lib/src/artifacts.dart

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ enum Artifact {
4444
dart2jsSnapshot,
4545
/// The dart snapshot of the dart2wasm compiler.
4646
dart2wasmSnapshot,
47-
/// The wasm-opt binary that ships with the dart-sdk
48-
wasmOptBinary,
4947

5048
/// The root of the Linux desktop sources.
5149
linuxDesktopPath,
@@ -194,8 +192,6 @@ String? _artifactToFileName(Artifact artifact, Platform hostPlatform, [ BuildMod
194192
return 'dart2js.dart.snapshot';
195193
case Artifact.dart2wasmSnapshot:
196194
return 'dart2wasm_product.snapshot';
197-
case Artifact.wasmOptBinary:
198-
return 'wasm-opt$exe';
199195
case Artifact.frontendServerSnapshotForEngineDartSdk:
200196
return 'frontend_server_aot.dart.snapshot';
201197
case Artifact.linuxDesktopPath:
@@ -566,7 +562,6 @@ class CachedArtifacts implements Artifacts {
566562
case Artifact.engineDartAotRuntime:
567563
case Artifact.dart2jsSnapshot:
568564
case Artifact.dart2wasmSnapshot:
569-
case Artifact.wasmOptBinary:
570565
case Artifact.frontendServerSnapshotForEngineDartSdk:
571566
case Artifact.constFinder:
572567
case Artifact.flutterFramework:
@@ -608,7 +603,6 @@ class CachedArtifacts implements Artifacts {
608603
case Artifact.engineDartAotRuntime:
609604
case Artifact.dart2jsSnapshot:
610605
case Artifact.dart2wasmSnapshot:
611-
case Artifact.wasmOptBinary:
612606
case Artifact.frontendServerSnapshotForEngineDartSdk:
613607
case Artifact.constFinder:
614608
case Artifact.flutterMacOSFramework:
@@ -668,7 +662,6 @@ class CachedArtifacts implements Artifacts {
668662
case Artifact.engineDartAotRuntime:
669663
case Artifact.dart2jsSnapshot:
670664
case Artifact.dart2wasmSnapshot:
671-
case Artifact.wasmOptBinary:
672665
case Artifact.frontendServerSnapshotForEngineDartSdk:
673666
case Artifact.icuData:
674667
case Artifact.isolateSnapshotData:
@@ -708,11 +701,6 @@ class CachedArtifacts implements Artifacts {
708701
_dartSdkPath(_cache), 'bin', 'snapshots',
709702
_artifactToFileName(artifact, _platform),
710703
);
711-
case Artifact.wasmOptBinary:
712-
return _fileSystem.path.join(
713-
_dartSdkPath(_cache), 'bin', 'utils',
714-
_artifactToFileName(artifact, _platform),
715-
);
716704
case Artifact.flutterTester:
717705
case Artifact.vmSnapshotData:
718706
case Artifact.isolateSnapshotData:
@@ -1039,8 +1027,6 @@ class CachedLocalEngineArtifacts implements Artifacts {
10391027
case Artifact.dart2wasmSnapshot:
10401028
case Artifact.frontendServerSnapshotForEngineDartSdk:
10411029
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'snapshots', artifactFileName);
1042-
case Artifact.wasmOptBinary:
1043-
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'utils', artifactFileName);
10441030
case Artifact.flutterToolsFileGenerators:
10451031
return _getFileGeneratorsPath();
10461032
case Artifact.flutterPreviewDevice:
@@ -1178,11 +1164,6 @@ class CachedLocalWebSdkArtifacts implements Artifacts {
11781164
_getDartSdkPath(), 'bin', 'snapshots',
11791165
_artifactToFileName(artifact, _platform, mode),
11801166
);
1181-
case Artifact.wasmOptBinary:
1182-
return _fileSystem.path.join(
1183-
_getDartSdkPath(), 'bin', 'utils',
1184-
_artifactToFileName(artifact, _platform, mode),
1185-
);
11861167
case Artifact.genSnapshot:
11871168
case Artifact.flutterTester:
11881169
case Artifact.flutterFramework:

packages/flutter_tools/lib/src/commands/build_web.dart

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ class BuildWebCommand extends BuildSubCommand {
5555
usesWebRendererOption();
5656
usesWebResourcesCdnFlag();
5757

58+
//
59+
// Common compilation options among JavaScript and Wasm
60+
//
61+
argParser.addOption(
62+
'optimization-level',
63+
abbr: 'O',
64+
help:
65+
'Sets the optimization level used for Dart compilation to JavaScript/Wasm.',
66+
defaultsTo: '${WebCompilerConfig.kDefaultOptimizationLevel}',
67+
allowed: const <String>['1', '2', '3', '4'],
68+
);
69+
5870
//
5971
// JavaScript compilation options
6072
//
@@ -72,10 +84,9 @@ class BuildWebCommand extends BuildSubCommand {
7284
);
7385
argParser.addOption('dart2js-optimization',
7486
help: 'Sets the optimization level used for Dart compilation to JavaScript. '
75-
'Valid values range from O1 to O4.',
76-
defaultsTo: JsCompilerConfig.kDart2jsDefaultOptimizationLevel,
77-
allowed: const <String>['O1', 'O2', 'O3', 'O4'],
78-
);
87+
'Deprecated: Please use "-O=<level>" / "--optimization-level=<level>".',
88+
allowed: const <String>['O1', 'O2', 'O3', 'O4'],
89+
);
7990
argParser.addFlag('dump-info', negatable: false,
8091
help: 'Passes "--dump-info" to the Javascript compiler which generates '
8192
'information about the generated code is a .js.info.json file.'
@@ -98,19 +109,9 @@ class BuildWebCommand extends BuildSubCommand {
98109
hide: !featureFlags.isFlutterWebWasmEnabled,
99110
);
100111
argParser.addFlag(
101-
'omit-type-checks',
102-
help: 'Omit type checks in Wasm output.\n'
103-
'Reduces code size and improves performance, but may affect runtime correctness. Use with care.',
104-
negatable: false,
105-
hide: !featureFlags.isFlutterWebWasmEnabled,
106-
);
107-
argParser.addOption(
108-
'wasm-opt',
109-
help:
110-
'Optimize output wasm using the Binaryen (https://github.com/WebAssembly/binaryen) tool.',
111-
defaultsTo: WasmOptLevel.defaultValue.cliName,
112-
allowed: WasmOptLevel.values.map<String>((WasmOptLevel e) => e.cliName),
113-
allowedHelp: CliEnum.allowedHelp(WasmOptLevel.values),
112+
'strip-wasm',
113+
help: 'Whether to strip the resulting wasm file of static symbol names.',
114+
defaultsTo: true,
114115
hide: !featureFlags.isFlutterWebWasmEnabled,
115116
);
116117
}
@@ -138,6 +139,13 @@ class BuildWebCommand extends BuildSubCommand {
138139
throwToolExit('"build web" is not currently supported. To enable, run "flutter config --enable-web".');
139140
}
140141

142+
final int optimizationLevel = int.parse(stringArg('optimization-level')!);
143+
144+
final String? dart2jsOptimizationLevelValue = stringArg('dart2js-optimization');
145+
final int jsOptimizationLevel = dart2jsOptimizationLevelValue != null
146+
? int.parse(dart2jsOptimizationLevelValue.substring(1))
147+
: optimizationLevel;
148+
141149
final List<WebCompilerConfig> compilerConfigs;
142150
if (boolArg('wasm')) {
143151
if (!featureFlags.isFlutterWebWasmEnabled) {
@@ -155,13 +163,13 @@ class BuildWebCommand extends BuildSubCommand {
155163

156164
compilerConfigs = <WebCompilerConfig>[
157165
WasmCompilerConfig(
158-
omitTypeChecks: boolArg('omit-type-checks'),
159-
wasmOpt: WasmOptLevel.values.byName(stringArg('wasm-opt')!),
166+
optimizationLevel: optimizationLevel,
167+
stripWasm: boolArg('strip-wasm'),
160168
renderer: WebRendererMode.skwasm,
161169
),
162170
JsCompilerConfig(
163171
csp: boolArg('csp'),
164-
optimizationLevel: stringArg('dart2js-optimization') ?? JsCompilerConfig.kDart2jsDefaultOptimizationLevel,
172+
optimizationLevel: jsOptimizationLevel,
165173
dumpInfo: boolArg('dump-info'),
166174
nativeNullAssertions: boolArg('native-null-assertions'),
167175
noFrequencyBasedMinification: boolArg('no-frequency-based-minification'),
@@ -175,7 +183,7 @@ class BuildWebCommand extends BuildSubCommand {
175183
}
176184
compilerConfigs = <WebCompilerConfig>[JsCompilerConfig(
177185
csp: boolArg('csp'),
178-
optimizationLevel: stringArg('dart2js-optimization') ?? JsCompilerConfig.kDart2jsDefaultOptimizationLevel,
186+
optimizationLevel: jsOptimizationLevel,
179187
dumpInfo: boolArg('dump-info'),
180188
nativeNullAssertions: boolArg('native-null-assertions'),
181189
noFrequencyBasedMinification: boolArg('no-frequency-based-minification'),

packages/flutter_tools/lib/src/web/compiler_config.dart

Lines changed: 36 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import '../base/utils.dart';
65
import '../convert.dart';
76
import 'compile.dart';
87

@@ -12,15 +11,33 @@ enum CompileTarget {
1211
}
1312

1413
sealed class WebCompilerConfig {
15-
const WebCompilerConfig({required this.renderer});
14+
const WebCompilerConfig({required this.renderer, required this.optimizationLevel});
15+
16+
/// The default optimization level for dart2js/dart2wasm.
17+
static const int kDefaultOptimizationLevel = 4;
18+
19+
/// Build environment flag for [optimizationLevel].
20+
static const String kOptimizationLevel = 'OptimizationLevel';
21+
22+
/// The compiler optimization level.
23+
///
24+
/// Valid values are O1 (lowest, profile default) to O4 (highest, release default).
25+
final int optimizationLevel;
1626

1727
/// Returns which target this compiler outputs (js or wasm)
1828
CompileTarget get compileTarget;
1929
final WebRendererMode renderer;
2030

2131
String get buildKey;
2232

23-
Map<String, Object> get buildEventAnalyticsValues => <String, Object>{};
33+
Map<String, Object> get buildEventAnalyticsValues => <String, Object>{
34+
'optimizationLevel': optimizationLevel,
35+
};
36+
37+
38+
Map<String, dynamic> get _buildKeyMap => <String, dynamic>{
39+
'optimizationLevel': optimizationLevel,
40+
};
2441
}
2542

2643
/// Configuration for the Dart-to-Javascript compiler (dart2js).
@@ -29,7 +46,7 @@ class JsCompilerConfig extends WebCompilerConfig {
2946
this.csp = false,
3047
this.dumpInfo = false,
3148
this.nativeNullAssertions = false,
32-
this.optimizationLevel = kDart2jsDefaultOptimizationLevel,
49+
super.optimizationLevel = WebCompilerConfig.kDefaultOptimizationLevel,
3350
this.noFrequencyBasedMinification = false,
3451
this.sourceMaps = true,
3552
super.renderer = WebRendererMode.auto,
@@ -41,18 +58,10 @@ class JsCompilerConfig extends WebCompilerConfig {
4158
required WebRendererMode renderer,
4259
}) : this(
4360
nativeNullAssertions: nativeNullAssertions,
44-
optimizationLevel: kDart2jsDefaultOptimizationLevel,
61+
optimizationLevel: WebCompilerConfig.kDefaultOptimizationLevel ,
4562
renderer: renderer,
4663
);
4764

48-
/// The default optimization level for dart2js.
49-
///
50-
/// Maps to [kDart2jsOptimization].
51-
static const String kDart2jsDefaultOptimizationLevel = 'O4';
52-
53-
/// Build environment flag for [optimizationLevel].
54-
static const String kDart2jsOptimization = 'Dart2jsOptimization';
55-
5665
/// Build environment flag for [dumpInfo].
5766
static const String kDart2jsDumpInfo = 'Dart2jsDumpInfo';
5867

@@ -82,12 +91,6 @@ class JsCompilerConfig extends WebCompilerConfig {
8291
// TODO(kevmoo): consider renaming this to be "positive". Double negatives are confusing.
8392
final bool noFrequencyBasedMinification;
8493

85-
/// The compiler optimization level.
86-
///
87-
/// Valid values are O1 (lowest, profile default) to O4 (highest, release default).
88-
// TODO(kevmoo): consider storing this as an [int] and validating it!
89-
final String optimizationLevel;
90-
9194
/// `true` if the JavaScript compiler build should output source maps.
9295
final bool sourceMaps;
9396

@@ -105,7 +108,7 @@ class JsCompilerConfig extends WebCompilerConfig {
105108
/// Includes the contents of [toSharedCommandOptions].
106109
List<String> toCommandOptions() => <String>[
107110
...toSharedCommandOptions(),
108-
'-$optimizationLevel',
111+
'-O$optimizationLevel',
109112
if (dumpInfo) '--dump-info',
110113
if (noFrequencyBasedMinification) '--no-frequency-based-minification',
111114
if (csp) '--csp',
@@ -114,11 +117,11 @@ class JsCompilerConfig extends WebCompilerConfig {
114117
@override
115118
String get buildKey {
116119
final Map<String, dynamic> settings = <String, dynamic>{
120+
...super._buildKeyMap,
117121
'csp': csp,
118122
'dumpInfo': dumpInfo,
119123
'nativeNullAssertions': nativeNullAssertions,
120124
'noFrequencyBasedMinification': noFrequencyBasedMinification,
121-
'optimizationLevel': optimizationLevel,
122125
'sourceMaps': sourceMaps,
123126
};
124127
return jsonEncode(settings);
@@ -128,79 +131,33 @@ class JsCompilerConfig extends WebCompilerConfig {
128131
/// Configuration for the Wasm compiler.
129132
class WasmCompilerConfig extends WebCompilerConfig {
130133
const WasmCompilerConfig({
131-
this.omitTypeChecks = false,
132-
this.wasmOpt = WasmOptLevel.defaultValue,
134+
super.optimizationLevel = WebCompilerConfig.kDefaultOptimizationLevel,
135+
this.stripWasm = true,
133136
super.renderer = WebRendererMode.auto,
134137
});
135138

136-
/// Build environment for [omitTypeChecks].
137-
static const String kOmitTypeChecks = 'WasmOmitTypeChecks';
138-
139-
/// Build environment for [wasmOpt].
140-
static const String kRunWasmOpt = 'RunWasmOpt';
141-
142-
/// If `omit-type-checks` should be passed to `dart2wasm`.
143-
final bool omitTypeChecks;
139+
/// Build environment for [stripWasm].
140+
static const String kStripWasm = 'StripWasm';
144141

145-
/// Run wasm-opt on the resulting module.
146-
final WasmOptLevel wasmOpt;
142+
/// Whether to strip the wasm file of static symbols.
143+
final bool stripWasm;
147144

148145
@override
149146
CompileTarget get compileTarget => CompileTarget.wasm;
150147

151148
List<String> toCommandOptions() {
152-
// -O1: Optimizes
153-
// -O2: Same as -O1 but also minifies (still semantics preserving)
154-
// -O3: Same as -O2 but also omits implicit type checks.
155-
// -O4: Same as -O3 but also omits explicit type checks.
156-
// (NOTE: This differs from dart2js -O4 semantics atm.)
157-
158-
// Ortogonal: The name section is always kept by default and we emit it only
159-
// in [WasmOptLevel.full] mode (similar to `--strip` of static symbols in
160-
// AOT mode).
161-
final String level = !omitTypeChecks ? '-O2' : '-O4';
162-
return switch (wasmOpt) {
163-
WasmOptLevel.none => <String>['-O0'],
164-
WasmOptLevel.debug => <String>[level, '--no-minify'],
165-
WasmOptLevel.full => <String>[level, '--no-name-section'],
166-
};
149+
return <String>[
150+
'-O$optimizationLevel',
151+
'--${stripWasm? 'no-' : ''}name-section',
152+
];
167153
}
168154

169-
@override
170-
Map<String, Object> get buildEventAnalyticsValues => <String, Object>{
171-
...super.buildEventAnalyticsValues,
172-
kOmitTypeChecks: omitTypeChecks.toString(),
173-
kRunWasmOpt: wasmOpt.name,
174-
};
175-
176155
@override
177156
String get buildKey {
178157
final Map<String, dynamic> settings = <String, dynamic>{
179-
'omitTypeChecks': omitTypeChecks,
180-
'wasmOpt': wasmOpt.name,
158+
...super._buildKeyMap,
159+
'stripWasm': stripWasm,
181160
};
182161
return jsonEncode(settings);
183162
}
184-
185-
}
186-
187-
enum WasmOptLevel implements CliEnum {
188-
full,
189-
debug,
190-
none;
191-
192-
static const WasmOptLevel defaultValue = WasmOptLevel.full;
193-
194-
@override
195-
String get cliName => name;
196-
197-
@override
198-
String get helpText => switch (this) {
199-
WasmOptLevel.none =>
200-
'wasm-opt is not run. Fastest build; bigger, slower output.',
201-
WasmOptLevel.debug =>
202-
'Similar to `${WasmOptLevel.full.name}`, but member names are preserved. Debugging is easier, but size is a bit bigger.',
203-
WasmOptLevel.full =>
204-
'wasm-opt is run. Build time is slower, but output is smaller and faster.',
205-
};
206163
}

packages/flutter_tools/test/general.shard/artifacts_test.dart

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -427,13 +427,6 @@ void main() {
427427
fileSystem.path.join('/flutter', 'prebuilts', 'linux-x64', 'dart-sdk',
428428
'bin', 'snapshots', 'dart2js.dart.snapshot'),
429429
);
430-
expect(
431-
artifacts.getArtifactPath(
432-
Artifact.wasmOptBinary,
433-
platform: TargetPlatform.web_javascript),
434-
fileSystem.path.join('/flutter', 'prebuilts', 'linux-x64', 'dart-sdk',
435-
'bin', 'utils', 'wasm-opt'),
436-
);
437430
});
438431

439432
testWithoutContext('getEngineType', () {

0 commit comments

Comments
 (0)