diff --git a/packages/flutter_tools/lib/src/commands/build_web.dart b/packages/flutter_tools/lib/src/commands/build_web.dart index 003503dfa0e..d6788bff5f2 100644 --- a/packages/flutter_tools/lib/src/commands/build_web.dart +++ b/packages/flutter_tools/lib/src/commands/build_web.dart @@ -99,9 +99,16 @@ class BuildWebCommand extends BuildSubCommand { hide: !verboseHelp, ); argParser.addFlag( - 'minify', + 'minify-js', help: - 'Generate minified output. ' + 'Generate minified output for js. ' + 'If not explicitly set, uses the compilation mode (debug, profile, release).', + hide: !verboseHelp, + ); + argParser.addFlag( + 'minify-wasm', + help: + 'Generate minified output for wasm. ' 'If not explicitly set, uses the compilation mode (debug, profile, release).', hide: !verboseHelp, ); @@ -175,7 +182,8 @@ class BuildWebCommand extends BuildSubCommand { ); final bool sourceMaps = boolArg('source-maps'); - final bool? minify = argResults!.wasParsed('minify') ? boolArg('minify') : null; + final bool? minifyJs = argResults!.wasParsed('minify-js') ? boolArg('minify-js') : null; + final bool? minifyWasm = argResults!.wasParsed('minify-wasm') ? boolArg('minify-wasm') : null; final List compilerConfigs; @@ -194,11 +202,12 @@ class BuildWebCommand extends BuildSubCommand { optimizationLevel: optimizationLevel, stripWasm: boolArg('strip-wasm'), sourceMaps: sourceMaps, + minify: minifyWasm, ), JsCompilerConfig( csp: boolArg('csp'), dumpInfo: boolArg('dump-info'), - minify: minify, + minify: minifyJs, nativeNullAssertions: boolArg('native-null-assertions'), noFrequencyBasedMinification: boolArg('no-frequency-based-minification'), optimizationLevel: jsOptimizationLevel, @@ -210,7 +219,7 @@ class BuildWebCommand extends BuildSubCommand { JsCompilerConfig( csp: boolArg('csp'), dumpInfo: boolArg('dump-info'), - minify: minify, + minify: minifyJs, nativeNullAssertions: boolArg('native-null-assertions'), noFrequencyBasedMinification: boolArg('no-frequency-based-minification'), optimizationLevel: jsOptimizationLevel, diff --git a/packages/flutter_tools/lib/src/web/compiler_config.dart b/packages/flutter_tools/lib/src/web/compiler_config.dart index aeb19c7de30..f2be41e88dd 100644 --- a/packages/flutter_tools/lib/src/web/compiler_config.dart +++ b/packages/flutter_tools/lib/src/web/compiler_config.dart @@ -146,6 +146,7 @@ class WasmCompilerConfig extends WebCompilerConfig { const WasmCompilerConfig({ super.optimizationLevel, this.stripWasm = true, + this.minify = true, super.sourceMaps = true, super.renderer = WebRendererMode.defaultForWasm, }); @@ -156,6 +157,8 @@ class WasmCompilerConfig extends WebCompilerConfig { /// Whether to strip the wasm file of static symbols. final bool stripWasm; + final bool? minify; + @override CompileTarget get compileTarget => CompileTarget.wasm; @@ -179,6 +182,7 @@ class WasmCompilerConfig extends WebCompilerConfig { '-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', ]; } @@ -188,6 +192,7 @@ class WasmCompilerConfig extends WebCompilerConfig { final Map settings = { ...super._buildKeyMap, kStripWasm: stripWasm, + 'minify': minify, WebCompilerConfig.kSourceMapsEnabled: sourceMaps, }; return jsonEncode(settings); 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 e67b699fbf1..66d048c98d3 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 @@ -435,7 +435,7 @@ void main() { ); testUsingContext( - 'Defaults to web renderer skwasm mode for wasm when no option is specified', + 'Defaults to web renderer skwasm mode and minify for wasm when no option is specified', () async { final TestWebBuildCommand buildCommand = TestWebBuildCommand(fileSystem: fileSystem); final CommandRunner runner = createTestCommandRunner(buildCommand); @@ -459,6 +459,123 @@ void main() { expect(configs[0].compileTarget, CompileTarget.wasm); expect(configs[1].renderer, WebRendererMode.canvaskit); expect(configs[1].compileTarget, CompileTarget.js); + + expect(configs[0].toCommandOptions(BuildMode.release), contains('--minify')); + expect(configs[0].toCommandOptions(BuildMode.debug), contains('--no-minify')); + expect(configs[1].toCommandOptions(BuildMode.release), contains('--minify')); + expect(configs[1].toCommandOptions(BuildMode.debug), contains('--no-minify')); + }), + }, + ); + + testUsingContext( + 'Passes minify to only wasm when minify-wasm specified', + () async { + final TestWebBuildCommand buildCommand = TestWebBuildCommand(fileSystem: fileSystem); + final CommandRunner runner = createTestCommandRunner(buildCommand); + setupFileSystemForEndToEndTest(fileSystem); + await runner.run(['build', 'web', '--no-pub', '--wasm', '--minify-wasm']); + }, + overrides: { + Platform: () => fakePlatform, + FileSystem: () => fileSystem, + FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), + ProcessManager: () => processManager, + BuildSystem: + () => TestBuildSystem.all(BuildResult(success: true), ( + Target target, + Environment environment, + ) { + final List configs = (target as WebServiceWorker).compileConfigs; + + expect(configs[0].toCommandOptions(BuildMode.release), contains('--minify')); + expect(configs[0].toCommandOptions(BuildMode.debug), contains('--minify')); + expect(configs[1].toCommandOptions(BuildMode.release), contains('--minify')); + expect(configs[1].toCommandOptions(BuildMode.debug), contains('--no-minify')); + }), + }, + ); + + testUsingContext( + 'Passes no-minify to wasm when no-minify-wasm specified', + () async { + final TestWebBuildCommand buildCommand = TestWebBuildCommand(fileSystem: fileSystem); + final CommandRunner runner = createTestCommandRunner(buildCommand); + setupFileSystemForEndToEndTest(fileSystem); + await runner.run(['build', 'web', '--no-pub', '--wasm', '--no-minify-wasm']); + }, + overrides: { + Platform: () => fakePlatform, + FileSystem: () => fileSystem, + FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), + ProcessManager: () => processManager, + BuildSystem: + () => TestBuildSystem.all(BuildResult(success: true), ( + Target target, + Environment environment, + ) { + final List configs = (target as WebServiceWorker).compileConfigs; + + expect(configs[0].toCommandOptions(BuildMode.release), contains('--no-minify')); + expect(configs[0].toCommandOptions(BuildMode.debug), contains('--no-minify')); + expect(configs[1].toCommandOptions(BuildMode.release), contains('--minify')); + expect(configs[1].toCommandOptions(BuildMode.debug), contains('--no-minify')); + }), + }, + ); + + testUsingContext( + 'Passes minify to js when minify-js specified', + () async { + final TestWebBuildCommand buildCommand = TestWebBuildCommand(fileSystem: fileSystem); + final CommandRunner runner = createTestCommandRunner(buildCommand); + setupFileSystemForEndToEndTest(fileSystem); + await runner.run(['build', 'web', '--no-pub', '--wasm', '--minify-js']); + }, + overrides: { + Platform: () => fakePlatform, + FileSystem: () => fileSystem, + FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), + ProcessManager: () => processManager, + BuildSystem: + () => TestBuildSystem.all(BuildResult(success: true), ( + Target target, + Environment environment, + ) { + final List configs = (target as WebServiceWorker).compileConfigs; + + expect(configs[0].toCommandOptions(BuildMode.release), contains('--minify')); + expect(configs[0].toCommandOptions(BuildMode.debug), contains('--no-minify')); + expect(configs[1].toCommandOptions(BuildMode.release), contains('--minify')); + expect(configs[1].toCommandOptions(BuildMode.debug), contains('--minify')); + }), + }, + ); + + testUsingContext( + 'Passes no-minify to js when no-minify-js specified', + () async { + final TestWebBuildCommand buildCommand = TestWebBuildCommand(fileSystem: fileSystem); + final CommandRunner runner = createTestCommandRunner(buildCommand); + setupFileSystemForEndToEndTest(fileSystem); + await runner.run(['build', 'web', '--no-pub', '--wasm', '--no-minify-js']); + }, + overrides: { + Platform: () => fakePlatform, + FileSystem: () => fileSystem, + FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), + ProcessManager: () => processManager, + BuildSystem: + () => TestBuildSystem.all(BuildResult(success: true), ( + Target target, + Environment environment, + ) { + final List configs = (target as WebServiceWorker).compileConfigs; + + expect(configs[0].toCommandOptions(BuildMode.release), contains('--minify')); + expect(configs[0].toCommandOptions(BuildMode.debug), contains('--no-minify')); + expect(configs[1].toCommandOptions(BuildMode.release), contains('--no-minify')); + expect(configs[1].toCommandOptions(BuildMode.debug), contains('--no-minify')); }), }, ); 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 8033697e59d..13842a7bd93 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 @@ -1138,75 +1138,82 @@ name: foo ]) { for (final String buildMode in const ['profile', 'release', 'debug']) { for (final bool sourceMaps in const [true, false]) { - test( - 'Dart2WasmTarget invokes dart2wasm with renderer=$renderer, -O$level, stripping=$strip, defines=$defines, modeMode=$buildMode sourceMaps=$sourceMaps', - () => testbed.run(() async { - final int expectedLevel = - level ?? - switch (buildMode) { - 'debug' => 0, - 'profile' || 'release' => 2, - _ => throw UnimplementedError(), - }; - environment.defines[kBuildMode] = buildMode; - environment.defines[kDartDefines] = encodeDartDefines(defines); + for (final bool minify in const [true, false]) { + test( + 'Dart2WasmTarget invokes dart2wasm with renderer=$renderer, -O$level, stripping=$strip, defines=$defines, modeMode=$buildMode sourceMaps=$sourceMaps minify=$minify', + () => testbed.run(() async { + final int expectedLevel = + level ?? + switch (buildMode) { + 'debug' => 0, + 'profile' || 'release' => 2, + _ => throw UnimplementedError(), + }; + environment.defines[kBuildMode] = buildMode; + environment.defines[kDartDefines] = encodeDartDefines(defines); - final File depFile = environment.buildDir.childFile('dart2wasm.d'); + final File depFile = environment.buildDir.childFile('dart2wasm.d'); - final File outputJsFile = environment.buildDir.childFile('main.dart.mjs'); - processManager.addCommand( - FakeCommand( - command: [ - ..._kDart2WasmLinuxArgs, - '-Ddart.vm.profile=${buildMode == 'profile'}', - '-Ddart.vm.product=${buildMode == 'release'}', - if (buildMode != 'debug') ...[ - '--extra-compiler-option=--delete-tostring-package-uri=dart:ui', - '--extra-compiler-option=--delete-tostring-package-uri=package:flutter', + final File outputJsFile = environment.buildDir.childFile('main.dart.mjs'); + processManager.addCommand( + FakeCommand( + command: [ + ..._kDart2WasmLinuxArgs, + '-Ddart.vm.profile=${buildMode == 'profile'}', + '-Ddart.vm.product=${buildMode == 'release'}', + if (buildMode != 'debug') ...[ + '--extra-compiler-option=--delete-tostring-package-uri=dart:ui', + '--extra-compiler-option=--delete-tostring-package-uri=package:flutter', + ], + if (renderer == WebRendererMode.skwasm) ...[ + '--extra-compiler-option=--import-shared-memory', + '--extra-compiler-option=--shared-memory-max-pages=32768', + ], + ...defines.map((String define) => '-D$define'), + if (renderer == WebRendererMode.skwasm) ...[ + '-DFLUTTER_WEB_USE_SKIA=false', + '-DFLUTTER_WEB_USE_SKWASM=true', + ], + if (renderer == WebRendererMode.canvaskit) ...[ + '-DFLUTTER_WEB_USE_SKIA=true', + '-DFLUTTER_WEB_USE_SKWASM=false', + ], + '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', + '--extra-compiler-option=--depfile=${depFile.absolute.path}', + '-O$expectedLevel', + if (strip && buildMode == 'release') + '--strip-wasm' + else + '--no-strip-wasm', + if (!sourceMaps) '--no-source-maps', + if (minify) '--minify' else '--no-minify', + if (buildMode == 'debug') '--extra-compiler-option=--enable-asserts', + '-o', + environment.buildDir.childFile('main.dart.wasm').absolute.path, + environment.buildDir.childFile('main.dart').absolute.path, ], - if (renderer == WebRendererMode.skwasm) ...[ - '--extra-compiler-option=--import-shared-memory', - '--extra-compiler-option=--shared-memory-max-pages=32768', - ], - ...defines.map((String define) => '-D$define'), - if (renderer == WebRendererMode.skwasm) ...[ - '-DFLUTTER_WEB_USE_SKIA=false', - '-DFLUTTER_WEB_USE_SKWASM=true', - ], - if (renderer == WebRendererMode.canvaskit) ...[ - '-DFLUTTER_WEB_USE_SKIA=true', - '-DFLUTTER_WEB_USE_SKWASM=false', - ], - '-DFLUTTER_WEB_CANVASKIT_URL=https://www.gstatic.com/flutter-canvaskit/abcdefghijklmnopqrstuvwxyz/', - '--extra-compiler-option=--depfile=${depFile.absolute.path}', - '-O$expectedLevel', - if (strip && buildMode == 'release') '--strip-wasm' else '--no-strip-wasm', - if (!sourceMaps) '--no-source-maps', - if (buildMode == 'debug') '--extra-compiler-option=--enable-asserts', - '-o', - environment.buildDir.childFile('main.dart.wasm').absolute.path, - environment.buildDir.childFile('main.dart').absolute.path, - ], - onRun: - (_) => - outputJsFile - ..createSync() - ..writeAsStringSync('foo'), - ), - ); + onRun: + (_) => + outputJsFile + ..createSync() + ..writeAsStringSync('foo'), + ), + ); - await Dart2WasmTarget( - WasmCompilerConfig( - optimizationLevel: level, - stripWasm: strip, - renderer: renderer, - sourceMaps: sourceMaps, - ), - ).build(environment); + await Dart2WasmTarget( + WasmCompilerConfig( + optimizationLevel: level, + stripWasm: strip, + renderer: renderer, + sourceMaps: sourceMaps, + minify: minify, + ), + ).build(environment); - expect(outputJsFile.existsSync(), isTrue); - }, overrides: {ProcessManager: () => processManager}), - ); + expect(outputJsFile.existsSync(), isTrue); + }, overrides: {ProcessManager: () => processManager}), + ); + } } } } @@ -1257,6 +1264,7 @@ name: foo WasmCompilerConfig(optimizationLevel: 0), WasmCompilerConfig(renderer: WebRendererMode.canvaskit), WasmCompilerConfig(stripWasm: false), + WasmCompilerConfig(minify: false), // All properties non-default WasmCompilerConfig(