Repository: vercel/next.js
Pull request: Turbopack: support more dynamic request with import map

Add support to resolve arbitrarily dynamic requests into a `'@/*": "./@"` import mapping, such as

```js
import(`@/styles/themes/theme-${themeName}/theme-${themeName}`)
```

Closes [#83785](https://github.com/vercel/next.js/issues/83785)
Closes PACK-5451

This was basically a regression from #82757

Changed files:
filename: turbopack/crates/turbopack-core/src/resolve/alias_map.rs
patch: @@ -562,6 +562,10 @@ where
                         }
                     }
                     AliasKey::Wildcard { suffix } => {
+                        // This is quite messy as we'd have to match against the FS to do this
+                        // properly. For now, try to support as many cases as possible (and as are
+                        // actually used).
+
                         let is_match = if let Some(request) = self.request.as_constant_string() {
                             // The request is a constant string, so the PatriciaMap lookup already
                             // ensured that the prefix is matching the request.
@@ -587,9 +591,16 @@ where
                             ] = req.as_slice()
                         {
                             req_prefix.starts_with(&**prefix) && req_suffix.ends_with(&**suffix)
+                        } else if !self.request.could_match(prefix) {
+                            // There's no way it could match if the prefix can't match.
+                            false
+                        } else if suffix.is_empty() {
+                            // Prefix matches the request, and suffix is empty.
+                            true
                         } else {
+                            // It may or may not match, throw an error.
                             return Some(Err(anyhow::anyhow!(
-                                "complex patterns into wildcard exports fields are not \
+                                "Complex patterns into wildcard exports fields are not \
                                  implemented yet: {} into '{}*{}'",
                                 self.request.describe_as_string(),
                                 prefix,

filename: turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-paths-dynamic/input/index.js
patch: @@ -1,4 +1,4 @@
-import { loadSub, /* loadSubNested, */ loadSubFallback } from './src/foo'
+import { loadSub, loadSubNested, loadSubFallback } from './src/foo'
 
 it('should support dynamic requests with tsconfig.paths', () => {
   expect(loadSub('file2.js').default).toBe('file2')
@@ -8,9 +8,9 @@ it('should support dynamic requests with tsconfig.paths and without extension',
   expect(loadSub('file2').default).toBe('file2')
 })
 
-// it('should support dynamic requests with tsconfig.paths and multiple dynamic parts', () => {
-//   expect(loadSubNested('file2').default).toBe('file2')
-// })
+it('should support dynamic requests with tsconfig.paths and multiple dynamic parts', () => {
+  expect(loadSubNested('file2').default).toBe('file2')
+})
 
 it('should support dynamic requests with tsconfig.paths fallbacks', () => {
   expect(loadSubFallback('file1').default).toBe('file1')

filename: turbopack/crates/turbopack-tests/tests/execution/turbopack/resolving/tsconfig-paths-dynamic/input/src/foo.ts
patch: @@ -2,10 +2,9 @@ export function loadSub(v: string) {
   return require(`@/sub/${v}`)
 }
 
-// TODO not supported
-// export function loadSubNested(v: string) {
-//   return require(`@/sub-nested/${v}/${v}.js`)
-// }
+export function loadSubNested(v: string) {
+  return require(`@/sub-nested/${v}/${v}.js`)
+}
 
 export function loadSubFallback(v: string) {
   return require(`@sub/${v}`)