Codegen an entrypoint for flutter web applications (#33956)

diff --git a/packages/flutter_tools/lib/src/web/asset_server.dart b/packages/flutter_tools/lib/src/web/asset_server.dart
index 730692c..ebe41be 100644
--- a/packages/flutter_tools/lib/src/web/asset_server.dart
+++ b/packages/flutter_tools/lib/src/web/asset_server.dart
@@ -66,6 +66,7 @@
 
   /// An HTTP server which provides JavaScript and web assets to the browser.
   Future<void> _onRequest(HttpRequest request) async {
+    final String targetName = '${fs.path.basenameWithoutExtension(target)}_web_entrypoint';
     if (request.method != 'GET') {
       request.response.statusCode = HttpStatus.forbidden;
       await request.response.close();
@@ -103,17 +104,17 @@
         'flutter_web',
         flutterProject.manifest.appName,
         'lib',
-        '${fs.path.basename(target)}.js',
+        '$targetName.dart.js',
       ));
       await _completeRequest(request, file, 'text/javascript');
-    } else if (uri.path.endsWith('${fs.path.basename(target)}.bootstrap.js')) {
+    } else if (uri.path.endsWith('$targetName.dart.bootstrap.js')) {
       final File file = fs.file(fs.path.join(
         flutterProject.dartTool.path,
         'build',
         'flutter_web',
         flutterProject.manifest.appName,
         'lib',
-        '${fs.path.basename(target)}.bootstrap.js',
+        '$targetName.dart.bootstrap.js',
       ));
       await _completeRequest(request, file, 'text/javascript');
     } else if (uri.path.contains('dart_sdk')) {
diff --git a/packages/flutter_tools/lib/src/web/compile.dart b/packages/flutter_tools/lib/src/web/compile.dart
index 732769a..90b7ea3 100644
--- a/packages/flutter_tools/lib/src/web/compile.dart
+++ b/packages/flutter_tools/lib/src/web/compile.dart
@@ -4,80 +4,56 @@
 
 import 'package:meta/meta.dart';
 
-import '../artifacts.dart';
+import '../asset.dart';
 import '../base/common.dart';
 import '../base/context.dart';
 import '../base/file_system.dart';
-import '../base/io.dart';
-import '../base/process_manager.dart';
+import '../base/logger.dart';
 import '../build_info.dart';
-import '../convert.dart';
+import '../bundle.dart';
 import '../globals.dart';
-
-/// The [WebCompiler] instance.
-WebCompiler get webCompiler => context.get<WebCompiler>();
+import '../project.dart';
 
 /// The [WebCompilationProxy] instance.
-WebCompilationProxy get webCompilationProxy =>
-    context.get<WebCompilationProxy>();
+WebCompilationProxy get webCompilationProxy => context.get<WebCompilationProxy>();
 
-/// A wrapper around dart tools for web compilation.
-class WebCompiler {
-  const WebCompiler();
+Future<void> buildWeb(FlutterProject flutterProject, String target, BuildInfo buildInfo) async {
+  final Status status = logger.startProgress('Compiling $target for the Web...', timeout: null);
+  final Directory outputDir = fs.directory(getWebBuildDirectory())
+    ..createSync(recursive: true);
+  bool result;
+  try {
+    result = await webCompilationProxy.initialize(
+      projectDirectory: FlutterProject.current().directory,
+      targets: <String>[target],
+      release: buildInfo.isRelease,
+    );
+    if (result) {
+      // Places assets adjacent to the web stuff.
+      final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle();
+      await assetBundle.build();
+      await writeBundle(fs.directory(fs.path.join(outputDir.path, 'assets')), assetBundle.entries);
 
-  /// Compile `target` using dart2js.
-  ///
-  /// `minify` controls whether minifaction of the source is enabled. Defaults to `true`.
-  /// `enabledAssertions` controls whether assertions are enabled. Defaults to `false`.
-  Future<int> compileDart2js({
-    @required String target,
-    bool minify = true,
-    bool enabledAssertions = false,
-  }) async {
-    final String engineDartPath =
-        artifacts.getArtifactPath(Artifact.engineDartBinary);
-    final String dart2jsPath =
-        artifacts.getArtifactPath(Artifact.dart2jsSnapshot);
-    final String flutterWebSdkPath =
-        artifacts.getArtifactPath(Artifact.flutterWebSdk);
-    final String librariesPath =
-        fs.path.join(flutterWebSdkPath, 'libraries.json');
-    final Directory outputDir = fs.directory(getWebBuildDirectory());
-    if (!outputDir.existsSync()) {
-      outputDir.createSync(recursive: true);
+      // Copy results to output directory.
+      final String outputPath = fs.path.join(
+        flutterProject.dartTool.path,
+        'build',
+        'flutter_web',
+        flutterProject.manifest.appName,
+        '${fs.path.withoutExtension(target)}_web_entrypoint.dart.js'
+      );
+      fs.file(outputPath).copySync(fs.path.join(outputDir.path, 'main.dart.js'));
+      fs.file('$outputPath.map').copySync(fs.path.join(outputDir.path, 'main.dart.js.map'));
+      flutterProject.web.indexFile.copySync(fs.path.join(outputDir.path, 'index.html'));
     }
-    final String outputPath = fs.path.join(outputDir.path, 'main.dart.js');
-    if (!processManager.canRun(engineDartPath)) {
-      throwToolExit('Unable to find Dart binary at $engineDartPath');
-    }
-
-    /// Compile Dart to JavaScript.
-    final List<String> command = <String>[
-      engineDartPath,
-      dart2jsPath,
-      target,
-      '-o',
-      '$outputPath',
-      '-O4',
-      '--libraries-spec=$librariesPath',
-    ];
-    if (minify) {
-      command.add('-m');
-    }
-    if (enabledAssertions) {
-      command.add('--enable-asserts');
-    }
-    printTrace(command.join(' '));
-    final Process result = await processManager.start(command);
-    result.stdout
-        .transform(utf8.decoder)
-        .transform(const LineSplitter())
-        .listen(printStatus);
-    result.stderr
-        .transform(utf8.decoder)
-        .transform(const LineSplitter())
-        .listen(printError);
-    return result.exitCode;
+  } catch (err) {
+    printError(err.toString());
+    result = false;
+  } finally {
+    status.stop();
+  }
+  if (result == false) {
+    throwToolExit('Failed to compile $target for the Web.');
   }
 }
 
@@ -87,12 +63,19 @@
 class WebCompilationProxy {
   const WebCompilationProxy();
 
-  /// Initialize the web compiler output to `outputDirectory` from a project spawned at
-  /// `projectDirectory`.
-  Future<void> initialize({
+  /// Initialize the web compiler from the `projectDirectory`.
+  ///
+  /// Returns whether or not the build was successful.
+  ///
+  /// `release` controls whether we build the bundle for dartdevc or only
+  /// the entrypoints for dart2js to later take over.
+  ///
+  /// `targets` controls the specific compiler targets.
+  Future<bool> initialize({
     @required Directory projectDirectory,
     @required List<String> targets,
     String testOutputDir,
+    bool release,
   }) async {
     throw UnimplementedError();
   }
diff --git a/packages/flutter_tools/lib/src/web/web_device.dart b/packages/flutter_tools/lib/src/web/web_device.dart
index b824343..86a10e8 100644
--- a/packages/flutter_tools/lib/src/web/web_device.dart
+++ b/packages/flutter_tools/lib/src/web/web_device.dart
@@ -5,15 +5,11 @@
 import 'package:meta/meta.dart';
 
 import '../application_package.dart';
-import '../asset.dart';
-import '../base/common.dart';
 import '../base/file_system.dart';
 import '../base/io.dart';
-import '../base/logger.dart';
 import '../base/platform.dart';
 import '../base/process_manager.dart';
 import '../build_info.dart';
-import '../bundle.dart';
 import '../device.dart';
 import '../globals.dart';
 import '../project.dart';
@@ -22,15 +18,15 @@
 import 'chrome.dart';
 
 class WebApplicationPackage extends ApplicationPackage {
-  WebApplicationPackage(this._flutterProject) : super(id: _flutterProject.manifest.appName);
+  WebApplicationPackage(this.flutterProject) : super(id: flutterProject.manifest.appName);
 
-  final FlutterProject _flutterProject;
+  final FlutterProject flutterProject;
 
   @override
-  String get name => _flutterProject.manifest.appName;
+  String get name => flutterProject.manifest.appName;
 
   /// The location of the web source assets.
-  Directory get webSourcePath => _flutterProject.directory.childDirectory('web');
+  Directory get webSourcePath => flutterProject.directory.childDirectory('web');
 }
 
 class WebDevice extends Device {
@@ -121,20 +117,11 @@
     bool usesTerminalUi = true,
     bool ipv6 = false,
   }) async {
-    final Status status = logger.startProgress('Compiling ${package.name} to JavaScript...', timeout: null);
-    final int result = await webCompiler.compileDart2js(target: mainPath, minify: false, enabledAssertions: true);
-    status.stop();
-    if (result != 0) {
-      printError('Failed to compile ${package.name} to JavaScript');
-      return LaunchResult.failed();
-    }
-    final AssetBundle assetBundle = AssetBundleFactory.instance.createBundle();
-    final int build = await assetBundle.build();
-    if (build != 0) {
-      throwToolExit('Error: Failed to build asset bundle');
-    }
-    await writeBundle(fs.directory(getAssetBuildDirectory()), assetBundle.entries);
-
+    await buildWeb(
+      package.flutterProject,
+      fs.path.relative(mainPath, from: package.flutterProject.directory.path),
+      debuggingOptions.buildInfo,
+    );
     _package = package;
     _server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
     _server.listen(_basicAssetServer);