Repository: vercel/next.js
Pull request: TURBOPACK: alias resolve lost query param

turbopack-resolve alias lost query as the following case:

```ts
import a from '@/a?query'

console.log(a);
```

alias config is:

```ts
resolveAlias: {
  '@/*': './app/*'
}
```

The query param will lost, i fix this and add some test case.

Changed files:
filename: test/e2e/app-dir/webpack-loader-resource-query/app/page.tsx
patch: @@ -1,5 +1,5 @@
 // @ts-expect-error -- ignore
-import { v } from './test.mdx?test=hi'
+import { v } from '@/test.mdx?test=hi'
 // @ts-expect-error -- ignore
 import reversed from './data.txt?reverse'
 // @ts-expect-error -- ignore

filename: test/e2e/app-dir/webpack-loader-resource-query/next.config.js
patch: @@ -1,3 +1,5 @@
+const path = require('path')
+
 /** @type {import('next').NextConfig} */
 const nextConfig = {
   turbopack: {
@@ -19,6 +21,9 @@ const nextConfig = {
         },
       ],
     },
+    resolveAlias: {
+      '@/*': './app/*',
+    },
   },
   webpack(config) {
     config.module.rules.push({
@@ -33,6 +38,10 @@ const nextConfig = {
       resourceQuery: /\?upper/,
       use: require.resolve('./upper-loader.js'),
     })
+    config.resolve.alias = {
+      ...config.resolve.alias,
+      '@': path.resolve(__dirname, 'app'),
+    }
     return config
   },
 }

filename: turbopack/crates/turbopack-core/src/resolve/mod.rs
patch: @@ -2969,21 +2969,27 @@ async fn resolve_import_map_result(
     Ok(match result {
         ImportMapResult::Result(result) => Some(ResolveResultOrCell::Cell(**result)),
         ImportMapResult::Alias(request, alias_lookup_path) => {
-            let request = **request;
-            let lookup_path = match alias_lookup_path {
-                Some(path) => path.clone(),
-                None => lookup_path,
+            let request_vc: Vc<Request> = **request;
+            // Only add query if the aliased request doesn't already have one
+            let request = if request_vc.query().await?.is_empty() && !query.is_empty() {
+                request_vc.with_query(query.clone())
+            } else {
+                request_vc
             };
-            // We must avoid cycles during resolving
-            if request == original_request && lookup_path == original_lookup_path {
+            let lookup_path = alias_lookup_path.clone().unwrap_or(lookup_path);
+
+            // Compare request patterns to avoid cycles (ignoring query differences)
+            let request_pattern = request.request_pattern();
+            let original_pattern = original_request.request_pattern();
+
+            if *request_pattern.await? == *original_pattern.await?
+                && lookup_path == original_lookup_path
+            {
                 None
             } else {
-                let result = resolve_internal(lookup_path, request, options);
                 Some(ResolveResultOrCell::Cell(
-                    result.with_replaced_request_key_pattern(
-                        request.request_pattern(),
-                        original_request.request_pattern(),
-                    ),
+                    resolve_internal(lookup_path, request, options)
+                        .with_replaced_request_key_pattern(request_pattern, original_pattern),
                 ))
             }
         }