| // 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. | |
| import '../build_info.dart' show BuildMode; | |
| import '../convert.dart'; | |
| import 'compile.dart'; | |
| enum CompileTarget { js, wasm } | |
| sealed class WebCompilerConfig { | |
| const WebCompilerConfig({ | |
| required this.renderer, | |
| this.optimizationLevel, | |
| required this.sourceMaps, | |
| }); | |
| /// Build environment flag for [optimizationLevel]. | |
| static const kOptimizationLevel = 'OptimizationLevel'; | |
| /// Build environment flag for [sourceMaps]. | |
| static const kSourceMapsEnabled = 'SourceMaps'; | |
| /// Calculates the optimization level for the compiler for the given | |
| /// build mode. | |
| int optimizationLevelForBuildMode(BuildMode mode); | |
| /// The compiler optimization level specified by the user. | |
| /// | |
| /// Valid values are O0 (lowest, debug default) to O4 (highest, release default). | |
| /// If the value is null, the user hasn't specified an optimization level and an | |
| /// appropriate default for the build mode will be used instead. | |
| final int? optimizationLevel; | |
| /// `true` if the compiler build should output source maps. | |
| final bool sourceMaps; | |
| /// Returns which target this compiler outputs (js or wasm) | |
| CompileTarget get compileTarget; | |
| final WebRendererMode renderer; | |
| List<String> toCommandOptions(BuildMode buildMode); | |
| String get buildKey; | |
| Map<String, Object> get buildEventAnalyticsValues => <String, Object>{ | |
| 'optimizationLevel': ?optimizationLevel, | |
| }; | |
| Map<String, dynamic> get _buildKeyMap => <String, dynamic>{ | |
| 'optimizationLevel': optimizationLevel, | |
| 'webRenderer': renderer.name, | |
| }; | |
| } | |
| /// Configuration for the Dart-to-Javascript compiler (dart2js). | |
| class JsCompilerConfig extends WebCompilerConfig { | |
| const JsCompilerConfig({ | |
| this.csp = false, | |
| this.dumpInfo = false, | |
| this.nativeNullAssertions = false, | |
| super.optimizationLevel, | |
| this.useFrequencyBasedMinification = true, | |
| super.sourceMaps = true, | |
| this.minify, | |
| super.renderer = WebRendererMode.defaultForJs, | |
| }); | |
| /// Instantiates [JsCompilerConfig] suitable for the `flutter run` command. | |
| const JsCompilerConfig.run({ | |
| required bool nativeNullAssertions, | |
| required WebRendererMode renderer, | |
| }) : this(nativeNullAssertions: nativeNullAssertions, renderer: renderer); | |
| /// 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; | |
| /// If minification should be used in the JS compiler. | |
| /// | |
| /// If `null`, minifies in release mode only. | |
| final bool? minify; | |
| /// Whether native null assertions are enabled. | |
| final bool nativeNullAssertions; | |
| /// Whether to use frequency-based minification in dart2js. | |
| /// | |
| /// When `false`, passes `--no-frequency-based-minification` to the compiler. | |
| final bool useFrequencyBasedMinification; | |
| @override | |
| CompileTarget get compileTarget => CompileTarget.js; | |
| /// Arguments to use in both phases: full JS compile and CFE-only. | |
| /// | |
| /// NOTE: MOST args should be passed here! | |
| List<String> toSharedCommandOptions(BuildMode buildMode) => <String>[ | |
| if (nativeNullAssertions) '--native-null-assertions', | |
| if (!sourceMaps) '--no-source-maps', | |
| if (buildMode == BuildMode.debug) '--enable-asserts', | |
| '-O${optimizationLevelForBuildMode(buildMode)}', | |
| if (minify ?? buildMode == BuildMode.release) '--minify' else '--no-minify', | |
| if (!useFrequencyBasedMinification) '--no-frequency-based-minification', | |
| if (csp) '--csp', | |
| ]; | |
| @override | |
| int optimizationLevelForBuildMode(BuildMode mode) => | |
| optimizationLevel ?? | |
| switch (mode) { | |
| // dart2js optimization level 0 is not well supported. Use | |
| // 1 instead. | |
| BuildMode.debug => 1, | |
| BuildMode.profile || BuildMode.release => 4, | |
| BuildMode.jitRelease => throw ArgumentError('Invalid build mode for web'), | |
| }; | |
| /// Arguments to use in the full JS compile, but not CFE-only. | |
| /// | |
| /// Includes the contents of [toSharedCommandOptions]. That is where MOST | |
| /// JS compiler flags should be passed! | |
| @override | |
| List<String> toCommandOptions(BuildMode buildMode) => <String>[ | |
| ...toSharedCommandOptions(buildMode), | |
| if (dumpInfo) '--stage=dump-info-all', | |
| ]; | |
| @override | |
| String get buildKey { | |
| final settings = <String, dynamic>{ | |
| ...super._buildKeyMap, | |
| 'csp': csp, | |
| 'dumpInfo': dumpInfo, | |
| 'nativeNullAssertions': nativeNullAssertions, | |
| 'useFrequencyBasedMinification': useFrequencyBasedMinification, | |
| 'minify': minify, | |
| WebCompilerConfig.kSourceMapsEnabled: sourceMaps, | |
| }; | |
| return jsonEncode(settings); | |
| } | |
| } | |
| /// Configuration for the Wasm compiler. | |
| class WasmCompilerConfig extends WebCompilerConfig { | |
| const WasmCompilerConfig({ | |
| super.optimizationLevel, | |
| this.stripWasm = true, | |
| this.minify, | |
| this.dryRun = false, | |
| super.sourceMaps = true, | |
| super.renderer = WebRendererMode.defaultForWasm, | |
| }); | |
| /// Build environment for [stripWasm]. | |
| static const kStripWasm = 'StripWasm'; | |
| /// Whether to strip the wasm file of static symbols. | |
| final bool stripWasm; | |
| final bool? minify; | |
| final bool dryRun; | |
| @override | |
| CompileTarget get compileTarget => CompileTarget.wasm; | |
| @override | |
| int optimizationLevelForBuildMode(BuildMode mode) => | |
| optimizationLevel ?? | |
| switch (mode) { | |
| BuildMode.debug => 0, | |
| // The optimization level of O2 uses only sound optimizations. We default | |
| // to this level because our web benchmarks have shown that the difference | |
| // between O2 and O4 is marginal enough that we would prefer soundness here. | |
| BuildMode.profile || BuildMode.release => 2, | |
| BuildMode.jitRelease => throw ArgumentError('Invalid build mode for web'), | |
| }; | |
| @override | |
| List<String> toCommandOptions(BuildMode buildMode) { | |
| final bool stripSymbols = buildMode == BuildMode.release && stripWasm; | |
| return <String>[ | |
| '-O${optimizationLevelForBuildMode(buildMode)}', | |
| '--${stripSymbols ? '' : 'no-'}strip-wasm', | |
| if (!sourceMaps) '--no-source-maps', | |
| if (minify ?? buildMode == BuildMode.release) '--minify' else '--no-minify', | |
| if (buildMode == BuildMode.debug) '--extra-compiler-option=--enable-asserts', | |
| if (dryRun) '--extra-compiler-option=--dry-run', | |
| ]; | |
| } | |
| @override | |
| String get buildKey { | |
| final settings = <String, dynamic>{ | |
| ...super._buildKeyMap, | |
| kStripWasm: stripWasm, | |
| 'minify': minify, | |
| 'dryRun': dryRun, | |
| WebCompilerConfig.kSourceMapsEnabled: sourceMaps, | |
| }; | |
| return jsonEncode(settings); | |
| } | |
| @override | |
| Map<String, Object> get buildEventAnalyticsValues => <String, Object>{ | |
| ...super.buildEventAnalyticsValues, | |
| 'dryRun': dryRun, | |
| }; | |
| } |