diff --git a/packages/flutter_tools/lib/src/commands/build_web.dart b/packages/flutter_tools/lib/src/commands/build_web.dart index 5aa0266327..f0c2e4e2cc 100644 --- a/packages/flutter_tools/lib/src/commands/build_web.dart +++ b/packages/flutter_tools/lib/src/commands/build_web.dart @@ -28,7 +28,7 @@ class BuildWebCommand extends BuildSubCommand { usesPubOption(); usesBuildNumberOption(); usesBuildNameOption(); - addBuildModeFlags(verboseHelp: verboseHelp, excludeDebug: true); + addBuildModeFlags(verboseHelp: verboseHelp); usesDartDefineOption(); addEnableExperimentation(hide: !verboseHelp); addNullSafetyModeOptions(hide: !verboseHelp); @@ -62,7 +62,6 @@ class BuildWebCommand extends BuildSubCommand { abbr: 'O', help: 'Sets the optimization level used for Dart compilation to JavaScript/Wasm.', - defaultsTo: '${WebCompilerConfig.kDefaultOptimizationLevel}', allowed: const ['0', '1', '2', '3', '4'], ); argParser.addFlag( @@ -134,10 +133,11 @@ 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? optimizationLevelArg = stringArg('optimization-level'); + final int? optimizationLevel = optimizationLevelArg != null ? int.parse(optimizationLevelArg) : null; final String? dart2jsOptimizationLevelValue = stringArg('dart2js-optimization'); - final int jsOptimizationLevel = dart2jsOptimizationLevelValue != null + final int? jsOptimizationLevel = dart2jsOptimizationLevelValue != null ? int.parse(dart2jsOptimizationLevelValue.substring(1)) : optimizationLevel; @@ -191,9 +191,6 @@ class BuildWebCommand extends BuildSubCommand { final String target = stringArg('target')!; final BuildInfo buildInfo = await getBuildInfo(); - if (buildInfo.isDebug) { - throwToolExit('debug builds cannot be built directly for the web. Try using "flutter run"'); - } final String? baseHref = stringArg('base-href'); if (baseHref != null && !(baseHref.startsWith('/') && baseHref.endsWith('/'))) { throwToolExit( diff --git a/packages/flutter_tools/lib/src/web/compiler_config.dart b/packages/flutter_tools/lib/src/web/compiler_config.dart index aa346df4fb..939b9b96ed 100644 --- a/packages/flutter_tools/lib/src/web/compiler_config.dart +++ b/packages/flutter_tools/lib/src/web/compiler_config.dart @@ -13,22 +13,29 @@ enum CompileTarget { sealed class WebCompilerConfig { const WebCompilerConfig({required this.renderer, - required this.optimizationLevel, + this.optimizationLevel, required this.sourceMaps}); - - /// The default optimization level for dart2js/dart2wasm. - static const int kDefaultOptimizationLevel = 4; - /// Build environment flag for [optimizationLevel]. static const String kOptimizationLevel = 'OptimizationLevel'; /// Build environment flag for [sourceMaps]. static const String kSourceMapsEnabled = 'SourceMaps'; - /// The compiler optimization level. + /// Calculates the optimization level for dart2js/dart2wasm for the given + /// build mode. + int optimizationLevelForBuildMode(BuildMode mode) => + optimizationLevel ?? switch (mode) { + BuildMode.debug => 0, + BuildMode.profile || BuildMode.release => 4, + BuildMode.jitRelease => throw ArgumentError('Invalid build mode for web'), + }; + + /// The compiler optimization level specified by the user. /// /// Valid values are O0 (lowest, debug default) to O4 (highest, release default). - final int optimizationLevel; + /// 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; @@ -40,7 +47,7 @@ sealed class WebCompilerConfig { String get buildKey; Map get buildEventAnalyticsValues => { - 'optimizationLevel': optimizationLevel, + if (optimizationLevel != null) 'optimizationLevel': optimizationLevel!, }; @@ -56,7 +63,7 @@ class JsCompilerConfig extends WebCompilerConfig { this.csp = false, this.dumpInfo = false, this.nativeNullAssertions = false, - super.optimizationLevel = WebCompilerConfig.kDefaultOptimizationLevel, + super.optimizationLevel, this.noFrequencyBasedMinification = false, super.sourceMaps = true, super.renderer = WebRendererMode.defaultForJs, @@ -68,7 +75,6 @@ class JsCompilerConfig extends WebCompilerConfig { required WebRendererMode renderer, }) : this( nativeNullAssertions: nativeNullAssertions, - optimizationLevel: WebCompilerConfig.kDefaultOptimizationLevel , renderer: renderer, ); @@ -108,13 +114,22 @@ class JsCompilerConfig extends WebCompilerConfig { if (buildMode == BuildMode.debug) '--enable-asserts', ]; + @override + int optimizationLevelForBuildMode(BuildMode mode) { + final int level = super.optimizationLevelForBuildMode(mode); + + // dart2js optimization level 0 is not well supported. Use + // 1 instead. + return level == 0 ? 1 : level; + } + /// Arguments to use in the full JS compile, but not CFE-only. /// /// Includes the contents of [toSharedCommandOptions]. List toCommandOptions(BuildMode buildMode) => [ if (buildMode != BuildMode.release) '--no-minify', ...toSharedCommandOptions(buildMode), - '-O$optimizationLevel', + '-O${optimizationLevelForBuildMode(buildMode)}', if (dumpInfo) '--stage=dump-info-all', if (noFrequencyBasedMinification) '--no-frequency-based-minification', if (csp) '--csp', @@ -137,7 +152,7 @@ class JsCompilerConfig extends WebCompilerConfig { /// Configuration for the Wasm compiler. class WasmCompilerConfig extends WebCompilerConfig { const WasmCompilerConfig({ - super.optimizationLevel = WebCompilerConfig.kDefaultOptimizationLevel, + super.optimizationLevel, this.stripWasm = true, super.sourceMaps = true, super.renderer = WebRendererMode.defaultForWasm, @@ -155,7 +170,7 @@ class WasmCompilerConfig extends WebCompilerConfig { List toCommandOptions(BuildMode buildMode) { final bool stripSymbols = buildMode == BuildMode.release && stripWasm; return [ - '-O$optimizationLevel', + '-O${optimizationLevelForBuildMode(buildMode)}', '--${stripSymbols ? '' : 'no-'}strip-wasm', if (!sourceMaps) '--no-source-maps', if (buildMode == BuildMode.debug) '--extra-compiler-option=--enable-asserts', diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart index 4d6e1f30e1..c7aa4d5a60 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart @@ -83,25 +83,6 @@ void main() { ProcessManager: () => processManager, }); - testUsingContext('Refuses to build a debug build for web', () async { - final CommandRunner runner = createTestCommandRunner(BuildCommand( - artifacts: artifacts, - androidSdk: FakeAndroidSdk(), - buildSystem: TestBuildSystem.all(BuildResult(success: true)), - fileSystem: fileSystem, - logger: logger, - processUtils: processUtils, - osUtils: FakeOperatingSystemUtils(), - )); - - expect(() => runner.run(['build', 'web', '--debug', '--no-pub']), - throwsA(isA())); - }, overrides: { - Platform: () => fakePlatform, - FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), - ProcessManager: () => processManager, - }); - testUsingContext('Refuses to build for web when feature is disabled', () async { final CommandRunner runner = createTestCommandRunner(BuildCommand( artifacts: artifacts, diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart index 56ff685c75..9c4d3125ff 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart @@ -909,7 +909,7 @@ void main() { '--no-minify', '--no-source-maps', '--enable-asserts', - '-O4', + '-O1', '-o', environment.buildDir.childFile('main.dart.js').absolute.path, environment.buildDir.childFile('app.dill').absolute.path, diff --git a/packages/flutter_tools/test/general.shard/web/compile_web_test.dart b/packages/flutter_tools/test/general.shard/web/compile_web_test.dart index 57015d5bf4..f854726472 100644 --- a/packages/flutter_tools/test/general.shard/web/compile_web_test.dart +++ b/packages/flutter_tools/test/general.shard/web/compile_web_test.dart @@ -107,7 +107,7 @@ void main() { label: 'web-compile', parameters: CustomDimensions( buildEventSettings: - 'optimizationLevel: 4; web-renderer: skwasm,canvaskit; web-target: wasm,js;', + 'optimizationLevel: 0; web-renderer: skwasm,canvaskit; web-target: wasm,js;', ), ), @@ -121,7 +121,7 @@ void main() { Event.flutterBuildInfo( label: 'web-compile', buildType: 'web', - settings: 'optimizationLevel: 4; web-renderer: skwasm,canvaskit; web-target: wasm,js;', + settings: 'optimizationLevel: 0; web-renderer: skwasm,canvaskit; web-target: wasm,js;', ), ]), );