@@ -52,7 +52,8 @@ type CacheEntry
5252 result?: TransformResult
5353 promise?: Promise<void>
5454
55- postfixRE := /[?#].*$/s
55+ queryPostfixRE := /\?.*$/s
56+ escapedHashRE := /\0#/g
5657isWindows := os.platform() is 'win32'
5758windowsSlashRE := /\\/g
5859civetSuffix := '.civet'
@@ -67,19 +68,33 @@ or needs an implicit .civet extension, or isn't Civet-related at all.
6768*/
6869function extractCivetFilename(id: string, outputExtension: string): {filename: string, postfix: string}
6970 postfix .= ''
70- filename .= id.replace postfixRE, (match) =>
71+ // Webpack escapes literal `#` in `loaderContext.resource` as `\0#` so it
72+ // can distinguish path characters from fragment suffixes. Undo that first.
73+ id = id.replace escapedHashRE, '#'
74+ // `?` is always treated as a suffix. Raw `?` is impossible in Windows paths,
75+ // and we rely on query suffixes across bundlers.
76+ filename .= id.replace queryPostfixRE, (match) =>
7177 postfix = match
7278 ''
7379 // Normally the outputExtension (.jsx/.tsx by default) should be present,
7480 // but sometimes (e.g. esbuild's alias feature) load directly without resolve
7581 if filename.endsWith outputExtension
7682 filename = filename[< -outputExtension#]
83+ // `#` may be either a literal path character or a fragment-like suffix.
84+ // Keep it when the file exists as written; otherwise strip one rightmost
85+ // `#...` suffix and let later resolution check whether file exists.
86+ hashIndex := filename.lastIndexOf '#'
87+ if hashIndex >= 0 and not tryStatSync filename
88+ postfix = filename[hashIndex..] + postfix
89+ filename = filename[..<hashIndex]
90+ if filename.endsWith outputExtension
91+ filename = filename[< -outputExtension#]
7792 {filename, postfix}
7893
7994function tryStatSync(file: string): fs.Stats?
8095 try
8196 // The "throwIfNoEntry" is a performance optimization for cases where the file does not exist
82- return fs.statSync( file, { throwIfNoEntry: false });
97+ return fs.statSync file, throwIfNoEntry: false
8398
8499export function slash(p: string): string
85100 p.replace windowsSlashRE, '/'
0 commit comments