Support `flutter run --wasm` and `flutter drive --wasm`. (#146231)

This adds support for adding the `--wasm` flag to `flutter run` and `flutter drive`
* Emits errors if you attempt to use the skwasm renderer without the `--wasm` flag
* Emits errors if you try to use `--wasm` when not using a web device
* Uses the skwasm renderer by default if you pass `--wasm` and no `--web-renderer`
diff --git a/dev/bots/suite_runners/run_web_long_running_tests.dart b/dev/bots/suite_runners/run_web_long_running_tests.dart
index 4ce1f02..5ae5d0c 100644
--- a/dev/bots/suite_runners/run_web_long_running_tests.dart
+++ b/dev/bots/suite_runners/run_web_long_running_tests.dart
@@ -32,6 +32,7 @@
         target: path.join('test_driver', 'failure.dart'),
         buildMode: buildMode,
         renderer: 'canvaskit',
+        wasm: false,
         // This test intentionally fails and prints stack traces in the browser
         // logs. To avoid confusion, silence browser output.
         silenceBrowserOutput: true,
@@ -42,6 +43,17 @@
         driver: path.join('test_driver', 'integration_test.dart'),
         buildMode: buildMode,
         renderer: 'canvaskit',
+        wasm: false,
+        expectWriteResponseFile: true,
+        expectResponseFileContent: 'null',
+      ),
+      () => _runFlutterDriverWebTest(
+        testAppDirectory: path.join('packages', 'integration_test', 'example'),
+        target: path.join('integration_test', 'example_test.dart'),
+        driver: path.join('test_driver', 'integration_test.dart'),
+        buildMode: buildMode,
+        renderer: 'skwasm',
+        wasm: true,
         expectWriteResponseFile: true,
         expectResponseFileContent: 'null',
       ),
@@ -51,6 +63,7 @@
         driver: path.join('test_driver', 'extended_integration_test.dart'),
         buildMode: buildMode,
         renderer: 'canvaskit',
