Unverified Commit 1045c3d0 authored by Kevin Moore's avatar Kevin Moore Committed by GitHub

flutter_tool: add and use WebCompilerConfig (#124183)

flutter_tool: add and use WebCompilerConfig
parent 98f35be7
......@@ -34,37 +34,12 @@ import 'shader_compiler.dart';
/// Whether the application has web plugins.
const String kHasWebPlugins = 'HasWebPlugins';
/// An override for the dart2js build mode.
///
/// Valid values are O1 (lowest, profile default) to O4 (highest, release default).
const String kDart2jsOptimization = 'Dart2jsOptimization';
/// The default optimization level for dart2js.
///
/// Maps to [kDart2jsOptimization].
const String kDart2jsDefaultOptimizationLevel = 'O4';
/// If `--dump-info` should be passed to dart2js.
const String kDart2jsDumpInfo = 'Dart2jsDumpInfo';
// If `--no-frequency-based-minification` should be based to dart2js
const String kDart2jsNoFrequencyBasedMinification = 'Dart2jsNoFrequencyBasedMinification';
/// Whether to disable dynamic generation code to satisfy csp policies.
const String kCspMode = 'cspMode';
/// Base href to set in index.html in flutter build command
const String kBaseHref = 'baseHref';
/// The caching strategy to use for service worker generation.
const String kServiceWorkerStrategy = 'ServiceWorkerStrategy';
/// Whether the dart2js build should output source maps.
const String kSourceMapsEnabled = 'SourceMaps';
/// Whether the dart2js native null assertions are enabled.
const String kNativeNullAssertions = 'NativeNullAssertions';
const String kOfflineFirst = 'offline-first';
const String kNoneWorker = 'none';
......@@ -201,8 +176,7 @@ class Dart2JSTarget extends Dart2WebTarget {
throw MissingDefineException(kBuildMode, name);
}
final BuildMode buildMode = getBuildModeForName(buildModeEnvironment);
final bool sourceMapsEnabled = environment.defines[kSourceMapsEnabled] == 'true';
final bool nativeNullAssertions = environment.defines[kNativeNullAssertions] == 'true';
final JsCompilerConfig compilerConfig = JsCompilerConfig.fromBuildSystemEnvironment(environment.defines);
final Artifacts artifacts = globals.artifacts!;
final String platformBinariesPath = getWebPlatformBinariesDirectory(artifacts, webRenderer).path;
final List<String> sharedCommandOptions = <String>[
......@@ -212,20 +186,17 @@ class Dart2JSTarget extends Dart2WebTarget {
'--platform-binaries=$platformBinariesPath',
...decodeCommaSeparated(environment.defines, kExtraFrontEndOptions),
'--invoker=flutter_tool',
if (nativeNullAssertions)
'--native-null-assertions',
if (buildMode == BuildMode.profile)
'-Ddart.vm.profile=true'
else
'-Ddart.vm.product=true',
for (final String dartDefine in decodeDartDefines(environment.defines, kDartDefines))
'-D$dartDefine',
if (!sourceMapsEnabled)
'--no-source-maps',
];
final List<String> compilationArgs = <String>[
...sharedCommandOptions,
...compilerConfig.toSharedCommandOptions(),
'-o',
environment.buildDir.childFile('app.dill').path,
'--packages=.dart_tool/package_config.json',
......@@ -241,19 +212,12 @@ class Dart2JSTarget extends Dart2WebTarget {
throw Exception(_collectOutput(kernelResult));
}
final String dart2jsOptimization = environment.defines[kDart2jsOptimization] ?? kDart2jsDefaultOptimizationLevel;
final bool dumpInfo = environment.defines[kDart2jsDumpInfo] == 'true';
final bool noFrequencyBasedMinification = environment.defines[kDart2jsNoFrequencyBasedMinification] == 'true';
final File outputJSFile = environment.buildDir.childFile('main.dart.js');
final bool csp = environment.defines[kCspMode] == 'true';
final ProcessResult javaScriptResult = await environment.processManager.run(<String>[
...sharedCommandOptions,
'-$dart2jsOptimization',
if (buildMode == BuildMode.profile) '--no-minify',
if (dumpInfo) '--dump-info',
if (noFrequencyBasedMinification) '--no-frequency-based-minification',
if (csp) '--csp',
...compilerConfig.toCommandOptions(),
'-o',
outputJSFile.path,
environment.buildDir.childFile('app.dill').path, // dartfile
......
......@@ -81,7 +81,7 @@ class BuildWebCommand extends BuildSubCommand {
argParser.addOption('dart2js-optimization',
help: 'Sets the optimization level used for Dart compilation to JavaScript. '
'Valid values range from O0 to O4.',
defaultsTo: kDart2jsDefaultOptimizationLevel
defaultsTo: JsCompilerConfig.kDart2jsDefaultOptimizationLevel
);
argParser.addFlag('dump-info', negatable: false,
help: 'Passes "--dump-info" to the Javascript compiler which generates '
......@@ -134,9 +134,21 @@ class BuildWebCommand extends BuildSubCommand {
throwToolExit('"build web" is not currently supported. To enable, run "flutter config --enable-web".');
}
final bool wasmRequested = boolArg(FlutterOptions.kWebWasmFlag);
if (wasmRequested && !featureFlags.isFlutterWebWasmEnabled) {
throwToolExit('Compiling to WebAssembly (wasm) is only available on the master channel.');
final WebCompilerConfig compilerConfig;
if (boolArg('wasm')) {
if (!featureFlags.isFlutterWebWasmEnabled) {
throwToolExit('Compiling to WebAssembly (wasm) is only available on the master channel.');
}
compilerConfig = const WasmCompilerConfig();
} else {
compilerConfig = JsCompilerConfig(
csp: boolArg('csp'),
optimizationLevel: stringArg('dart2js-optimization') ?? JsCompilerConfig.kDart2jsDefaultOptimizationLevel,
dumpInfo: boolArg('dump-info'),
nativeNullAssertions: boolArg('native-null-assertions'),
noFrequencyBasedMinification: boolArg('no-frequency-based-minification'),
sourceMaps: boolArg('source-maps'),
);
}
final FlutterProject flutterProject = FlutterProject.current();
......@@ -180,16 +192,10 @@ class BuildWebCommand extends BuildSubCommand {
flutterProject,
target,
buildInfo,
boolArg('csp'),
stringArg('pwa-strategy')!,
boolArg('source-maps'),
boolArg('native-null-assertions'),
wasmRequested,
compilerConfig: compilerConfig,
baseHref: baseHref,
dart2jsOptimization: stringArg('dart2js-optimization') ?? kDart2jsDefaultOptimizationLevel,
outputDirectoryPath: outputDirectoryPath,
dumpInfo: boolArg('dump-info'),
noFrequencyBasedMinification: boolArg('no-frequency-based-minification'),
);
return FlutterCommandResult.success();
}
......
......@@ -325,11 +325,8 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
flutterProject,
target,
debuggingOptions.buildInfo,
false,
kNoneWorker,
true,
debuggingOptions.nativeNullAssertions,
false,
compilerConfig: JsCompilerConfig.run(nativeNullAssertions: debuggingOptions.nativeNullAssertions)
);
}
await device!.device!.startApp(
......@@ -405,11 +402,8 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive).
flutterProject,
target,
debuggingOptions.buildInfo,
false,
kNoneWorker,
true,
debuggingOptions.nativeNullAssertions,
false,
compilerConfig: JsCompilerConfig.run(nativeNullAssertions: debuggingOptions.nativeNullAssertions),
);
} on ToolExit {
return OperationResult(1, 'Failed to recompile application.');
......
......@@ -18,9 +18,10 @@ import '../plugins.dart';
import '../project.dart';
import '../reporting/reporting.dart';
import '../version.dart';
import 'compiler_config.dart';
import 'migrations/scrub_generated_plugin_registrant.dart';
export '../build_system/targets/web.dart' show kDart2jsDefaultOptimizationLevel;
export 'compiler_config.dart';
class WebBuilder {
WebBuilder({
......@@ -45,18 +46,12 @@ class WebBuilder {
FlutterProject flutterProject,
String target,
BuildInfo buildInfo,
bool csp,
String serviceWorkerStrategy,
bool sourceMaps,
bool nativeNullAssertions,
bool isWasm, {
String dart2jsOptimization = kDart2jsDefaultOptimizationLevel,
String serviceWorkerStrategy, {
required WebCompilerConfig compilerConfig,
String? baseHref,
bool dumpInfo = false,
bool noFrequencyBasedMinification = false,
String? outputDirectoryPath,
}) async {
if (isWasm) {
if (compilerConfig.isWasm) {
globals.logger.printBox(
title: 'Experimental feature',
'''
......@@ -68,7 +63,7 @@ class WebBuilder {
final bool hasWebPlugins =
(await findPlugins(flutterProject)).any((Plugin p) => p.platforms.containsKey(WebPlugin.kConfigKey));
final Directory outputDirectory = outputDirectoryPath == null
? _fileSystem.directory(getWebBuildDirectory(isWasm))
? _fileSystem.directory(getWebBuildDirectory(compilerConfig.isWasm))
: _fileSystem.directory(outputDirectoryPath);
outputDirectory.createSync(recursive: true);
......@@ -84,7 +79,7 @@ class WebBuilder {
final Stopwatch sw = Stopwatch()..start();
try {
final BuildResult result = await _buildSystem.build(
WebServiceWorker(_fileSystem, buildInfo.webRenderer, isWasm: isWasm),
WebServiceWorker(_fileSystem, buildInfo.webRenderer, isWasm: compilerConfig.isWasm),
Environment(
projectDir: _fileSystem.currentDirectory,
outputDir: outputDirectory,
......@@ -92,14 +87,9 @@ class WebBuilder {
defines: <String, String>{
kTargetFile: target,
kHasWebPlugins: hasWebPlugins.toString(),
kCspMode: csp.toString(),
if (baseHref != null) kBaseHref: baseHref,
kSourceMapsEnabled: sourceMaps.toString(),
kNativeNullAssertions: nativeNullAssertions.toString(),
kServiceWorkerStrategy: serviceWorkerStrategy,
kDart2jsOptimization: dart2jsOptimization,
kDart2jsDumpInfo: dumpInfo.toString(),
kDart2jsNoFrequencyBasedMinification: noFrequencyBasedMinification.toString(),
...compilerConfig.toBuildSystemEnvironment(),
...buildInfo.toBuildSystemEnvironment(),
},
artifacts: globals.artifacts!,
......
// 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.
abstract class WebCompilerConfig {
const WebCompilerConfig();
/// Returns `true` if `this` represents configuration for the Wasm compiler.
///
/// Otherwise, `false`–represents the JavaScript compiler.
bool get isWasm;
Map<String, String> toBuildSystemEnvironment();
}
/// Configuration for the Dart-to-Javascript compiler (dart2js).
class JsCompilerConfig extends WebCompilerConfig {
const JsCompilerConfig({
required this.csp,
required this.dumpInfo,
required this.nativeNullAssertions,
required this.optimizationLevel,
required this.noFrequencyBasedMinification,
required this.sourceMaps,
});
/// Instantiates [JsCompilerConfig] suitable for the `flutter run` command.
const JsCompilerConfig.run({required bool nativeNullAssertions})
: this(
csp: false,
dumpInfo: false,
nativeNullAssertions: nativeNullAssertions,
noFrequencyBasedMinification: false,
optimizationLevel: kDart2jsDefaultOptimizationLevel,
sourceMaps: true,
);
/// Creates a new [JsCompilerConfig] from build system environment values.
///
/// Should correspond exactly with [toBuildSystemEnvironment].
factory JsCompilerConfig.fromBuildSystemEnvironment(
Map<String, String> defines) =>
JsCompilerConfig(
csp: defines[kCspMode] == 'true',
dumpInfo: defines[kDart2jsDumpInfo] == 'true',
nativeNullAssertions: defines[kNativeNullAssertions] == 'true',
optimizationLevel: defines[kDart2jsOptimization] ?? kDart2jsDefaultOptimizationLevel,
noFrequencyBasedMinification: defines[kDart2jsNoFrequencyBasedMinification] == 'true',
sourceMaps: defines[kSourceMapsEnabled] == 'true',
);
/// 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';
/// Build environment flag for [noFrequencyBasedMinification].
static const String kDart2jsNoFrequencyBasedMinification =
'Dart2jsNoFrequencyBasedMinification';
/// Build environment flag for [csp].
static const String kCspMode = 'cspMode';
/// Build environment flag for [sourceMaps].
static const String kSourceMapsEnabled = 'SourceMaps';
/// Build environment flag for [nativeNullAssertions].
static const String kNativeNullAssertions = 'NativeNullAssertions';
/// Whether to disable dynamic generation code to satisfy CSP policies.
final bool csp;
/// If `--dump-info` should be passed to the compiler.
final bool dumpInfo;
/// Whether native null assertions are enabled.
final bool nativeNullAssertions;
// If `--no-frequency-based-minification` should be passed to dart2js
// 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;
@override
bool get isWasm => false;
@override
Map<String, String> toBuildSystemEnvironment() => <String, String>{
kCspMode: csp.toString(),
kDart2jsDumpInfo: dumpInfo.toString(),
kNativeNullAssertions: nativeNullAssertions.toString(),
kDart2jsNoFrequencyBasedMinification: noFrequencyBasedMinification.toString(),
kDart2jsOptimization: optimizationLevel,
kSourceMapsEnabled: sourceMaps.toString(),
};
/// Arguments to use in both phases: full JS compile and CFE-only.
List<String> toSharedCommandOptions() => <String>[
if (nativeNullAssertions) '--native-null-assertions',
if (!sourceMaps) '--no-source-maps',
];
/// Arguments to use in the full JS compile, but not CFE-only.
///
/// Includes the contents of [toSharedCommandOptions].
List<String> toCommandOptions() => <String>[
...toSharedCommandOptions(),
'-$optimizationLevel',
if (dumpInfo) '--dump-info',
if (noFrequencyBasedMinification) '--no-frequency-based-minification',
if (csp) '--csp',
];
}
/// Configuration for the Wasm compiler.
class WasmCompilerConfig extends WebCompilerConfig {
const WasmCompilerConfig();
@override
bool get isWasm => true;
@override
Map<String, String> toBuildSystemEnvironment() => const <String, String>{};
}
......@@ -330,7 +330,7 @@ void main() {
test('Dart2JSTarget calls dart2js with expected args with csp', () => testbed.run(() async {
environment.defines[kBuildMode] = 'profile';
environment.defines[kCspMode] = 'true';
environment.defines[JsCompilerConfig.kCspMode] = 'true';
processManager.addCommand(FakeCommand(
command: <String>[
...kDart2jsLinuxArgs,
......@@ -479,14 +479,14 @@ void main() {
test('Dart2JSTarget calls dart2js with expected args in release mode with native null assertions', () => testbed.run(() async {
environment.defines[kBuildMode] = 'release';
environment.defines[kNativeNullAssertions] = 'true';
environment.defines[JsCompilerConfig.kNativeNullAssertions] = 'true';
processManager.addCommand(FakeCommand(
command: <String>[
...kDart2jsLinuxArgs,
'--platform-binaries=bin/cache/flutter_web_sdk/kernel',
'--invoker=flutter_tool',
'--native-null-assertions',
'-Ddart.vm.product=true',
'--native-null-assertions',
'--no-source-maps',
'-o',
environment.buildDir.childFile('app.dill').absolute.path,
......@@ -500,8 +500,8 @@ void main() {
...kDart2jsLinuxArgs,
'--platform-binaries=bin/cache/flutter_web_sdk/kernel',
'--invoker=flutter_tool',
'--native-null-assertions',
'-Ddart.vm.product=true',
'--native-null-assertions',
'--no-source-maps',
'-O4',
'-o',
......@@ -517,7 +517,7 @@ void main() {
test('Dart2JSTarget calls dart2js with expected args in release with dart2js optimization override', () => testbed.run(() async {
environment.defines[kBuildMode] = 'release';
environment.defines[kDart2jsOptimization] = 'O3';
environment.defines[JsCompilerConfig.kDart2jsOptimization] = 'O3';
processManager.addCommand(FakeCommand(
command: <String>[
...kDart2jsLinuxArgs,
......@@ -624,7 +624,7 @@ void main() {
test('Dart2JSTarget can enable source maps', () => testbed.run(() async {
environment.defines[kBuildMode] = 'release';
environment.defines[kSourceMapsEnabled] = 'true';
environment.defines[JsCompilerConfig.kSourceMapsEnabled] = 'true';
processManager.addCommand(FakeCommand(
command: <String>[
...kDart2jsLinuxArgs,
......@@ -700,7 +700,7 @@ void main() {
test('Dart2JSTarget calls dart2js with expected args with dump-info', () => testbed.run(() async {
environment.defines[kBuildMode] = 'profile';
environment.defines[kDart2jsDumpInfo] = 'true';
environment.defines[JsCompilerConfig.kDart2jsDumpInfo] = 'true';
processManager.addCommand(FakeCommand(
command: <String>[
...kDart2jsLinuxArgs,
......@@ -738,7 +738,7 @@ void main() {
test('Dart2JSTarget calls dart2js with expected args with no-frequency-based-minification', () => testbed.run(() async {
environment.defines[kBuildMode] = 'profile';
environment.defines[kDart2jsNoFrequencyBasedMinification] = 'true';
environment.defines[JsCompilerConfig.kDart2jsNoFrequencyBasedMinification] = 'true';
processManager.addCommand(FakeCommand(
command: <String>[
...kDart2jsLinuxArgs,
......
......@@ -38,19 +38,13 @@ void main() {
final TestBuildSystem buildSystem =
TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
final WebServiceWorker webServiceWorker = target as WebServiceWorker;
expect(webServiceWorker.isWasm, isTrue);
expect(webServiceWorker.isWasm, isTrue, reason: 'should be wasm');
expect(webServiceWorker.webRenderer, WebRendererMode.autoDetect);
expect(environment.defines, <String, String>{
'TargetFile': 'target',
'HasWebPlugins': 'false',
'cspMode': 'true',
'SourceMaps': 'true',
'NativeNullAssertions': 'true',
'ServiceWorkerStrategy': 'serviceWorkerStrategy',
'Dart2jsOptimization': 'O4',
'Dart2jsDumpInfo': 'false',
'Dart2jsNoFrequencyBasedMinification': 'false',
'BuildMode': 'debug',
'DartObfuscation': 'false',
'TrackWidgetCreation': 'true',
......@@ -72,11 +66,8 @@ void main() {
flutterProject,
'target',
BuildInfo.debug,
true,
'serviceWorkerStrategy',
true,
true,
true,
compilerConfig: const WasmCompilerConfig(),
);
expect(logger.statusText, contains('Compiling target for the Web...'));
......@@ -114,11 +105,8 @@ void main() {
flutterProject,
'target',
BuildInfo.debug,
true,
'serviceWorkerStrategy',
true,
true,
true,
compilerConfig: const JsCompilerConfig.run(nativeNullAssertions: true),
),
throwsToolExit(message: 'Failed to compile application for the Web.'));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment