[dart2wasm] Legacy URL format is correctly mapped to new format when `compiler` query parameter is present (#9617)

diff --git a/packages/devtools_app/lib/src/shared/primitives/url_utils.dart b/packages/devtools_app/lib/src/shared/primitives/url_utils.dart
index 632f487..933706b 100644
--- a/packages/devtools_app/lib/src/shared/primitives/url_utils.dart
+++ b/packages/devtools_app/lib/src/shared/primitives/url_utils.dart
@@ -14,6 +14,9 @@
       : uri.path.substring(1);
 }
 
+const _jsCompilerParam = '?compiler=js';
+const _wasmCompilerParam = '?compiler=wasm';
+
 /// Maps DevTools URLs in the original fragment format onto the equivalent URLs
 /// in the new URL format.
 ///
@@ -25,9 +28,16 @@
   //   http://localhost:123/#/?page=inspector&uri=ws://...
   final isRootRequest = uri.path == '/' || uri.path.endsWith('/devtools/');
   if (isRootRequest && uri.fragment.isNotEmpty) {
+    // Note: If there is a ?compiler= query parameter, we remove it from before
+    // the hash then add it back in as a query parameter at the end.
+    // See https://github.com/flutter/devtools/issues/9612 for details.
+    final hasJsParam = url.contains(_jsCompilerParam);
+    final hasWasmParam = url.contains(_wasmCompilerParam) && !hasJsParam;
     final basePath = uri.path;
     // Convert the URL by removing the fragment separator.
     final newUrl = url
+        .replaceAll(_jsCompilerParam, '')
+        .replaceAll(_wasmCompilerParam, '')
         // Handle localhost:123/#/inspector?uri=xxx
         .replaceFirst('/#/', '/')
         // Handle localhost:123/#?page=inspector&uri=xxx
@@ -35,6 +45,12 @@
 
     // Move page names from the querystring into the path.
     var newUri = Uri.parse(newUrl);
+    final queryParams = {
+      ...newUri.queryParameters,
+      if (hasJsParam) 'compiler': 'js',
+      if (hasWasmParam) 'compiler': 'wasm',
+    };
+    newUri = newUri.replace(queryParameters: queryParams);
     final page = newUri.queryParameters['page'];
     if (newUri.path == basePath && page != null) {
       final newParams = {...newUri.queryParameters}..remove('page');
diff --git a/packages/devtools_app/test/shared/primitives/url_utils_test.dart b/packages/devtools_app/test/shared/primitives/url_utils_test.dart
index ba1ee16..16494d1 100644
--- a/packages/devtools_app/test/shared/primitives/url_utils_test.dart
+++ b/packages/devtools_app/test/shared/primitives/url_utils_test.dart
@@ -65,6 +65,49 @@
           test('maps legacy URIs with no page names', () {
             expect(mapLegacyUrl('$prefix/#/?foo=bar'), '$prefix/?foo=bar');
           });
+
+          group(
+            'with "compiler" query param (https://github.com/flutter/devtools/issues/9612)',
+            () {
+              for (final compilerValue in ['js', 'wasm']) {
+                test(
+                  'moves ?compiler=$compilerValue from before hash to after path',
+                  () {
+                    final newUrl = '$prefix/inspector?compiler=$compilerValue';
+                    expect(
+                      mapLegacyUrl(
+                        '$prefix/?compiler=$compilerValue#/inspector',
+                      ),
+                      newUrl,
+                    );
+                    expect(
+                      mapLegacyUrl(
+                        '$prefix/?compiler=$compilerValue#/?page=inspector',
+                      ),
+                      newUrl,
+                    );
+                  },
+                );
+
+                test('handles additional query parameters', () {
+                  final newUrl =
+                      '$prefix/inspector?foo=bar&compiler=$compilerValue';
+                  expect(
+                    mapLegacyUrl(
+                      '$prefix/?compiler=$compilerValue#/inspector?foo=bar',
+                    ),
+                    newUrl,
+                  );
+                  expect(
+                    mapLegacyUrl(
+                      '$prefix/?compiler=$compilerValue#/?page=inspector&foo=bar',
+                    ),
+                    newUrl,
+                  );
+                });
+              }
+            },
+          );
         });
       }
     });
diff --git a/packages/devtools_app/web/flutter_bootstrap.js b/packages/devtools_app/web/flutter_bootstrap.js
index dc563c3..ee6a54d 100644
--- a/packages/devtools_app/web/flutter_bootstrap.js
+++ b/packages/devtools_app/web/flutter_bootstrap.js
@@ -84,6 +84,10 @@
 
 // Sets or removes the 'wasm' query parameter based on whether DevTools should
 // be loaded with the skwasm renderer.
+//
+// Note: In the case of the legacy-formatted URL, this adds the query parameter
+// in the wrong place. We fix this in the Dart mapLegacyUrl function. Details:
+// https://github.com/flutter/devtools/issues/9612
 function updateWasmQueryParameter(useSkwasm) {
   const url = new URL(window.location.href);
   if (useSkwasm) {