11import fs from 'fs'
22import path from 'path'
33import MagicString from 'magic-string'
4+ import type { SourceMapInput } from 'rollup'
45import type { AttributeNode , ElementNode , TextNode } from '@vue/compiler-dom'
56import { NodeTypes } from '@vue/compiler-dom'
67import type { Connect } from 'types/connect'
@@ -15,7 +16,12 @@ import {
1516} from '../../plugins/html'
1617import type { ResolvedConfig , ViteDevServer } from '../..'
1718import { send } from '../send'
18- import { CLIENT_PUBLIC_PATH , FS_PREFIX } from '../../constants'
19+ import {
20+ CLIENT_PUBLIC_PATH ,
21+ FS_PREFIX ,
22+ VALID_ID_PREFIX ,
23+ NULL_BYTE_PLACEHOLDER
24+ } from '../../constants'
1925import {
2026 cleanUrl ,
2127 fsPathFromId ,
@@ -108,32 +114,53 @@ const devHtmlHook: IndexHtmlTransformHook = async (
108114 const { config, moduleGraph, watcher } = server !
109115 const base = config . base || '/'
110116
117+ let proxyModulePath : string
118+ let proxyModuleUrl : string
119+
120+ const trailingSlash = htmlPath . endsWith ( '/' )
121+ if ( ! trailingSlash && fs . existsSync ( filename ) ) {
122+ proxyModulePath = htmlPath
123+ proxyModuleUrl = base + htmlPath . slice ( 1 )
124+ } else {
125+ // There are users of vite.transformIndexHtml calling it with url '/'
126+ // for SSR integrations #7993, filename is root for this case
127+ // A user may also use a valid name for a virtual html file
128+ // Mark the path as virtual in both cases so sourcemaps aren't processed
129+ // and ids are properly handled
130+ const validPath = `${ htmlPath } ${ trailingSlash ? 'index.html' : '' } `
131+ proxyModulePath = `\0${ validPath } `
132+ proxyModuleUrl = `${ VALID_ID_PREFIX } ${ NULL_BYTE_PLACEHOLDER } ${ validPath } `
133+ }
134+
111135 const s = new MagicString ( html )
112136 let inlineModuleIndex = - 1
113- const filePath = cleanUrl ( htmlPath )
137+ const proxyCacheUrl = cleanUrl ( proxyModulePath ) . replace (
138+ normalizePath ( config . root ) ,
139+ ''
140+ )
114141 const styleUrl : AssetNode [ ] = [ ]
115142
116143 const addInlineModule = ( node : ElementNode , ext : 'js' ) => {
117144 inlineModuleIndex ++
118145
119- const url = filePath . replace ( normalizePath ( config . root ) , '' )
120-
121146 const contentNode = node . children [ 0 ] as TextNode
122147
123148 const code = contentNode . content
124- const map = new MagicString ( html )
125- . snip ( contentNode . loc . start . offset , contentNode . loc . end . offset )
126- . generateMap ( { hires : true } )
127- map . sources = [ filename ]
128- map . file = filename
149+
150+ let map : SourceMapInput | undefined
151+ if ( ! proxyModulePath . startsWith ( '\0' ) ) {
152+ map = new MagicString ( html )
153+ . snip ( contentNode . loc . start . offset , contentNode . loc . end . offset )
154+ . generateMap ( { hires : true } )
155+ map . sources = [ filename ]
156+ map . file = filename
157+ }
129158
130159 // add HTML Proxy to Map
131- addToHTMLProxyCache ( config , url , inlineModuleIndex , { code, map } )
160+ addToHTMLProxyCache ( config , proxyCacheUrl , inlineModuleIndex , { code, map } )
132161
133162 // inline js module. convert to src="proxy"
134- const modulePath = `${
135- config . base + htmlPath . slice ( 1 )
136- } ?html-proxy&index=${ inlineModuleIndex } .${ ext } `
163+ const modulePath = `${ proxyModuleUrl } ?html-proxy&index=${ inlineModuleIndex } .${ ext } `
137164
138165 // invalidate the module so the newly cached contents will be served
139166 const module = server ?. moduleGraph . getModuleById ( modulePath )
@@ -190,13 +217,13 @@ const devHtmlHook: IndexHtmlTransformHook = async (
190217
191218 await Promise . all (
192219 styleUrl . map ( async ( { start, end, code } , index ) => {
193- const url = filename + ` ?html-proxy&${ index } .css`
220+ const url = ` ${ proxyModulePath } ?html-proxy&index= ${ index } .css`
194221
195222 // ensure module in graph after successful load
196223 const mod = await moduleGraph . ensureEntryFromUrl ( url , false )
197224 ensureWatchedFile ( watcher , mod . file , config . root )
198225
199- const result = await server ! . pluginContainer . transform ( code , url )
226+ const result = await server ! . pluginContainer . transform ( code , mod . id ! )
200227 s . overwrite ( start , end , result ?. code || '' )
201228 } )
202229 )
0 commit comments