1
1
import fs from 'fs'
2
2
import path from 'path'
3
3
import MagicString from 'magic-string'
4
+ import type { SourceMapInput } from 'rollup'
4
5
import type { AttributeNode , ElementNode , TextNode } from '@vue/compiler-dom'
5
6
import { NodeTypes } from '@vue/compiler-dom'
6
7
import type { Connect } from 'types/connect'
@@ -15,7 +16,12 @@ import {
15
16
} from '../../plugins/html'
16
17
import type { ResolvedConfig , ViteDevServer } from '../..'
17
18
import { 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'
19
25
import {
20
26
cleanUrl ,
21
27
fsPathFromId ,
@@ -108,32 +114,53 @@ const devHtmlHook: IndexHtmlTransformHook = async (
108
114
const { config, moduleGraph, watcher } = server !
109
115
const base = config . base || '/'
110
116
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
+
111
135
const s = new MagicString ( html )
112
136
let inlineModuleIndex = - 1
113
- const filePath = cleanUrl ( htmlPath )
137
+ const proxyCacheUrl = cleanUrl ( proxyModulePath ) . replace (
138
+ normalizePath ( config . root ) ,
139
+ ''
140
+ )
114
141
const styleUrl : AssetNode [ ] = [ ]
115
142
116
143
const addInlineModule = ( node : ElementNode , ext : 'js' ) => {
117
144
inlineModuleIndex ++
118
145
119
- const url = filePath . replace ( normalizePath ( config . root ) , '' )
120
-
121
146
const contentNode = node . children [ 0 ] as TextNode
122
147
123
148
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
+ }
129
158
130
159
// add HTML Proxy to Map
131
- addToHTMLProxyCache ( config , url , inlineModuleIndex , { code, map } )
160
+ addToHTMLProxyCache ( config , proxyCacheUrl , inlineModuleIndex , { code, map } )
132
161
133
162
// 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 } `
137
164
138
165
// invalidate the module so the newly cached contents will be served
139
166
const module = server ?. moduleGraph . getModuleById ( modulePath )
@@ -190,13 +217,13 @@ const devHtmlHook: IndexHtmlTransformHook = async (
190
217
191
218
await Promise . all (
192
219
styleUrl . map ( async ( { start, end, code } , index ) => {
193
- const url = filename + ` ?html-proxy&${ index } .css`
220
+ const url = ` ${ proxyModulePath } ?html-proxy&index= ${ index } .css`
194
221
195
222
// ensure module in graph after successful load
196
223
const mod = await moduleGraph . ensureEntryFromUrl ( url , false )
197
224
ensureWatchedFile ( watcher , mod . file , config . root )
198
225
199
- const result = await server ! . pluginContainer . transform ( code , url )
226
+ const result = await server ! . pluginContainer . transform ( code , mod . id ! )
200
227
s . overwrite ( start , end , result ?. code || '' )
201
228
} )
202
229
)
0 commit comments