Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disentangle and align flutter build web --wasm flags #143517

Merged
merged 3 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions dev/devicelab/lib/tasks/web_benchmarks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ Future<TaskResult> runWebBenchmark(WebBenchmarkOptions benchmarkOptions) async {
await evalFlutter('build', options: <String>[
'web',
if (benchmarkOptions.useWasm) ...<String>[
'--O4',
'--wasm',
'--wasm-opt=debug',
'--omit-type-checks',
'--no-strip-wasm',
],
'--dart-define=FLUTTER_WEB_ENABLE_PROFILING=true',
if (!benchmarkOptions.useWasm) '--web-renderer=${benchmarkOptions.webRenderer}',
Expand Down
19 changes: 0 additions & 19 deletions packages/flutter_tools/lib/src/artifacts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ enum Artifact {
dart2jsSnapshot,
/// The dart snapshot of the dart2wasm compiler.
dart2wasmSnapshot,
/// The wasm-opt binary that ships with the dart-sdk
wasmOptBinary,

/// The root of the Linux desktop sources.
linuxDesktopPath,
Expand Down Expand Up @@ -194,8 +192,6 @@ String? _artifactToFileName(Artifact artifact, Platform hostPlatform, [ BuildMod
return 'dart2js.dart.snapshot';
case Artifact.dart2wasmSnapshot:
return 'dart2wasm_product.snapshot';
case Artifact.wasmOptBinary:
return 'wasm-opt$exe';
case Artifact.frontendServerSnapshotForEngineDartSdk:
return 'frontend_server_aot.dart.snapshot';
case Artifact.linuxDesktopPath:
Expand Down Expand Up @@ -566,7 +562,6 @@ class CachedArtifacts implements Artifacts {
case Artifact.engineDartAotRuntime:
case Artifact.dart2jsSnapshot:
case Artifact.dart2wasmSnapshot:
case Artifact.wasmOptBinary:
case Artifact.frontendServerSnapshotForEngineDartSdk:
case Artifact.constFinder:
case Artifact.flutterFramework:
Expand Down Expand Up @@ -608,7 +603,6 @@ class CachedArtifacts implements Artifacts {
case Artifact.engineDartAotRuntime:
case Artifact.dart2jsSnapshot:
case Artifact.dart2wasmSnapshot:
case Artifact.wasmOptBinary:
case Artifact.frontendServerSnapshotForEngineDartSdk:
case Artifact.constFinder:
case Artifact.flutterMacOSFramework:
Expand Down Expand Up @@ -668,7 +662,6 @@ class CachedArtifacts implements Artifacts {
case Artifact.engineDartAotRuntime:
case Artifact.dart2jsSnapshot:
case Artifact.dart2wasmSnapshot:
case Artifact.wasmOptBinary:
case Artifact.frontendServerSnapshotForEngineDartSdk:
case Artifact.icuData:
case Artifact.isolateSnapshotData:
Expand Down Expand Up @@ -708,11 +701,6 @@ class CachedArtifacts implements Artifacts {
_dartSdkPath(_cache), 'bin', 'snapshots',
_artifactToFileName(artifact, _platform),
);
case Artifact.wasmOptBinary:
return _fileSystem.path.join(
_dartSdkPath(_cache), 'bin', 'utils',
_artifactToFileName(artifact, _platform),
);
case Artifact.flutterTester:
case Artifact.vmSnapshotData:
case Artifact.isolateSnapshotData:
Expand Down Expand Up @@ -1039,8 +1027,6 @@ class CachedLocalEngineArtifacts implements Artifacts {
case Artifact.dart2wasmSnapshot:
case Artifact.frontendServerSnapshotForEngineDartSdk:
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'snapshots', artifactFileName);
case Artifact.wasmOptBinary:
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'utils', artifactFileName);
case Artifact.flutterToolsFileGenerators:
return _getFileGeneratorsPath();
case Artifact.flutterPreviewDevice:
Expand Down Expand Up @@ -1178,11 +1164,6 @@ class CachedLocalWebSdkArtifacts implements Artifacts {
_getDartSdkPath(), 'bin', 'snapshots',
_artifactToFileName(artifact, _platform, mode),
);
case Artifact.wasmOptBinary:
return _fileSystem.path.join(
_getDartSdkPath(), 'bin', 'utils',
_artifactToFileName(artifact, _platform, mode),
);
case Artifact.genSnapshot:
case Artifact.flutterTester:
case Artifact.flutterFramework:
Expand Down
50 changes: 29 additions & 21 deletions packages/flutter_tools/lib/src/commands/build_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ class BuildWebCommand extends BuildSubCommand {
usesWebRendererOption();
usesWebResourcesCdnFlag();

//
// Common compilation options among JavaScript and Wasm
//
argParser.addOption(
'optimization-level',
abbr: 'O',
help:
'Sets the optimization level used for Dart compilation to JavaScript/Wasm.',
defaultsTo: '${WebCompilerConfig.kDefaultOptimizationLevel}',
allowed: const <String>['1', '2', '3', '4'],
);

//
// JavaScript compilation options
//
Expand All @@ -72,10 +84,9 @@ class BuildWebCommand extends BuildSubCommand {
);
argParser.addOption('dart2js-optimization',
help: 'Sets the optimization level used for Dart compilation to JavaScript. '
'Valid values range from O1 to O4.',
defaultsTo: JsCompilerConfig.kDart2jsDefaultOptimizationLevel,
allowed: const <String>['O1', 'O2', 'O3', 'O4'],
);
'Deprecated: Please use "-O=<level>" / "--optimization-level=<level>".',
allowed: const <String>['O1', 'O2', 'O3', 'O4'],
);
argParser.addFlag('dump-info', negatable: false,
help: 'Passes "--dump-info" to the Javascript compiler which generates '
'information about the generated code is a .js.info.json file.'
Expand All @@ -98,19 +109,9 @@ class BuildWebCommand extends BuildSubCommand {
hide: !featureFlags.isFlutterWebWasmEnabled,
);
argParser.addFlag(
'omit-type-checks',
help: 'Omit type checks in Wasm output.\n'
'Reduces code size and improves performance, but may affect runtime correctness. Use with care.',
negatable: false,
hide: !featureFlags.isFlutterWebWasmEnabled,
);
argParser.addOption(
'wasm-opt',
help:
'Optimize output wasm using the Binaryen (https://github.com/WebAssembly/binaryen) tool.',
defaultsTo: WasmOptLevel.defaultValue.cliName,
allowed: WasmOptLevel.values.map<String>((WasmOptLevel e) => e.cliName),
allowedHelp: CliEnum.allowedHelp(WasmOptLevel.values),
'strip-wasm',
help: 'Whether to strip the resulting wasm file of static symbol names.',
defaultsTo: true,
hide: !featureFlags.isFlutterWebWasmEnabled,
);
}
Expand Down Expand Up @@ -138,6 +139,13 @@ class BuildWebCommand extends BuildSubCommand {
throwToolExit('"build web" is not currently supported. To enable, run "flutter config --enable-web".');
}

final int optimizationLevel = int.parse(stringArg('optimization-level')!);

final String? dart2jsOptimizationLevelValue = stringArg('dart2js-optimization');
final int jsOptimizationLevel = dart2jsOptimizationLevelValue != null
? int.parse(dart2jsOptimizationLevelValue.substring(1))
: optimizationLevel;

final List<WebCompilerConfig> compilerConfigs;
if (boolArg('wasm')) {
if (!featureFlags.isFlutterWebWasmEnabled) {
Expand All @@ -155,13 +163,13 @@ class BuildWebCommand extends BuildSubCommand {

compilerConfigs = <WebCompilerConfig>[
WasmCompilerConfig(
omitTypeChecks: boolArg('omit-type-checks'),
wasmOpt: WasmOptLevel.values.byName(stringArg('wasm-opt')!),
optimizationLevel: optimizationLevel,
stripWasm: boolArg('strip-wasm'),
renderer: WebRendererMode.skwasm,
),
JsCompilerConfig(
csp: boolArg('csp'),
optimizationLevel: stringArg('dart2js-optimization') ?? JsCompilerConfig.kDart2jsDefaultOptimizationLevel,
optimizationLevel: jsOptimizationLevel,
dumpInfo: boolArg('dump-info'),
nativeNullAssertions: boolArg('native-null-assertions'),
noFrequencyBasedMinification: boolArg('no-frequency-based-minification'),
Expand All @@ -175,7 +183,7 @@ class BuildWebCommand extends BuildSubCommand {
}
compilerConfigs = <WebCompilerConfig>[JsCompilerConfig(
csp: boolArg('csp'),
optimizationLevel: stringArg('dart2js-optimization') ?? JsCompilerConfig.kDart2jsDefaultOptimizationLevel,
optimizationLevel: jsOptimizationLevel,
dumpInfo: boolArg('dump-info'),
nativeNullAssertions: boolArg('native-null-assertions'),
noFrequencyBasedMinification: boolArg('no-frequency-based-minification'),
Expand Down
115 changes: 36 additions & 79 deletions packages/flutter_tools/lib/src/web/compiler_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import '../base/utils.dart';
import '../convert.dart';
import 'compile.dart';

Expand All @@ -12,15 +11,33 @@ enum CompileTarget {
}

sealed class WebCompilerConfig {
const WebCompilerConfig({required this.renderer});
const WebCompilerConfig({required this.renderer, required this.optimizationLevel});

/// The default optimization level for dart2js/dart2wasm.
static const int kDefaultOptimizationLevel = 4;

/// Build environment flag for [optimizationLevel].
static const String kOptimizationLevel = 'OptimizationLevel';

/// The compiler optimization level.
///
/// Valid values are O1 (lowest, profile default) to O4 (highest, release default).
final int optimizationLevel;

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

String get buildKey;

Map<String, Object> get buildEventAnalyticsValues => <String, Object>{};
Map<String, Object> get buildEventAnalyticsValues => <String, Object>{
'optimizationLevel': optimizationLevel,
};


Map<String, dynamic> get _buildKeyMap => <String, dynamic>{
'optimizationLevel': optimizationLevel,
};
}

/// Configuration for the Dart-to-Javascript compiler (dart2js).
Expand All @@ -29,7 +46,7 @@ class JsCompilerConfig extends WebCompilerConfig {
this.csp = false,
this.dumpInfo = false,
this.nativeNullAssertions = false,
this.optimizationLevel = kDart2jsDefaultOptimizationLevel,
super.optimizationLevel = WebCompilerConfig.kDefaultOptimizationLevel,
this.noFrequencyBasedMinification = false,
this.sourceMaps = true,
super.renderer = WebRendererMode.auto,
Expand All @@ -41,18 +58,10 @@ class JsCompilerConfig extends WebCompilerConfig {
required WebRendererMode renderer,
}) : this(
nativeNullAssertions: nativeNullAssertions,
optimizationLevel: kDart2jsDefaultOptimizationLevel,
optimizationLevel: WebCompilerConfig.kDefaultOptimizationLevel ,
renderer: renderer,
);

/// The default optimization level for dart2js.
///
/// Maps to [kDart2jsOptimization].
static const String kDart2jsDefaultOptimizationLevel = 'O4';

/// Build environment flag for [optimizationLevel].
static const String kDart2jsOptimization = 'Dart2jsOptimization';

/// Build environment flag for [dumpInfo].
static const String kDart2jsDumpInfo = 'Dart2jsDumpInfo';

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

/// The compiler optimization level.
///
/// Valid values are O1 (lowest, profile default) to O4 (highest, release default).
// TODO(kevmoo): consider storing this as an [int] and validating it!
final String optimizationLevel;

/// `true` if the JavaScript compiler build should output source maps.
final bool sourceMaps;

Expand All @@ -105,7 +108,7 @@ class JsCompilerConfig extends WebCompilerConfig {
/// Includes the contents of [toSharedCommandOptions].
List<String> toCommandOptions() => <String>[
...toSharedCommandOptions(),
'-$optimizationLevel',
'-O$optimizationLevel',
if (dumpInfo) '--dump-info',
if (noFrequencyBasedMinification) '--no-frequency-based-minification',
if (csp) '--csp',
Expand All @@ -114,11 +117,11 @@ class JsCompilerConfig extends WebCompilerConfig {
@override
String get buildKey {
final Map<String, dynamic> settings = <String, dynamic>{
...super._buildKeyMap,
'csp': csp,
'dumpInfo': dumpInfo,
'nativeNullAssertions': nativeNullAssertions,
'noFrequencyBasedMinification': noFrequencyBasedMinification,
'optimizationLevel': optimizationLevel,
'sourceMaps': sourceMaps,
};
return jsonEncode(settings);
Expand All @@ -128,79 +131,33 @@ class JsCompilerConfig extends WebCompilerConfig {
/// Configuration for the Wasm compiler.
class WasmCompilerConfig extends WebCompilerConfig {
const WasmCompilerConfig({
this.omitTypeChecks = false,
this.wasmOpt = WasmOptLevel.defaultValue,
super.optimizationLevel = WebCompilerConfig.kDefaultOptimizationLevel,
this.stripWasm = true,
super.renderer = WebRendererMode.auto,
});

/// Build environment for [omitTypeChecks].
static const String kOmitTypeChecks = 'WasmOmitTypeChecks';

/// Build environment for [wasmOpt].
static const String kRunWasmOpt = 'RunWasmOpt';

/// If `omit-type-checks` should be passed to `dart2wasm`.
final bool omitTypeChecks;
/// Build environment for [stripWasm].
static const String kStripWasm = 'StripWasm';

/// Run wasm-opt on the resulting module.
final WasmOptLevel wasmOpt;
/// Whether to strip the wasm file of static symbols.
final bool stripWasm;

@override
CompileTarget get compileTarget => CompileTarget.wasm;

List<String> toCommandOptions() {
// -O1: Optimizes
// -O2: Same as -O1 but also minifies (still semantics preserving)
// -O3: Same as -O2 but also omits implicit type checks.
// -O4: Same as -O3 but also omits explicit type checks.
// (NOTE: This differs from dart2js -O4 semantics atm.)

// Ortogonal: The name section is always kept by default and we emit it only
// in [WasmOptLevel.full] mode (similar to `--strip` of static symbols in
// AOT mode).
final String level = !omitTypeChecks ? '-O2' : '-O4';
return switch (wasmOpt) {
WasmOptLevel.none => <String>['-O0'],
WasmOptLevel.debug => <String>[level, '--no-minify'],
WasmOptLevel.full => <String>[level, '--no-name-section'],
};
return <String>[
'-O$optimizationLevel',
'--${stripWasm? 'no-' : ''}name-section',
];
}

@override
Map<String, Object> get buildEventAnalyticsValues => <String, Object>{
...super.buildEventAnalyticsValues,
kOmitTypeChecks: omitTypeChecks.toString(),
kRunWasmOpt: wasmOpt.name,
};

@override
String get buildKey {
final Map<String, dynamic> settings = <String, dynamic>{
'omitTypeChecks': omitTypeChecks,
'wasmOpt': wasmOpt.name,
...super._buildKeyMap,
'stripWasm': stripWasm,
};
return jsonEncode(settings);
}

}

enum WasmOptLevel implements CliEnum {
full,
debug,
none;

static const WasmOptLevel defaultValue = WasmOptLevel.full;

@override
String get cliName => name;

@override
String get helpText => switch (this) {
WasmOptLevel.none =>
'wasm-opt is not run. Fastest build; bigger, slower output.',
WasmOptLevel.debug =>
'Similar to `${WasmOptLevel.full.name}`, but member names are preserved. Debugging is easier, but size is a bit bigger.',
WasmOptLevel.full =>
'wasm-opt is run. Build time is slower, but output is smaller and faster.',
};
}
7 changes: 0 additions & 7 deletions packages/flutter_tools/test/general.shard/artifacts_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -427,13 +427,6 @@ void main() {
fileSystem.path.join('/flutter', 'prebuilts', 'linux-x64', 'dart-sdk',
'bin', 'snapshots', 'dart2js.dart.snapshot'),
);
expect(
artifacts.getArtifactPath(
Artifact.wasmOptBinary,
platform: TargetPlatform.web_javascript),
fileSystem.path.join('/flutter', 'prebuilts', 'linux-x64', 'dart-sdk',
'bin', 'utils', 'wasm-opt'),
);
});

testWithoutContext('getEngineType', () {
Expand Down