![auto-submit[bot]](/assets/img/avatar_default.png)
Reverts: flutter/flutter#145376 Initiated by: loic-sharma Reason for reverting: It caused the following post-submit failures: 1. https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8752928710548811665/+/u/run_run_release_test_windows/stdout 2. https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8752927564747697169/+/u/run_run_release_test_windows/stdout Original PR Author: guidezpl Reviewed By: {loic-sharma} This change reverts the following previous change: Reland #128236, reverted in https://github.com/flutter/flutter/pull/143125 and https://github.com/flutter/flutter/pull/145261. This PR contains 3 additional commits, fixing post-submit tests on Android and Windows. ## Original description Improves the build output: 1. Gives confirmation that the build succeeded, in green 1. Gives the path to the built executable, without a trailing period to make it slightly easier to cmd/ctrl+open 1. Gives the size of the built executable (when the built executable is self contained) ### `apk`, `appbundle` <img width="607" alt="image" src="https://github.com/flutter/flutter/assets/6655696/ecc52abe-cd2e-4116-b22a-8385ae3e980d"> <img width="634" alt="image" src="https://github.com/flutter/flutter/assets/6655696/8af8bd33-c0bd-4215-9a06-9652ee019436"> ### `macos`, `ios`, `ipa` Build executables are self-contained and use a newly introduced `OperatingSystemUtils.getDirectorySize`. <img width="514" alt="image" src="https://github.com/flutter/flutter/assets/6655696/b5918a69-3959-4417-9205-4f501d185257"> <img width="581" alt="image" src="https://github.com/flutter/flutter/assets/6655696/d72fd420-18cf-4470-9e4b-b6ac10fbcd50"> <img width="616" alt="image" src="https://github.com/flutter/flutter/assets/6655696/5f235ce1-252a-4c13-898f-139f6c7bc698"> ### `windows`, `linux`, and `web` Build executables aren't self-contained, and folder size can sometimes overestimate distribution size, therefore their size isn't mentioned (see discussion below). <img width="647" alt="image" src="https://github.com/flutter/flutter/assets/6655696/7179e771-1eb7-48f6-b770-975bc073437b"> <img width="658" alt="image" src="https://github.com/flutter/flutter/assets/6655696/a6801cab-7b5a-4975-a406-f4c9fa44d7a2"> <img width="608" alt="image" src="https://github.com/flutter/flutter/assets/6655696/ee7c4125-a273-4a65-95d7-ab441edf8ac5"> ### Size reporting When applicable, the printed size matches the OS reported size. - macOS <img width="391" alt="image" src="https://github.com/flutter/flutter/assets/6655696/881cbfb1-d355-444b-ab44-c1a6343190ce"> - Windows <img width="338" alt="image" src="https://github.com/flutter/flutter/assets/6655696/3b806def-3d15-48a9-8a25-df200d6feef7"> - Linux <img width="320" alt="image" src="https://github.com/flutter/flutter/assets/6655696/89a4aa3d-2148-4f3b-b231-f93a057fee2b"> ## Related issues Part of #120127 Fixes https://github.com/flutter/flutter/issues/121401
309 lines
12 KiB
Dart
309 lines
12 KiB
Dart
// 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 'package:process/process.dart';
|
|
import 'package:unified_analytics/unified_analytics.dart';
|
|
|
|
import '../artifacts.dart';
|
|
import '../base/common.dart';
|
|
import '../base/file_system.dart';
|
|
import '../base/logger.dart';
|
|
import '../base/project_migrator.dart';
|
|
import '../base/utils.dart';
|
|
import '../build_info.dart';
|
|
import '../build_system/build_system.dart';
|
|
import '../cache.dart';
|
|
import '../flutter_plugins.dart';
|
|
import '../globals.dart' as globals;
|
|
import '../platform_plugins.dart';
|
|
import '../plugins.dart';
|
|
import '../project.dart';
|
|
import '../reporting/reporting.dart';
|
|
import '../version.dart';
|
|
import 'compiler_config.dart';
|
|
import 'file_generators/flutter_service_worker_js.dart';
|
|
import 'migrations/scrub_generated_plugin_registrant.dart';
|
|
|
|
export 'compiler_config.dart';
|
|
|
|
/// Whether the application has web plugins.
|
|
const String kHasWebPlugins = 'HasWebPlugins';
|
|
|
|
/// 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';
|
|
|
|
class WebBuilder {
|
|
WebBuilder({
|
|
required Logger logger,
|
|
required ProcessManager processManager,
|
|
required BuildSystem buildSystem,
|
|
required Usage usage,
|
|
required Analytics analytics,
|
|
required FlutterVersion flutterVersion,
|
|
required FileSystem fileSystem,
|
|
}) : _logger = logger,
|
|
_processManager = processManager,
|
|
_buildSystem = buildSystem,
|
|
_flutterUsage = usage,
|
|
_analytics = analytics,
|
|
_flutterVersion = flutterVersion,
|
|
_fileSystem = fileSystem;
|
|
|
|
final Logger _logger;
|
|
final ProcessManager _processManager;
|
|
final BuildSystem _buildSystem;
|
|
final Usage _flutterUsage;
|
|
final Analytics _analytics;
|
|
final FlutterVersion _flutterVersion;
|
|
final FileSystem _fileSystem;
|
|
|
|
Future<void> buildWeb(
|
|
FlutterProject flutterProject,
|
|
String target,
|
|
BuildInfo buildInfo,
|
|
ServiceWorkerStrategy serviceWorkerStrategy, {
|
|
required List<WebCompilerConfig> compilerConfigs,
|
|
String? baseHref,
|
|
String? outputDirectoryPath,
|
|
}) async {
|
|
final bool hasWebPlugins =
|
|
(await findPlugins(flutterProject)).any((Plugin p) => p.platforms.containsKey(WebPlugin.kConfigKey));
|
|
final Directory outputDirectory = outputDirectoryPath == null
|
|
? _fileSystem.directory(getWebBuildDirectory())
|
|
: _fileSystem.directory(outputDirectoryPath);
|
|
outputDirectory.createSync(recursive: true);
|
|
|
|
// The migrators to apply to a Web project.
|
|
final List<ProjectMigrator> migrators = <ProjectMigrator>[
|
|
ScrubGeneratedPluginRegistrant(flutterProject.web, _logger),
|
|
];
|
|
|
|
final ProjectMigration migration = ProjectMigration(migrators);
|
|
migration.run();
|
|
|
|
final Status status = _logger.startProgress('Compiling $target for the Web...');
|
|
final Stopwatch sw = Stopwatch()..start();
|
|
try {
|
|
final BuildResult result = await _buildSystem.build(
|
|
globals.buildTargets.webServiceWorker(_fileSystem, compilerConfigs),
|
|
Environment(
|
|
projectDir: _fileSystem.currentDirectory,
|
|
outputDir: outputDirectory,
|
|
buildDir: flutterProject.directory.childDirectory('.dart_tool').childDirectory('flutter_build'),
|
|
defines: <String, String>{
|
|
kTargetFile: target,
|
|
kHasWebPlugins: hasWebPlugins.toString(),
|
|
if (baseHref != null) kBaseHref: baseHref,
|
|
kServiceWorkerStrategy: serviceWorkerStrategy.cliName,
|
|
...buildInfo.toBuildSystemEnvironment(),
|
|
},
|
|
artifacts: globals.artifacts!,
|
|
fileSystem: _fileSystem,
|
|
logger: _logger,
|
|
processManager: _processManager,
|
|
platform: globals.platform,
|
|
usage: _flutterUsage,
|
|
analytics: _analytics,
|
|
cacheDir: globals.cache.getRoot(),
|
|
engineVersion: globals.artifacts!.isLocalEngine ? null : _flutterVersion.engineRevision,
|
|
flutterRootDir: _fileSystem.directory(Cache.flutterRoot),
|
|
// Web uses a different Dart plugin registry.
|
|
// https://github.com/flutter/flutter/issues/80406
|
|
generateDartPluginRegistry: false,
|
|
));
|
|
if (!result.success) {
|
|
for (final ExceptionMeasurement measurement in result.exceptions.values) {
|
|
_logger.printError(
|
|
'Target ${measurement.target} failed: ${measurement.exception}',
|
|
stackTrace: measurement.fatal ? measurement.stackTrace : null,
|
|
);
|
|
}
|
|
throwToolExit('Failed to compile application for the Web.');
|
|
}
|
|
} on Exception catch (err) {
|
|
throwToolExit(err.toString());
|
|
} finally {
|
|
status.stop();
|
|
}
|
|
|
|
final String buildSettingsString = _buildEventAnalyticsSettings(
|
|
configs: compilerConfigs,
|
|
);
|
|
|
|
BuildEvent(
|
|
'web-compile',
|
|
type: 'web',
|
|
settings: buildSettingsString,
|
|
flutterUsage: _flutterUsage,
|
|
).send();
|
|
_analytics.send(Event.flutterBuildInfo(
|
|
label: 'web-compile',
|
|
buildType: 'web',
|
|
settings: buildSettingsString,
|
|
));
|
|
|
|
final Duration elapsedDuration = sw.elapsed;
|
|
final String variableName = compilerConfigs.length > 1 ? 'dual-compile' : 'dart2js';
|
|
_flutterUsage.sendTiming(
|
|
'build',
|
|
variableName,
|
|
elapsedDuration,
|
|
);
|
|
_analytics.send(Event.timing(
|
|
workflow: 'build',
|
|
variableName: variableName,
|
|
elapsedMilliseconds: elapsedDuration.inMilliseconds,
|
|
));
|
|
}
|
|
}
|
|
|
|
/// Web rendering backend mode.
|
|
enum WebRendererMode implements CliEnum {
|
|
/// Auto detects which rendering backend to use.
|
|
auto,
|
|
|
|
/// Always uses canvaskit.
|
|
canvaskit,
|
|
|
|
/// Always uses html.
|
|
html,
|
|
|
|
/// Always use skwasm.
|
|
skwasm;
|
|
|
|
@override
|
|
String get cliName => snakeCase(name, '-');
|
|
|
|
@override
|
|
String get helpText => switch (this) {
|
|
auto =>
|
|
'Use the HTML renderer on mobile devices, and CanvasKit on desktop devices.',
|
|
canvaskit =>
|
|
'Always use the CanvasKit renderer. This renderer uses WebGL and WebAssembly to render graphics.',
|
|
html =>
|
|
'Always use the HTML renderer. This renderer uses a combination of HTML, CSS, SVG, 2D Canvas, and WebGL.',
|
|
skwasm => 'Always use the experimental skwasm renderer.'
|
|
};
|
|
|
|
Iterable<String> get dartDefines => switch (this) {
|
|
WebRendererMode.auto => <String>[
|
|
'FLUTTER_WEB_AUTO_DETECT=true',
|
|
],
|
|
WebRendererMode.canvaskit => <String>[
|
|
'FLUTTER_WEB_AUTO_DETECT=false',
|
|
'FLUTTER_WEB_USE_SKIA=true',
|
|
],
|
|
WebRendererMode.html => <String>[
|
|
'FLUTTER_WEB_AUTO_DETECT=false',
|
|
'FLUTTER_WEB_USE_SKIA=false',
|
|
],
|
|
WebRendererMode.skwasm => <String>[
|
|
'FLUTTER_WEB_AUTO_DETECT=false',
|
|
'FLUTTER_WEB_USE_SKIA=false',
|
|
'FLUTTER_WEB_USE_SKWASM=true',
|
|
]
|
|
};
|
|
|
|
List<String> updateDartDefines(List<String> inputDefines) {
|
|
final Set<String> dartDefinesSet = inputDefines.toSet();
|
|
if (!inputDefines.any((String d) => d.startsWith('FLUTTER_WEB_AUTO_DETECT='))
|
|
&& inputDefines.any((String d) => d.startsWith('FLUTTER_WEB_USE_SKIA='))) {
|
|
dartDefinesSet.removeWhere((String d) => d.startsWith('FLUTTER_WEB_USE_SKIA='));
|
|
}
|
|
dartDefinesSet.addAll(dartDefines);
|
|
return dartDefinesSet.toList();
|
|
}
|
|
}
|
|
|
|
/// The correct precompiled artifact to use for each build and render mode for DDC with AMD modules.
|
|
// TODO(markzipan): delete this when DDC's AMD module system is deprecated, https://github.com/flutter/flutter/issues/142060.
|
|
const Map<WebRendererMode, Map<NullSafetyMode, HostArtifact>> kAmdDartSdkJsArtifactMap = <WebRendererMode, Map<NullSafetyMode, HostArtifact>>{
|
|
WebRendererMode.auto: <NullSafetyMode, HostArtifact> {
|
|
NullSafetyMode.sound: HostArtifact.webPrecompiledAmdCanvaskitAndHtmlSoundSdk,
|
|
NullSafetyMode.unsound: HostArtifact.webPrecompiledAmdCanvaskitAndHtmlSdk,
|
|
},
|
|
WebRendererMode.canvaskit: <NullSafetyMode, HostArtifact> {
|
|
NullSafetyMode.sound: HostArtifact.webPrecompiledAmdCanvaskitSoundSdk,
|
|
NullSafetyMode.unsound: HostArtifact.webPrecompiledAmdCanvaskitSdk,
|
|
},
|
|
WebRendererMode.html: <NullSafetyMode, HostArtifact> {
|
|
NullSafetyMode.sound: HostArtifact.webPrecompiledAmdSoundSdk,
|
|
NullSafetyMode.unsound: HostArtifact.webPrecompiledAmdSdk,
|
|
},
|
|
};
|
|
|
|
/// The correct source map artifact to use for each build and render mode for DDC with AMD modules.
|
|
// TODO(markzipan): delete this when DDC's AMD module system is deprecated, https://github.com/flutter/flutter/issues/142060.
|
|
const Map<WebRendererMode, Map<NullSafetyMode, HostArtifact>> kAmdDartSdkJsMapArtifactMap = <WebRendererMode, Map<NullSafetyMode, HostArtifact>>{
|
|
WebRendererMode.auto: <NullSafetyMode, HostArtifact> {
|
|
NullSafetyMode.sound: HostArtifact.webPrecompiledAmdCanvaskitAndHtmlSoundSdkSourcemaps,
|
|
NullSafetyMode.unsound: HostArtifact.webPrecompiledAmdCanvaskitAndHtmlSdkSourcemaps,
|
|
},
|
|
WebRendererMode.canvaskit: <NullSafetyMode, HostArtifact> {
|
|
NullSafetyMode.sound: HostArtifact.webPrecompiledAmdCanvaskitSoundSdkSourcemaps,
|
|
NullSafetyMode.unsound: HostArtifact.webPrecompiledAmdCanvaskitSdkSourcemaps,
|
|
},
|
|
WebRendererMode.html: <NullSafetyMode, HostArtifact> {
|
|
NullSafetyMode.sound: HostArtifact.webPrecompiledAmdSoundSdkSourcemaps,
|
|
NullSafetyMode.unsound: HostArtifact.webPrecompiledAmdSdkSourcemaps,
|
|
},
|
|
};
|
|
|
|
/// The correct precompiled artifact to use for each build and render mode for DDC with DDC modules.
|
|
const Map<WebRendererMode, Map<NullSafetyMode, HostArtifact>> kDdcDartSdkJsArtifactMap = <WebRendererMode, Map<NullSafetyMode, HostArtifact>>{
|
|
WebRendererMode.auto: <NullSafetyMode, HostArtifact> {
|
|
NullSafetyMode.sound: HostArtifact.webPrecompiledDdcCanvaskitAndHtmlSoundSdk,
|
|
NullSafetyMode.unsound: HostArtifact.webPrecompiledDdcCanvaskitAndHtmlSdk,
|
|
},
|
|
WebRendererMode.canvaskit: <NullSafetyMode, HostArtifact> {
|
|
NullSafetyMode.sound: HostArtifact.webPrecompiledDdcCanvaskitSoundSdk,
|
|
NullSafetyMode.unsound: HostArtifact.webPrecompiledDdcCanvaskitSdk,
|
|
},
|
|
WebRendererMode.html: <NullSafetyMode, HostArtifact> {
|
|
NullSafetyMode.sound: HostArtifact.webPrecompiledDdcSoundSdk,
|
|
NullSafetyMode.unsound: HostArtifact.webPrecompiledDdcSdk,
|
|
},
|
|
};
|
|
|
|
/// The correct source map artifact to use for each build and render mode for DDC with DDC modules.
|
|
const Map<WebRendererMode, Map<NullSafetyMode, HostArtifact>> kDdcDartSdkJsMapArtifactMap = <WebRendererMode, Map<NullSafetyMode, HostArtifact>>{
|
|
WebRendererMode.auto: <NullSafetyMode, HostArtifact> {
|
|
NullSafetyMode.sound: HostArtifact.webPrecompiledDdcCanvaskitAndHtmlSoundSdkSourcemaps,
|
|
NullSafetyMode.unsound: HostArtifact.webPrecompiledDdcCanvaskitAndHtmlSdkSourcemaps,
|
|
},
|
|
WebRendererMode.canvaskit: <NullSafetyMode, HostArtifact> {
|
|
NullSafetyMode.sound: HostArtifact.webPrecompiledDdcCanvaskitSoundSdkSourcemaps,
|
|
NullSafetyMode.unsound: HostArtifact.webPrecompiledDdcCanvaskitSdkSourcemaps,
|
|
},
|
|
WebRendererMode.html: <NullSafetyMode, HostArtifact> {
|
|
NullSafetyMode.sound: HostArtifact.webPrecompiledDdcSoundSdkSourcemaps,
|
|
NullSafetyMode.unsound: HostArtifact.webPrecompiledDdcSdkSourcemaps,
|
|
},
|
|
};
|
|
|
|
String _buildEventAnalyticsSettings({
|
|
required List<WebCompilerConfig> configs,
|
|
}) {
|
|
final Map<String, Object> values = <String, Object>{};
|
|
final List<String> renderers = <String>[];
|
|
final List<String> targets = <String>[];
|
|
for (final WebCompilerConfig config in configs) {
|
|
values.addAll(config.buildEventAnalyticsValues);
|
|
renderers.add(config.renderer.name);
|
|
targets.add(config.compileTarget.name);
|
|
}
|
|
values['web-renderer'] = renderers.join(',');
|
|
values['web-target'] = targets.join(',');
|
|
|
|
final List<String> sortedList = values.entries
|
|
.map((MapEntry<String, Object> e) => '${e.key}: ${e.value};')
|
|
.toList()
|
|
..sort();
|
|
|
|
return sortedList.join(' ');
|
|
}
|