+        wasm: false,
         expectWriteResponseFile: true,
         expectResponseFileContent: '''
 {
@@ -97,6 +110,7 @@
     () => _runWebE2eTest('capabilities_integration_canvaskit', buildMode: 'debug', renderer: 'auto'),
     () => _runWebE2eTest('capabilities_integration_canvaskit', buildMode: 'profile', renderer: 'canvaskit'),
     () => _runWebE2eTest('capabilities_integration_html', buildMode: 'release', renderer: 'html'),
+    () => _runWebE2eTest('capabilities_integration_skwasm', buildMode: 'release', renderer: 'skwasm', wasm: true),
 
     // This test doesn't do anything interesting w.r.t. rendering, so we don't run the full build mode x renderer matrix.
     // CacheWidth and CacheHeight are only currently supported in CanvasKit mode, so we don't run the test in HTML mode.
@@ -110,6 +124,7 @@
       target: 'test_driver/smoke_web_engine.dart',
       buildMode: 'profile',
       renderer: 'auto',
+      wasm: false,
     ),
     () => _runGalleryE2eWebTest('debug'),
     () => _runGalleryE2eWebTest('debug', canvasKit: true),
@@ -192,12 +207,14 @@
   String name, {
   required String buildMode,
   required String renderer,
+  bool wasm = false,
 }) async {
   await _runFlutterDriverWebTest(
     target: path.join('test_driver', '$name.dart'),
     buildMode: buildMode,
     renderer: renderer,
     testAppDirectory: path.join(flutterRoot, 'dev', 'integration_tests', 'web_e2e_tests'),
+    wasm: wasm,
   );
 }
 
@@ -206,6 +223,7 @@
   required String buildMode,
   required String renderer,
   required String testAppDirectory,
+  required bool wasm,
   String? driver,
   bool expectFailure = false,
   bool silenceBrowserOutput = false,
@@ -235,6 +253,7 @@
       'web-server',
       '--$buildMode',
       '--web-renderer=$renderer',
+      if (wasm) '--wasm',
     ],
     expectNonZeroExit: expectFailure,
     workingDirectory: testAppDirectory,
diff --git a/dev/integration_tests/non_nullable/web/flutter_bootstrap.js b/dev/integration_tests/non_nullable/web/flutter_bootstrap.js
new file mode 100644
index 0000000..be78d93
--- /dev/null
+++ b/dev/integration_tests/non_nullable/web/flutter_bootstrap.js
@@ -0,0 +1,12 @@
+// 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.
+
+{{flutter_js}}
+{{flutter_build_config}}
+_flutter.loader.load({
+  config: {
+    // Use the local CanvasKit bundle instead of the CDN to reduce test flakiness.
+    canvasKitBaseUrl: "/canvaskit/",
+  },
+});
diff --git a/dev/integration_tests/non_nullable/web/index.html b/dev/integration_tests/non_nullable/web/index.html
index aae9e6e..dd2f083 100644
--- a/dev/integration_tests/non_nullable/web/index.html
+++ b/dev/integration_tests/non_nullable/web/index.html
@@ -22,16 +22,6 @@
   <link rel="manifest" href="manifest.json">
 </head>
 <body>
-  <!-- This script installs service_worker.js to provide PWA functionality to
-       application. For more information, see:
-       https://developers.google.com/web/fundamentals/primers/service-workers -->
-  <script>
-    if ('serviceWorker' in navigator) {
-      window.addEventListener('load', function () {
-        navigator.serviceWorker.register('flutter_service_worker.js');
-      });
-    }
-  </script>
-  <script src="main.dart.js" type="application/javascript"></script>
+  <script src="flutter_bootstrap.js" async></script>
 </body>
 </html>
diff --git a/dev/integration_tests/web_compile_tests/web/flutter_bootstrap.js b/dev/integration_tests/web_compile_tests/web/flutter_bootstrap.js
new file mode 100644
index 0000000..be78d93
--- /dev/null
+++ b/dev/integration_tests/web_compile_tests/web/flutter_bootstrap.js
@@ -0,0 +1,12 @@
+// 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.
+
+{{flutter_js}}
+{{flutter_build_config}}
+_flutter.loader.load({
+  config: {
+    // Use the local CanvasKit bundle instead of the CDN to reduce test flakiness.
+    canvasKitBaseUrl: "/canvaskit/",
+  },
+});
diff --git a/dev/integration_tests/web_compile_tests/web/index.html b/dev/integration_tests/web_compile_tests/web/index.html
index a856086..313adac 100644
--- a/dev/integration_tests/web_compile_tests/web/index.html
+++ b/dev/integration_tests/web_compile_tests/web/index.html
@@ -7,6 +7,6 @@
         <title>Hello, World</title>
     </head>
     <body>
-        <script src="main.dart.js"></script>
+        <script src="flutter_bootstrap.js" async></script>
     </body>
 </html>
diff --git a/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_canvaskit.dart b/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_canvaskit.dart
index 2dbbfb5..46d8a8a 100644
--- a/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_canvaskit.dart
+++ b/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_canvaskit.dart
@@ -12,5 +12,7 @@
   testWidgets('isCanvasKit returns true in CanvasKit mode', (WidgetTester tester) async {
     await tester.pumpAndSettle();
     expect(isCanvasKit, true);
+    expect(isSkwasm, false);
+    expect(isSkiaWeb, true);
   });
 }
diff --git a/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_html.dart b/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_html.dart
index 1f0a11e..d0830e1 100644
--- a/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_html.dart
+++ b/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_html.dart
@@ -8,8 +8,10 @@
 void main() {
   IntegrationTestWidgetsFlutterBinding.ensureInitialized();
 
-  testWidgets('isCanvasKit returns false in HTML mode', (WidgetTester tester) async {
+  testWidgets('capabilities are set properly in HTML mode', (WidgetTester tester) async {
     await tester.pumpAndSettle();
     expect(isCanvasKit, false);
+    expect(isSkwasm, false);
+    expect(isSkiaWeb, false);
   });
 }
diff --git a/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_skwasm.dart b/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_skwasm.dart
new file mode 100644
index 0000000..c16afb2
--- /dev/null
+++ b/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_skwasm.dart
@@ -0,0 +1,18 @@
+// 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:flutter/foundation.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:integration_test/integration_test.dart';
+
+void main() {
+  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
+
+  testWidgets('capabilities are set properly in Skwasm mode', (WidgetTester tester) async {
+    await tester.pumpAndSettle();
+    expect(isCanvasKit, false);
+    expect(isSkwasm, true);
+    expect(isSkiaWeb, true);
+  });
+}
diff --git a/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_skwasm_test.dart b/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_skwasm_test.dart
new file mode 100644
index 0000000..b2d2a17
--- /dev/null
+++ b/dev/integration_tests/web_e2e_tests/test_driver/capabilities_integration_skwasm_test.dart
@@ -0,0 +1,7 @@
+// 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:integration_test/integration_test_driver.dart' as test;
+
+Future<void> main() async => test.integrationDriver();
diff --git a/examples/hello_world/web/flutter_bootstrap.js b/examples/hello_world/web/flutter_bootstrap.js
new file mode 100644
index 0000000..be78d93
--- /dev/null
+++ b/examples/hello_world/web/flutter_bootstrap.js
@@ -0,0 +1,12 @@
+// 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.
+
+{{flutter_js}}
+{{flutter_build_config}}
+_flutter.loader.load({
+  config: {
+    // Use the local CanvasKit bundle instead of the CDN to reduce test flakiness.
+    canvasKitBaseUrl: "/canvaskit/",
+  },
+});
diff --git a/examples/hello_world/web/index.html b/examples/hello_world/web/index.html
index a856086..313adac 100644
--- a/examples/hello_world/web/index.html
+++ b/examples/hello_world/web/index.html
@@ -7,6 +7,6 @@
         <title>Hello, World</title>
     </head>
     <body>
-        <script src="main.dart.js"></script>
+        <script src="flutter_bootstrap.js" async></script>
     </body>
 </html>
diff --git a/packages/flutter_tools/lib/src/commands/build_web.dart b/packages/flutter_tools/lib/src/commands/build_web.dart
index db67a41..7244c45 100644
--- a/packages/flutter_tools/lib/src/commands/build_web.dart
+++ b/packages/flutter_tools/lib/src/commands/build_web.dart
@@ -64,7 +64,7 @@
       help:
           'Sets the optimization level used for Dart compilation to JavaScript/Wasm.',
       defaultsTo: '${WebCompilerConfig.kDefaultOptimizationLevel}',
-      allowed: const <String>['1', '2', '3', '4'],
+      allowed: const <String>['0', '1', '2', '3', '4'],
     );
 
     //
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index 8890928..548b9fc 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -30,6 +30,7 @@
 import '../tracing.dart';
 import '../vmservice.dart';
 import '../web/compile.dart';
+import '../web/web_constants.dart';
 import '../web/web_runner.dart';
 import 'daemon.dart';
 
@@ -179,7 +180,12 @@
         hide: !verboseHelp,
         help: 'Uninstall previous versions of the app on the device '
               'before reinstalling. Currently only supported on iOS.',
-    );
+      )
+      ..addFlag(
+        FlutterOptions.kWebWasmFlag,
+        help: 'Compile to WebAssembly rather than JavaScript.\n$kWasmMoreInfo',
+        negatable: false,
+      );
     usesWebOptions(verboseHelp: verboseHelp);
     usesTargetOption();
     usesPortOptions(verboseHelp: verboseHelp);
@@ -227,6 +233,13 @@
 
   String? get traceAllowlist => stringArg('trace-allowlist');
 
+  bool get useWasm => boolArg(FlutterOptions.kWebWasmFlag);
+
+  WebRendererMode get webRenderer => WebRendererMode.fromCliOption(
+    stringArg(FlutterOptions.kWebRendererFlag),
+    useWasm: useWasm
+  );
+
   /// Create a debugging options instance for the current `run` or `drive` invocation.
   @visibleForTesting
   @protected
@@ -242,10 +255,6 @@
     final Map<String, String> webHeaders = featureFlags.isWebEnabled
         ? extractWebHeaders()
         : const <String, String>{};
-    final String? webRendererString = stringArg('web-renderer');
-    final WebRendererMode webRenderer = (webRendererString != null)
-        ? WebRendererMode.values.byName(webRendererString)
-        : WebRendererMode.auto;
 
     if (buildInfo.mode.isRelease) {
       return DebuggingOptions.disabled(
@@ -264,6 +273,7 @@
         webBrowserFlags: webBrowserFlags,
         webHeaders: webHeaders,
         webRenderer: webRenderer,
+        webUseWasm: useWasm,
         enableImpeller: enableImpeller,
         enableVulkanValidation: enableVulkanValidation,
         uninstallFirst: uninstallFirst,
@@ -314,6 +324,7 @@
         webLaunchUrl: featureFlags.isWebEnabled ? stringArg('web-launch-url') : null,
         webHeaders: webHeaders,
         webRenderer: webRenderer,
+        webUseWasm: useWasm,
         vmserviceOutFile: stringArg('vmservice-out-file'),
         fastStart: argParser.options.containsKey('fast-start')
           && boolArg('fast-start')
@@ -630,12 +641,21 @@
     if (devices!.any((Device device) => device is AndroidDevice)) {
       _deviceDeprecationBehavior = DeprecationBehavior.exit;
     }
+
     // Only support "web mode" with a single web device due to resident runner
     // refactoring required otherwise.
     webMode = featureFlags.isWebEnabled &&
       devices!.length == 1  &&
       await devices!.single.targetPlatform == TargetPlatform.web_javascript;
 
+    if (useWasm && !webMode) {
+      throwToolExit('--wasm is only supported on the web platform');
+    }
+
+    if (webRenderer == WebRendererMode.skwasm && !useWasm) {
+      throwToolExit('Skwasm renderer requires --wasm');
+    }
+
     final String? flavor = stringArg('flavor');
     final bool flavorsSupportedOnEveryDevice = devices!
       .every((Device device) => device.supportsFlavors);
diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart
index abaa42f..b3cf671 100644
--- a/packages/flutter_tools/lib/src/commands/test.dart
+++ b/packages/flutter_tools/lib/src/commands/test.dart
@@ -330,6 +330,11 @@
     return super.verifyThenRunCommand(commandPath);
   }
 
+  WebRendererMode get webRenderer => WebRendererMode.fromCliOption(
+    stringArg(FlutterOptions.kWebRendererFlag),
+    useWasm: useWasm
+  );
+
   @override
   Future<FlutterCommandResult> runCommand() async {
     if (!globals.fs.isFileSync('pubspec.yaml')) {
@@ -388,10 +393,6 @@
       );
     }
 
-    final String? webRendererString = stringArg('web-renderer');
-    final WebRendererMode webRenderer = (webRendererString != null)
-        ? WebRendererMode.values.byName(webRendererString)
-        : WebRendererMode.auto;
     final DebuggingOptions debuggingOptions = DebuggingOptions.enabled(
       buildInfo,
       startPaused: startPaused,
@@ -405,6 +406,7 @@
       enableImpeller: ImpellerStatus.fromBool(argResults!['enable-impeller'] as bool?),
       debugLogsDirectoryPath: debugLogsDirectoryPath,
       webRenderer: webRenderer,
+      webUseWasm: useWasm,
     );
 
     String? testAssetDirectory;
@@ -511,6 +513,10 @@
       throwToolExit('--wasm is only supported on the web platform');
     }
 
+    if (webRenderer == WebRendererMode.skwasm && !useWasm) {
+      throwToolExit('Skwasm renderer requires --wasm');
+    }
+
     Device? integrationTestDevice;
     if (_isIntegrationTest) {
       integrationTestDevice = await findTargetDevice();
@@ -589,7 +595,6 @@
         testAssetDirectory: testAssetDirectory,
         flutterProject: flutterProject,
         web: isWeb,
-        useWasm: useWasm,
         randomSeed: stringArg('test-randomize-ordering-seed'),
         reporter: stringArg('reporter'),
         fileReporter: stringArg('file-reporter'),
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index 96006cd..6afabbd 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -994,6 +994,7 @@
     this.webHeaders = const <String, String>{},
     this.webLaunchUrl,
     this.webRenderer = WebRendererMode.auto,
+    this.webUseWasm = false,
     this.vmserviceOutFile,
     this.fastStart = false,
     this.nullAssertions = false,
@@ -1024,6 +1025,7 @@
       this.webLaunchUrl,
       this.webHeaders = const <String, String>{},
       this.webRenderer = WebRendererMode.auto,
+      this.webUseWasm = false,
       this.cacheSkSL = false,
       this.traceAllowlist,
       this.enableImpeller = ImpellerStatus.platformDefault,
@@ -1104,6 +1106,7 @@
     required this.webHeaders,
     required this.webLaunchUrl,
     required this.webRenderer,
+    required this.webUseWasm,
     required this.vmserviceOutFile,
     required this.fastStart,
     required this.nullAssertions,
@@ -1191,6 +1194,9 @@
   /// Which web renderer to use for the debugging session
   final WebRendererMode webRenderer;
 
+  /// Whether to compile to webassembly
+  final bool webUseWasm;
+
   /// A file where the VM Service URL should be written after the application is started.
   final String? vmserviceOutFile;
   final bool fastStart;
@@ -1300,6 +1306,7 @@
     'webLaunchUrl': webLaunchUrl,
     'webHeaders': webHeaders,
     'webRenderer': webRenderer.name,
+    'webUseWasm': webUseWasm,
     'vmserviceOutFile': vmserviceOutFile,
     'fastStart': fastStart,
     'nullAssertions': nullAssertions,
@@ -1356,6 +1363,7 @@
       webHeaders: (json['webHeaders']! as Map<dynamic, dynamic>).cast<String, String>(),
       webLaunchUrl: json['webLaunchUrl'] as String?,
       webRenderer: WebRendererMode.values.byName(json['webRenderer']! as String),
+      webUseWasm: json['webUseWasm']! as bool,
       vmserviceOutFile: json['vmserviceOutFile'] as String?,
       fastStart: json['fastStart']! as bool,
       nullAssertions: json['nullAssertions']! as bool,
diff --git a/packages/flutter_tools/lib/src/drive/web_driver_service.dart b/packages/flutter_tools/lib/src/drive/web_driver_service.dart
index fa10cfb..fd1e99c 100644
--- a/packages/flutter_tools/lib/src/drive/web_driver_service.dart
+++ b/packages/flutter_tools/lib/src/drive/web_driver_service.dart
@@ -79,6 +79,7 @@
           port: debuggingOptions.port,
           hostname: debuggingOptions.hostname,
           webRenderer: debuggingOptions.webRenderer,
+          webUseWasm: debuggingOptions.webUseWasm
         )
         : DebuggingOptions.enabled(
           buildInfo,
@@ -86,6 +87,7 @@
           hostname: debuggingOptions.hostname,
           disablePortPublication: debuggingOptions.disablePortPublication,
           webRenderer: debuggingOptions.webRenderer,
+          webUseWasm: debuggingOptions.webUseWasm,
         ),
       stayResident: true,
       flutterProject: FlutterProject.current(),
diff --git a/packages/flutter_tools/lib/src/isolated/devfs_web.dart b/packages/flutter_tools/lib/src/isolated/devfs_web.dart
index a4a2c9f..656c5f1 100644
--- a/packages/flutter_tools/lib/src/isolated/devfs_web.dart
+++ b/packages/flutter_tools/lib/src/isolated/devfs_web.dart
@@ -180,6 +180,7 @@
     Map<String, String> extraHeaders,
     NullSafetyMode nullSafetyMode, {
     required WebRendererMode webRenderer,
+    required bool isWasm,
     bool testMode = false,
     DwdsLauncher dwdsLauncher = Dwds.start,
     // TODO(markzipan): Make sure this default value aligns with that in the debugger options.
@@ -237,8 +238,8 @@
       return server;
     }
 
-    // In release builds deploy a simpler proxy server.
-    if (buildInfo.mode != BuildMode.debug) {
+    // In release builds (or wasm builds) deploy a simpler proxy server.
+    if (buildInfo.mode != BuildMode.debug || isWasm) {
       final ReleaseAssetServer releaseAssetServer = ReleaseAssetServer(
         entrypoint,
         fileSystem: globals.fs,
@@ -246,6 +247,7 @@
         flutterRoot: Cache.flutterRoot,
         webBuildDirectory: getWebBuildDirectory(),
         basePath: server.basePath,
+        needsCoopCoep: webRenderer == WebRendererMode.skwasm,
       );
       runZonedGuarded(() {
         shelf.serveRequests(httpServer!, releaseAssetServer.handle);
@@ -737,6 +739,7 @@
     required this.nullSafetyMode,
     required this.ddcModuleSystem,
     required this.webRenderer,
+    required this.isWasm,
     required this.rootDirectory,
     this.testMode = false,
   }) : _port = port;
@@ -763,6 +766,7 @@
   final String? tlsCertPath;
   final String? tlsCertKeyPath;
   final WebRendererMode webRenderer;
+  final bool isWasm;
 
   late WebAssetServer webAssetServer;
 
@@ -863,6 +867,7 @@
       extraHeaders,
       nullSafetyMode,
       webRenderer: webRenderer,
+      isWasm: isWasm,
       testMode: testMode,
       ddcModuleSystem: ddcModuleSystem,
     );
@@ -1108,11 +1113,13 @@
     required String? webBuildDirectory,
     required String? flutterRoot,
     required Platform platform,
+    required bool needsCoopCoep,
     this.basePath = '',
   })  : _fileSystem = fileSystem,
         _platform = platform,
         _flutterRoot = flutterRoot,
         _webBuildDirectory = webBuildDirectory,
+        _needsCoopCoep = needsCoopCoep,
         _fileSystemUtils =
             FileSystemUtils(fileSystem: fileSystem, platform: platform);
 
@@ -1122,6 +1129,7 @@
   final FileSystem _fileSystem;
   final FileSystemUtils _fileSystemUtils;
   final Platform _platform;
+  final bool _needsCoopCoep;
 
   /// The base path to serve from.
   ///
@@ -1174,14 +1182,23 @@
               'application/octet-stream';
       return shelf.Response.ok(bytes, headers: <String, String>{
         'Content-Type': mimeType,
+        if (_needsCoopCoep && file.basename == 'index.html') ...<String, String>{
+          'Cross-Origin-Opener-Policy': 'same-origin',
+          'Cross-Origin-Embedder-Policy': 'require-corp',
+        }
       });
     }
 
     final File file = _fileSystem
         .file(_fileSystem.path.join(_webBuildDirectory!, 'index.html'));
-    return shelf.Response.ok(file.readAsBytesSync(), headers: <String, String>{
-      'Content-Type': 'text/html',
-    });
+    return shelf.Response.ok(file.readAsBytesSync(),
+      headers: <String, String>{
+        'Content-Type': 'text/html',
+        if (_needsCoopCoep) ...<String, String>{
+          'Cross-Origin-Opener-Policy': 'same-origin',
+          'Cross-Origin-Embedder-Policy': 'require-corp',
+        },
+      });
   }
 }
 
diff --git a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart
index 6228520..a0de64f 100644
--- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart
+++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart
@@ -134,9 +134,9 @@
   // and platform initialization.
   Directory? _generatedEntrypointDirectory;
 
-  // Only the debug builds of the web support the service protocol.
+  // Only non-wasm debug builds of the web support the service protocol.
   @override
-  bool get supportsServiceProtocol => isRunningDebug && deviceIsDebuggable;
+  bool get supportsServiceProtocol => !debuggingOptions.webUseWasm && isRunningDebug && deviceIsDebuggable;
 
   @override
   bool get debuggingEnabled => isRunningDebug && deviceIsDebuggable;
@@ -311,13 +311,14 @@
           nativeNullAssertions: debuggingOptions.nativeNullAssertions,
           ddcModuleSystem: debuggingOptions.buildInfo.ddcModuleFormat == DdcModuleFormat.ddc,
           webRenderer: debuggingOptions.webRenderer,
+          isWasm: debuggingOptions.webUseWasm,
           rootDirectory: fileSystem.directory(projectRootPath),
         );
         Uri url = await device!.devFS!.create();
         if (debuggingOptions.tlsCertKeyPath != null && debuggingOptions.tlsCertPath != null) {
           url = url.replace(scheme: 'https');
         }
-        if (debuggingOptions.buildInfo.isDebug) {
+        if (debuggingOptions.buildInfo.isDebug && !debuggingOptions.webUseWasm) {
           await runSourceGenerators();
           final UpdateFSReport report = await _updateDevFS(fullRestart: true);
           if (!report.success) {
@@ -342,12 +343,7 @@
             target,
             debuggingOptions.buildInfo,
             ServiceWorkerStrategy.none,
-            compilerConfigs: <WebCompilerConfig>[
-              JsCompilerConfig.run(
-                nativeNullAssertions: debuggingOptions.nativeNullAssertions,
-                renderer: debuggingOptions.webRenderer,
-              )
-            ]
+            compilerConfigs: <WebCompilerConfig>[_compilerConfig],
           );
         }
         await device!.device!.startApp(
@@ -386,6 +382,17 @@
     }
   }
 
+  WebCompilerConfig get _compilerConfig => (debuggingOptions.webUseWasm)
+    ? WasmCompilerConfig(
+        optimizationLevel: 0,
+        stripWasm: false,
+        renderer: debuggingOptions.webRenderer
+      )
+    : JsCompilerConfig.run(
+        nativeNullAssertions: debuggingOptions.nativeNullAssertions,
+        renderer: debuggingOptions.webRenderer,
+      );
+
   @override
   Future<OperationResult> restart({
     bool fullRestart = false,
@@ -399,7 +406,7 @@
       progressId: 'hot.restart',
     );
 
-    if (debuggingOptions.buildInfo.isDebug) {
+    if (debuggingOptions.buildInfo.isDebug && !debuggingOptions.webUseWasm) {
       await runSourceGenerators();
       // Full restart is always false for web, since the extra recompile is wasteful.
       final UpdateFSReport report = await _updateDevFS();
@@ -426,12 +433,7 @@
           target,
           debuggingOptions.buildInfo,
           ServiceWorkerStrategy.none,
-          compilerConfigs: <WebCompilerConfig>[
-            JsCompilerConfig.run(
-              nativeNullAssertions: debuggingOptions.nativeNullAssertions,
-              renderer: debuggingOptions.webRenderer,
-            )
-          ],
+          compilerConfigs: <WebCompilerConfig>[_compilerConfig],
         );
       } on ToolExit {
         return OperationResult(1, 'Failed to recompile application.');
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart
index 87a2e51..addb06a 100644
--- a/packages/flutter_tools/lib/src/resident_runner.dart
+++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -1181,10 +1181,10 @@
   bool get debuggingEnabled => debuggingOptions.debuggingEnabled;
 
   @override
-  bool get isRunningDebug => debuggingOptions.buildInfo.isDebug;
+  bool get isRunningDebug => !debuggingOptions.webUseWasm && debuggingOptions.buildInfo.isDebug;
 
   @override
-  bool get isRunningProfile => debuggingOptions.buildInfo.isProfile;
+  bool get isRunningProfile => !debuggingOptions.webUseWasm && debuggingOptions.buildInfo.isProfile;
 
   @override
   bool get isRunningRelease => debuggingOptions.buildInfo.isRelease;
diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart
index 9b85adb..bfa5c1d 100644
--- a/packages/flutter_tools/lib/src/test/runner.dart
+++ b/packages/flutter_tools/lib/src/test/runner.dart
@@ -52,7 +52,6 @@
     String? icudtlPath,
     Directory? coverageDirectory,
     bool web = false,
-    bool useWasm = false,
     String? randomSeed,
     String? reporter,
     String? fileReporter,
@@ -118,7 +117,6 @@
     String? icudtlPath,
     Directory? coverageDirectory,
     bool web = false,
-    bool useWasm = false,
     String? randomSeed,
     String? reporter,
     String? fileReporter,
@@ -188,7 +186,7 @@
         testFiles: testFiles.map((Uri uri) => uri.toFilePath()).toList(),
         buildInfo: debuggingOptions.buildInfo,
         webRenderer: debuggingOptions.webRenderer,
-        useWasm: useWasm,
+        useWasm: debuggingOptions.webUseWasm,
       );
       testArgs
         ..add('--platform=chrome')
@@ -221,7 +219,7 @@
             ),
             testTimeRecorder: testTimeRecorder,
             webRenderer: debuggingOptions.webRenderer,
-            useWasm: useWasm,
+            useWasm: debuggingOptions.webUseWasm,
           );
         },
       );
diff --git a/packages/flutter_tools/lib/src/web/compile.dart b/packages/flutter_tools/lib/src/web/compile.dart
index 22302d0..66a99ad 100644
--- a/packages/flutter_tools/lib/src/web/compile.dart
+++ b/packages/flutter_tools/lib/src/web/compile.dart
@@ -184,6 +184,17 @@
   /// Always use skwasm.
   skwasm;
 
+  factory WebRendererMode.fromCliOption(String? webRendererString, {required bool useWasm}) {
+    final WebRendererMode mode = webRendererString != null
+      ? WebRendererMode.values.byName(webRendererString)
+      : WebRendererMode.auto;
+    if (mode == WebRendererMode.auto && useWasm) {
+      // Wasm defaults to skwasm
+      return WebRendererMode.skwasm;
+    }
+    return mode;
+  }
+
   @override
   String get cliName => snakeCase(name, '-');
 
diff --git a/packages/flutter_tools/lib/src/web/compiler_config.dart b/packages/flutter_tools/lib/src/web/compiler_config.dart
index 79206ad..352baa5 100644
--- a/packages/flutter_tools/lib/src/web/compiler_config.dart
+++ b/packages/flutter_tools/lib/src/web/compiler_config.dart
@@ -22,7 +22,7 @@
 
   /// The compiler optimization level.
   ///
-  /// Valid values are O1 (lowest, profile default) to O4 (highest, release default).
+  /// Valid values are O0 (lowest, debug default) to O4 (highest, release default).
   final int optimizationLevel;
 
   /// Returns which target this compiler outputs (js or wasm)
diff --git a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart
index d62cafd..4d74c30 100644
--- a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart
+++ b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart
@@ -29,6 +29,7 @@
 import 'package:flutter_tools/src/run_hot.dart';
 import 'package:flutter_tools/src/runner/flutter_command.dart';
 import 'package:flutter_tools/src/vmservice.dart';
+import 'package:flutter_tools/src/web/compile.dart';
 import 'package:test/fake.dart';
 import 'package:unified_analytics/unified_analytics.dart' as analytics;
 import 'package:vm_service/vm_service.dart';
@@ -986,6 +987,36 @@
         DeviceManager: () => testDeviceManager,
       });
 
+      testUsingContext('throws a ToolExit when using --wasm on a non-web platform', () async {
+        final RunCommand command = RunCommand();
+        await expectLater(
+          () => createTestCommandRunner(command).run(<String>[
+            'run',
+            '--no-pub',
+            '--wasm',
+          ]), throwsToolExit(message: '--wasm is only supported on the web platform'));
+      }, overrides: <Type, Generator>{
+        FileSystem: () => fileSystem,
+        ProcessManager: () => FakeProcessManager.any(),
+        Logger: () => logger,
+        DeviceManager: () => testDeviceManager,
+      });
+
+      testUsingContext('throws a ToolExit when using the skwasm renderer without --wasm', () async {
+        final RunCommand command = RunCommand();
+        await expectLater(
+          () => createTestCommandRunner(command).run(<String>[
+            'run',
+            '--no-pub',
+            '--web-renderer=skwasm',
+          ]), throwsToolExit(message: 'Skwasm renderer requires --wasm'));
+      }, overrides: <Type, Generator>{
+        FileSystem: () => fileSystem,
+        ProcessManager: () => FakeProcessManager.any(),
+        Logger: () => logger,
+        DeviceManager: () => testDeviceManager,
+      });
+
       testUsingContext('accepts headers with commas in them', () async {
         final RunCommand command = RunCommand();
         await expectLater(
@@ -1170,6 +1201,24 @@
     ProcessManager: () => FakeProcessManager.any(),
   });
 
+  testUsingContext('wasm mode selects skwasm renderer by default', () async {
+    final RunCommand command = RunCommand();
+    await expectLater(() => createTestCommandRunner(command).run(<String>[
+      'run',
+      '-d chrome',
+      '--wasm',
+    ]), throwsToolExit());
+
+    final DebuggingOptions options = await command.createDebuggingOptions(false);
+
+    expect(options.webUseWasm, true);
+    expect(options.webRenderer, WebRendererMode.skwasm);
+  }, overrides: <Type, Generator>{
+    Cache: () => Cache.test(processManager: FakeProcessManager.any()),
+    FileSystem: () => MemoryFileSystem.test(),
+    ProcessManager: () => FakeProcessManager.any(),
+  });
+
   testUsingContext('fails when "--web-launch-url" is not supported', () async {
     final RunCommand command = RunCommand();
     await expectLater(
diff --git a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart
index fa27e70..7ddef36 100644
--- a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart
+++ b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart
@@ -1348,6 +1348,24 @@
       FileSystem: () => fs,
       ProcessManager: () => FakeProcessManager.any(),
     });
+
+    testUsingContext('Web renderer defaults to Skwasm when using wasm', () async {
+      final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0);
+
+      final TestCommand testCommand = TestCommand(testRunner: testRunner);
+      final CommandRunner<void> commandRunner = createTestCommandRunner(testCommand);
+
+      await commandRunner.run(const <String>[
+        'test',
+        '--no-pub',
+        '--platform=chrome',
+        '--wasm',
+      ]);
+      expect(testRunner.lastDebuggingOptionsValue.webRenderer, WebRendererMode.skwasm);
+    }, overrides: <Type, Generator>{
+      FileSystem: () => fs,
+      ProcessManager: () => FakeProcessManager.any(),
+    });
   });
 }
 
diff --git a/packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart b/packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart
index bcb9e24..2b18e13 100644
--- a/packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart
+++ b/packages/flutter_tools/test/general.shard/web/devfs_web_ddc_modules_test.dart
@@ -137,6 +137,7 @@
             flutterRoot: null, // ignore: avoid_redundant_argument_values
             platform: FakePlatform(),
             webBuildDirectory: null, // ignore: avoid_redundant_argument_values
+            needsCoopCoep: false,
           );
         },
         overrides: <Type, Generator>{
@@ -927,6 +928,7 @@
               nullSafetyMode: NullSafetyMode.unsound,
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.html,
+              isWasm: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1063,6 +1065,7 @@
               nullSafetyMode: NullSafetyMode.sound,
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.html,
+              isWasm: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1199,6 +1202,7 @@
                 nullSafetyMode: NullSafetyMode.sound,
                 ddcModuleSystem: usesDdcModuleSystem,
                 webRenderer: WebRendererMode.canvaskit,
+                isWasm: false,
                 rootDirectory: globals.fs.currentDirectory,
               );
               webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1272,6 +1276,7 @@
               nullSafetyMode: NullSafetyMode.sound,
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.canvaskit,
+              isWasm: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1321,6 +1326,7 @@
               nullSafetyMode: NullSafetyMode.sound,
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.canvaskit,
+              isWasm: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1372,6 +1378,7 @@
               nullSafetyMode: NullSafetyMode.sound,
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.auto,
+              isWasm: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1425,6 +1432,7 @@
               nullSafetyMode: NullSafetyMode.unsound,
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.canvaskit,
+              isWasm: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
@@ -1463,6 +1471,7 @@
         const <String, String>{},
         NullSafetyMode.unsound,
         webRenderer: WebRendererMode.canvaskit,
+        isWasm: false,
         testMode: true);
 
     expect(webAssetServer.defaultResponseHeaders['x-frame-options'], null);
@@ -1496,6 +1505,7 @@
         },
         NullSafetyMode.unsound,
         webRenderer: WebRendererMode.canvaskit,
+        isWasm: false,
         testMode: true);
 
     expect(webAssetServer.defaultResponseHeaders[extraHeaderKey],
@@ -1596,6 +1606,7 @@
               nullSafetyMode: NullSafetyMode.unsound,
               ddcModuleSystem: usesDdcModuleSystem,
               webRenderer: WebRendererMode.canvaskit,
+              isWasm: false,
               rootDirectory: globals.fs.currentDirectory,
             );
             webDevFS.ddcModuleLoaderJS.createSync(recursive: true);
diff --git a/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart b/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart
index 7802b1d..c4074f5 100644
--- a/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart
+++ b/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart
@@ -76,6 +76,7 @@
         flutterRoot: null,
         platform: FakePlatform(),
         webBuildDirectory: null,
+        needsCoopCoep: false,
       );
     }, overrides: <Type, Generator>{
       Logger: () => logger,
@@ -715,6 +716,7 @@
       nullSafetyMode: NullSafetyMode.unsound,
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.html,
+      isWasm: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
@@ -827,6 +829,7 @@
       nullSafetyMode: NullSafetyMode.sound,
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.html,
+      isWasm: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
@@ -945,6 +948,7 @@
         nullSafetyMode: NullSafetyMode.sound,
         ddcModuleSystem: usesDdcModuleSystem,
         webRenderer: WebRendererMode.canvaskit,
+        isWasm: false,
         rootDirectory: globals.fs.currentDirectory,
       );
       webDevFS.requireJS.createSync(recursive: true);
@@ -1009,6 +1013,7 @@
       nullSafetyMode: NullSafetyMode.sound,
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.canvaskit,
+      isWasm: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
@@ -1057,6 +1062,7 @@
       nullSafetyMode: NullSafetyMode.sound,
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.canvaskit,
+      isWasm: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
@@ -1106,6 +1112,7 @@
       nullSafetyMode: NullSafetyMode.sound,
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.auto,
+      isWasm: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
@@ -1156,6 +1163,7 @@
       nullSafetyMode: NullSafetyMode.unsound,
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.canvaskit,
+      isWasm: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
@@ -1194,6 +1202,7 @@
       const <String, String>{},
       NullSafetyMode.unsound,
       webRenderer: WebRendererMode.canvaskit,
+      isWasm: false,
       testMode: true
     );
 
@@ -1228,6 +1237,7 @@
       },
       NullSafetyMode.unsound,
       webRenderer: WebRendererMode.canvaskit,
+      isWasm: false,
       testMode: true
     );
 
@@ -1310,6 +1320,7 @@
       nullSafetyMode: NullSafetyMode.unsound,
       ddcModuleSystem: usesDdcModuleSystem,
       webRenderer: WebRendererMode.canvaskit,
+      isWasm: false,
       rootDirectory: globals.fs.currentDirectory,
     );
     webDevFS.requireJS.createSync(recursive: true);
diff --git a/packages/flutter_tools/test/general.shard/web/web_asset_server_test.dart b/packages/flutter_tools/test/general.shard/web/web_asset_server_test.dart
index 858ed11..d0b8196 100644
--- a/packages/flutter_tools/test/general.shard/web/web_asset_server_test.dart
+++ b/packages/flutter_tools/test/general.shard/web/web_asset_server_test.dart
@@ -49,6 +49,7 @@
       platform: platform,
       flutterRoot: '/flutter',
       webBuildDirectory: 'build/web',
+      needsCoopCoep: false,
     );
     fileSystem.file('build/web/assets/foo.png')
       ..createSync(recursive: true)
@@ -68,6 +69,7 @@
       platform: platform,
       flutterRoot: '/flutter',
       webBuildDirectory: 'build/web',
+      needsCoopCoep: false,
     );
     fileSystem.file('build/web/assets/foo.js')
       ..createSync(recursive: true)
@@ -87,6 +89,7 @@
       platform: platform,
       flutterRoot: '/flutter',
       webBuildDirectory: 'build/web',
+      needsCoopCoep: false,
     );
     fileSystem.file('build/web/assets/foo.html')
       ..createSync(recursive: true)
@@ -106,6 +109,7 @@
       platform: platform,
       flutterRoot: '/flutter',
       webBuildDirectory: 'build/web',
+      needsCoopCoep: false,
     );
     fileSystem.file('flutter/bar.dart')
       ..createSync(recursive: true)
@@ -122,6 +126,7 @@
       platform: platform,
       flutterRoot: '/flutter',
       webBuildDirectory: 'build/web',
+      needsCoopCoep: false,
     );
     fileSystem.file('bar.dart')
       ..createSync(recursive: true)
@@ -131,4 +136,44 @@
 
     expect(response.statusCode, HttpStatus.ok);
   });
+
+  testWithoutContext('release asset server serves html content with COOP/COEP headers when specified', () async {
+    final ReleaseAssetServer assetServer = ReleaseAssetServer(Uri.base,
+      fileSystem: fileSystem,
+      platform: platform,
+      flutterRoot: '/flutter',
+      webBuildDirectory: 'build/web',
+      needsCoopCoep: true,
+    );
+    fileSystem.file('build/web/index.html')
+      ..createSync(recursive: true)
+      ..writeAsStringSync('<html></html>');
+    final Response response = await assetServer
+      .handle(Request('GET', Uri.parse('http://localhost:8080/index.html')));
+
+    expect(response.statusCode, HttpStatus.ok);
+    final Map<String, String> headers = response.headers;
+    expect(headers['Cross-Origin-Opener-Policy'], 'same-origin');
+    expect(headers['Cross-Origin-Embedder-Policy'], 'require-corp');
+  });
+
+  testWithoutContext('release asset server serves html content without COOP/COEP headers when specified', () async {
+    final ReleaseAssetServer assetServer = ReleaseAssetServer(Uri.base,
+      fileSystem: fileSystem,
+      platform: platform,
+      flutterRoot: '/flutter',
+      webBuildDirectory: 'build/web',
+      needsCoopCoep: false,
+    );
+    fileSystem.file('build/web/index.html')
+      ..createSync(recursive: true)
+      ..writeAsStringSync('<html></html>');
+    final Response response = await assetServer
+      .handle(Request('GET', Uri.parse('http://localhost:8080/index.html')));
+
+    expect(response.statusCode, HttpStatus.ok);
+    final Map<String, String> headers = response.headers;
+    expect(headers.containsKey('Cross-Origin-Opener-Policy'), false);
+    expect(headers.containsKey('Cross-Origin-Embedder-Policy'), false);
+  });
 }
diff --git a/packages/integration_test/example/web/flutter_bootstrap.js b/packages/integration_test/example/web/flutter_bootstrap.js
new file mode 100644
index 0000000..be78d93
--- /dev/null
+++ b/packages/integration_test/example/web/flutter_bootstrap.js
@@ -0,0 +1,12 @@
+// 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.
+
+{{flutter_js}}
+{{flutter_build_config}}
+_flutter.loader.load({
+  config: {
+    // Use the local CanvasKit bundle instead of the CDN to reduce test flakiness.
+    canvasKitBaseUrl: "/canvaskit/",
+  },
+});
diff --git a/packages/integration_test/example/web/index.html b/packages/integration_test/example/web/index.html
index fe77e24..c02e33b 100644
--- a/packages/integration_test/example/web/index.html
+++ b/packages/integration_test/example/web/index.html
@@ -21,16 +21,6 @@
   <link rel="manifest" href="/manifest.json">
 </head>
 <body>
-  <!-- This script installs service_worker.js to provide PWA functionality to
-       application. For more information, see:
-       https://developers.google.com/web/fundamentals/primers/service-workers -->
-  <script>
-    if ('serviceWorker' in navigator) {
-      window.addEventListener('load', function () {
-        navigator.serviceWorker.register('/flutter_service_worker.js');
-      });
-    }
-  </script>
-  <script src="main.dart.js" type="application/javascript"></script>
+  <script src="flutter_bootstrap.js" async></script>
 </body>
 </html>