| // Copyright 2019 The Chromium 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 '../../artifacts.dart'; |
| import '../../base/file_system.dart'; |
| import '../../base/io.dart'; |
| import '../../base/process_manager.dart'; |
| import '../../build_info.dart'; |
| import '../../dart/package_map.dart'; |
| import '../../globals.dart'; |
| import '../../project.dart'; |
| import '../build_system.dart'; |
| import '../depfile.dart'; |
| import 'assets.dart'; |
| import 'dart.dart'; |
| |
| /// Whether web builds should call the platform initialization logic. |
| const String kInitializePlatform = 'InitializePlatform'; |
| |
| /// 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'; |
| |
| /// Generates an entry point for a web target. |
| class WebEntrypointTarget extends Target { |
| const WebEntrypointTarget(); |
| |
| @override |
| String get name => 'web_entrypoint'; |
| |
| @override |
| List<Target> get dependencies => const <Target>[]; |
| |
| @override |
| List<Source> get inputs => const <Source>[ |
| Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/web.dart'), |
| ]; |
| |
| @override |
| List<Source> get outputs => const <Source>[ |
| Source.pattern('{BUILD_DIR}/main.dart'), |
| ]; |
| |
| @override |
| Future<void> build(Environment environment) async { |
| final String targetFile = environment.defines[kTargetFile]; |
| final bool shouldInitializePlatform = environment.defines[kInitializePlatform] == 'true'; |
| final bool hasPlugins = environment.defines[kHasWebPlugins] == 'true'; |
| final String import = fs.file(fs.path.absolute(targetFile)).uri.toString(); |
| |
| String contents; |
| if (hasPlugins) { |
| final String generatedPath = environment.projectDir |
| .childDirectory('lib') |
| .childFile('generated_plugin_registrant.dart') |
| .absolute.uri.toString(); |
| contents = ''' |
| import 'dart:ui' as ui; |
| |
| import 'package:flutter_web_plugins/flutter_web_plugins.dart'; |
| |
| import '$generatedPath'; |
| import "$import" as entrypoint; |
| |
| Future<void> main() async { |
| registerPlugins(webPluginRegistry); |
| if ($shouldInitializePlatform) { |
| await ui.webOnlyInitializePlatform(); |
| } |
| entrypoint.main(); |
| } |
| '''; |
| } else { |
| contents = ''' |
| import 'dart:ui' as ui; |
| |
| import "$import" as entrypoint; |
| |
| Future<void> main() async { |
| if ($shouldInitializePlatform) { |
| await ui.webOnlyInitializePlatform(); |
| } |
| entrypoint.main(); |
| } |
| '''; |
| } |
| environment.buildDir.childFile('main.dart') |
| ..writeAsStringSync(contents); |
| } |
| } |
| |
| /// Compiles a web entry point with dart2js. |
| class Dart2JSTarget extends Target { |
| const Dart2JSTarget(); |
| |
| @override |
| String get name => 'dart2js'; |
| |
| @override |
| List<Target> get dependencies => const <Target>[ |
| WebEntrypointTarget() |
| ]; |
| |
| @override |
| List<Source> get inputs => const <Source>[ |
| Source.artifact(Artifact.flutterWebSdk), |
| Source.artifact(Artifact.dart2jsSnapshot), |
| Source.artifact(Artifact.engineDartBinary), |
| Source.pattern('{BUILD_DIR}/main.dart'), |
| Source.pattern('{PROJECT_DIR}/.packages'), |
| ]; |
| |
| @override |
| List<Source> get outputs => const <Source>[]; |
| |
| @override |
| List<String> get depfiles => const <String>[ |
| 'dart2js.d', |
| ]; |
| |
| @override |
| Future<void> build(Environment environment) async { |
| final String dart2jsOptimization = environment.defines[kDart2jsOptimization]; |
| final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); |
| final String specPath = fs.path.join(artifacts.getArtifactPath(Artifact.flutterWebSdk), 'libraries.json'); |
| final String packageFile = FlutterProject.fromDirectory(environment.projectDir).hasBuilders |
| ? PackageMap.globalGeneratedPackagesPath |
| : PackageMap.globalPackagesPath; |
| final File outputFile = environment.buildDir.childFile('main.dart.js'); |
| |
| final ProcessResult result = await processManager.run(<String>[ |
| artifacts.getArtifactPath(Artifact.engineDartBinary), |
| artifacts.getArtifactPath(Artifact.dart2jsSnapshot), |
| '--libraries-spec=$specPath', |
| if (dart2jsOptimization != null) |
| '-$dart2jsOptimization' |
| else |
| '-O4', |
| if (buildMode == BuildMode.profile) |
| '--no-minify', |
| '-o', |
| outputFile.path, |
| '--packages=$packageFile', |
| if (buildMode == BuildMode.profile) |
| '-Ddart.vm.profile=true' |
| else |
| '-Ddart.vm.product=true', |
| for (String dartDefine in parseDartDefines(environment)) |
| '-D$dartDefine', |
| environment.buildDir.childFile('main.dart').path, |
| ]); |
| if (result.exitCode != 0) { |
| throw Exception(result.stdout + result.stderr); |
| } |
| final File dart2jsDeps = environment.buildDir |
| .childFile('main.dart.js.deps'); |
| if (!dart2jsDeps.existsSync()) { |
| printError('Warning: dart2js did not produced expected deps list at ' |
| '${dart2jsDeps.path}'); |
| return; |
| } |
| final Depfile depfile = Depfile.parseDart2js( |
| environment.buildDir.childFile('main.dart.js.deps'), |
| outputFile, |
| ); |
| depfile.writeToFile(environment.buildDir.childFile('dart2js.d')); |
| } |
| } |
| |
| /// Unpacks the dart2js compilation to a given output directory |
| class WebReleaseBundle extends Target { |
| const WebReleaseBundle(); |
| |
| @override |
| String get name => 'web_release_bundle'; |
| |
| @override |
| List<Target> get dependencies => const <Target>[ |
| Dart2JSTarget(), |
| ]; |
| |
| @override |
| List<Source> get inputs => const <Source>[ |
| Source.pattern('{BUILD_DIR}/main.dart.js'), |
| Source.pattern('{PROJECT_DIR}/pubspec.yaml'), |
| Source.pattern('{PROJECT_DIR}/web/index.html'), |
| ]; |
| |
| @override |
| List<Source> get outputs => const <Source>[ |
| Source.pattern('{OUTPUT_DIR}/main.dart.js'), |
| Source.pattern('{OUTPUT_DIR}/index.html'), |
| ]; |
| |
| @override |
| List<String> get depfiles => const <String>[ |
| 'dart2js.d', |
| ]; |
| |
| @override |
| Future<void> build(Environment environment) async { |
| for (File outputFile in environment.buildDir.listSync(recursive: true).whereType<File>()) { |
| if (!fs.path.basename(outputFile.path).contains('main.dart.js')) { |
| continue; |
| } |
| outputFile.copySync( |
| environment.outputDir.childFile(fs.path.basename(outputFile.path)).path |
| ); |
| } |
| final Directory outputDirectory = environment.outputDir.childDirectory('assets'); |
| outputDirectory.createSync(recursive: true); |
| environment.projectDir |
| .childDirectory('web') |
| .childFile('index.html') |
| .copySync(fs.path.join(environment.outputDir.path, 'index.html')); |
| final Depfile depfile = await copyAssets(environment, environment.outputDir.childDirectory('assets')); |
| depfile.writeToFile(environment.buildDir.childFile('flutter_assets.d')); |
| } |
| } |