@@ -225,17 +225,8 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
225225 ctx : & mut Ctx ,
226226 ) -> Result < Resolution , ResolveError > {
227227 ctx. with_fully_specified ( self . options . fully_specified ) ;
228- let specifier = Specifier :: parse ( specifier) . map_err ( ResolveError :: Specifier ) ?;
229- ctx. with_query_fragment ( specifier. query , specifier. fragment ) ;
230228 let cached_path = self . cache . value ( path) ;
231- let cached_path = self . require ( & cached_path, specifier. path ( ) , ctx) . or_else ( |err| {
232- if err. is_ignore ( ) {
233- return Err ( err) ;
234- }
235- // enhanced-resolve: try fallback
236- self . load_alias ( & cached_path, specifier. path ( ) , & self . options . fallback , ctx)
237- . and_then ( |value| value. ok_or ( err) )
238- } ) ?;
229+ let cached_path = self . require ( & cached_path, specifier, ctx) ?;
239230 let path = self . load_realpath ( & cached_path) ?;
240231 // enhanced-resolve: restrictions
241232 self . check_restrictions ( & path) ?;
@@ -266,11 +257,21 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
266257 ) -> Result < CachedPath , ResolveError > {
267258 ctx. test_for_infinite_recursion ( ) ?;
268259
269- // enhanced-resolve: try fragment as path
270- if let Some ( path) = self . try_fragment_as_path ( cached_path, specifier, ctx) {
260+ // enhanced-resolve: parse
261+ let ( parsed, try_fragment_as_path) = self . load_parse ( cached_path, specifier, ctx) ?;
262+ if let Some ( path) = try_fragment_as_path {
271263 return Ok ( path) ;
272264 }
273265
266+ self . require_without_parse ( cached_path, parsed. path ( ) , ctx)
267+ }
268+
269+ fn require_without_parse (
270+ & self ,
271+ cached_path : & CachedPath ,
272+ specifier : & str ,
273+ ctx : & mut Ctx ,
274+ ) -> Result < CachedPath , ResolveError > {
274275 // tsconfig-paths
275276 if let Some ( path) = self . load_tsconfig_paths ( cached_path, specifier, & mut Ctx :: default ( ) ) ? {
276277 return Ok ( path) ;
@@ -281,7 +282,7 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
281282 return Ok ( path) ;
282283 }
283284
284- match Path :: new ( specifier) . components ( ) . next ( ) {
285+ let result = match Path :: new ( specifier) . components ( ) . next ( ) {
285286 // 3. If X begins with './' or '/' or '../'
286287 Some ( Component :: RootDir | Component :: Prefix ( _) ) => {
287288 self . require_absolute ( cached_path, specifier, ctx)
@@ -305,7 +306,16 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
305306 // Set resolved the result of PACKAGE_RESOLVE(specifier, parentURL).
306307 self . require_bare ( cached_path, specifier, ctx)
307308 }
308- }
309+ } ;
310+
311+ result. or_else ( |err| {
312+ if err. is_ignore ( ) {
313+ return Err ( err) ;
314+ }
315+ // enhanced-resolve: try fallback
316+ self . load_alias ( cached_path, specifier, & self . options . fallback , ctx)
317+ . and_then ( |value| value. ok_or ( err) )
318+ } )
309319 }
310320
311321 // PACKAGE_RESOLVE(packageSpecifier, parentURL)
@@ -409,29 +419,34 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
409419 self . load_package_self_or_node_modules ( cached_path, specifier, ctx)
410420 }
411421
412- /// Try fragment as part of the path
422+ /// enhanced-resolve: ParsePlugin.
413423 ///
414424 /// It's allowed to escape # as \0# to avoid parsing it as fragment.
415425 /// enhanced-resolve will try to resolve requests containing `#` as path and as fragment,
416426 /// so it will automatically figure out if `./some#thing` means `.../some.js#thing` or `.../some#thing.js`.
417427 /// When a # is resolved as path it will be escaped in the result. Here: `.../some\0#thing.js`.
418428 ///
419429 /// <https://github.com/webpack/enhanced-resolve#escaping>
420- fn try_fragment_as_path (
430+ fn load_parse < ' s > (
421431 & self ,
422432 cached_path : & CachedPath ,
423- specifier : & str ,
433+ specifier : & ' s str ,
424434 ctx : & mut Ctx ,
425- ) -> Option < CachedPath > {
435+ ) -> Result < ( Specifier < ' s > , Option < CachedPath > ) , ResolveError > {
436+ let parsed = Specifier :: parse ( specifier) . map_err ( ResolveError :: Specifier ) ?;
437+ ctx. with_query_fragment ( parsed. query , parsed. fragment ) ;
438+
439+ // There is an edge-case where a request with # can be a path or a fragment -> try both
426440 if ctx. fragment . is_some ( ) && ctx. query . is_none ( ) {
441+ let specifier = parsed. path ( ) ;
427442 let fragment = ctx. fragment . take ( ) . unwrap ( ) ;
428443 let path = format ! ( "{specifier}{fragment}" ) ;
429- if let Ok ( path) = self . require ( cached_path, & path, ctx) {
430- return Some ( path) ;
444+ if let Ok ( path) = self . require_without_parse ( cached_path, & path, ctx) {
445+ return Ok ( ( parsed , Some ( path) ) ) ;
431446 }
432447 ctx. fragment . replace ( fragment) ;
433448 }
434- None
449+ Ok ( ( parsed , None ) )
435450 }
436451
437452 fn load_package_self_or_node_modules (
@@ -850,12 +865,10 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
850865 }
851866 return Err ( ResolveError :: Recursion ) ;
852867 }
853- let specifier = Specifier :: parse ( new_specifier) . map_err ( ResolveError :: Specifier ) ?;
854- ctx. with_query_fragment ( specifier. query , specifier. fragment ) ;
855- ctx. with_resolving_alias ( specifier. path ( ) . to_string ( ) ) ;
868+ ctx. with_resolving_alias ( new_specifier. to_string ( ) ) ;
856869 ctx. with_fully_specified ( false ) ;
857870 let cached_path = self . cache . value ( package_json. directory ( ) ) ;
858- self . require ( & cached_path, specifier . path ( ) , ctx) . map ( Some )
871+ self . require ( & cached_path, new_specifier , ctx) . map ( Some )
859872 }
860873
861874 /// enhanced-resolve: AliasPlugin for [ResolveOptions::alias] and [ResolveOptions::fallback].
@@ -886,23 +899,16 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
886899 for r in specifiers {
887900 match r {
888901 AliasValue :: Path ( alias_value) => {
889- let new_specifier =
890- Specifier :: parse ( alias_value) . map_err ( ResolveError :: Specifier ) ?;
891- // Resolve path without query and fragment
892- let old_query = ctx. query . clone ( ) ;
893- let old_fragment = ctx. fragment . clone ( ) ;
894- ctx. with_query_fragment ( new_specifier. query , new_specifier. fragment ) ;
895902 if let Some ( path) = self . load_alias_value (
896903 cached_path,
897904 alias_key,
898- new_specifier . path ( ) , // pass in parsed alias value
905+ alias_value ,
899906 specifier,
900907 ctx,
901908 & mut should_stop,
902909 ) ? {
903910 return Ok ( Some ( path) ) ;
904911 }
905- ctx. with_query_fragment ( old_query. as_deref ( ) , old_fragment. as_deref ( ) ) ;
906912 }
907913 AliasValue :: Ignore => {
908914 let path = cached_path. path ( ) . normalize_with ( alias_key) ;
@@ -1175,10 +1181,8 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
11751181 }
11761182 }
11771183 let subpath = format ! ( ".{subpath}" ) ;
1178- let specifier = Specifier :: parse ( & subpath) . map_err ( ResolveError :: Specifier ) ?;
11791184 ctx. with_fully_specified ( false ) ;
1180- ctx. with_query_fragment ( specifier. query , specifier. fragment ) ;
1181- return self . require ( & cached_path, specifier. path ( ) , ctx) . map ( Some ) ;
1185+ return self . require ( & cached_path, & subpath, ctx) . map ( Some ) ;
11821186 }
11831187 }
11841188 }
0 commit comments