1
1
import fs from 'fs'
2
2
import path from 'path'
3
3
import MagicString from 'magic-string'
4
- import { NodeTypes } from '@vue/compiler-dom'
4
+ import { AttributeNode , NodeTypes } from '@vue/compiler-dom'
5
5
import { Connect } from 'types/connect'
6
6
import {
7
7
applyHtmlTransforms ,
@@ -10,25 +10,24 @@ import {
10
10
resolveHtmlTransforms ,
11
11
traverseHtml
12
12
} from '../../plugins/html'
13
- import { ViteDevServer } from '../..'
13
+ import { ResolvedConfig , ViteDevServer } from '../..'
14
14
import { send } from '../send'
15
15
import { CLIENT_PUBLIC_PATH , FS_PREFIX } from '../../constants'
16
16
import { cleanUrl , fsPathFromId } from '../../utils'
17
17
import { assetAttrsConfig } from '../../plugins/html'
18
18
19
19
export function createDevHtmlTransformFn (
20
20
server : ViteDevServer
21
- ) : ( url : string , html : string ) => Promise < string > {
21
+ ) : ( url : string , html : string , originalUrl : string ) => Promise < string > {
22
22
const [ preHooks , postHooks ] = resolveHtmlTransforms ( server . config . plugins )
23
23
24
- return ( url : string , html : string ) : Promise < string > => {
25
- return applyHtmlTransforms (
26
- html ,
27
- url ,
28
- getHtmlFilename ( url , server ) ,
29
- [ ...preHooks , devHtmlHook , ...postHooks ] ,
30
- server
31
- )
24
+ return ( url : string , html : string , originalUrl : string ) : Promise < string > => {
25
+ return applyHtmlTransforms ( html , [ ...preHooks , devHtmlHook , ...postHooks ] , {
26
+ path : url ,
27
+ filename : getHtmlFilename ( url , server ) ,
28
+ server,
29
+ originalUrl
30
+ } )
32
31
}
33
32
}
34
33
@@ -41,9 +40,44 @@ function getHtmlFilename(url: string, server: ViteDevServer) {
41
40
}
42
41
43
42
const startsWithSingleSlashRE = / ^ \/ (? ! \/ ) /
43
+ const processNodeUrl = (
44
+ node : AttributeNode ,
45
+ s : MagicString ,
46
+ config : ResolvedConfig ,
47
+ htmlPath : string ,
48
+ originalUrl ?: string
49
+ ) => {
50
+ const url = node . value ?. content || ''
51
+ if ( startsWithSingleSlashRE . test ( url ) ) {
52
+ // prefix with base
53
+ s . overwrite (
54
+ node . value ! . loc . start . offset ,
55
+ node . value ! . loc . end . offset ,
56
+ `"${ config . base + url . slice ( 1 ) } "`
57
+ )
58
+ } else if (
59
+ url . startsWith ( '.' ) &&
60
+ originalUrl &&
61
+ originalUrl !== '/' &&
62
+ htmlPath === '/index.html'
63
+ ) {
64
+ // #3230 if some request url (localhost:3000/a/b) return to fallback html, the relative assets
65
+ // path will add `/a/` prefix, it will caused 404.
66
+ // rewrite before `./index.js` -> `localhost:3000/a/index.js`.
67
+ // rewrite after `../index.js` -> `localhost:3000/index.js`.
68
+ s . overwrite (
69
+ node . value ! . loc . start . offset ,
70
+ node . value ! . loc . end . offset ,
71
+ `"${ path . posix . join (
72
+ path . posix . relative ( originalUrl , '/' ) ,
73
+ url . slice ( 1 )
74
+ ) } "`
75
+ )
76
+ }
77
+ }
44
78
const devHtmlHook : IndexHtmlTransformHook = async (
45
79
html ,
46
- { path : htmlPath , server }
80
+ { path : htmlPath , server, originalUrl }
47
81
) => {
48
82
// TODO: solve this design issue
49
83
// Optional chain expressions can return undefined by design
@@ -67,15 +101,7 @@ const devHtmlHook: IndexHtmlTransformHook = async (
67
101
}
68
102
69
103
if ( src ) {
70
- const url = src . value ?. content || ''
71
- if ( startsWithSingleSlashRE . test ( url ) ) {
72
- // prefix with base
73
- s . overwrite (
74
- src . value ! . loc . start . offset ,
75
- src . value ! . loc . end . offset ,
76
- `"${ config . base + url . slice ( 1 ) } "`
77
- )
78
- }
104
+ processNodeUrl ( src , s , config , htmlPath , originalUrl )
79
105
} else if ( isModule ) {
80
106
// inline js module. convert to src="proxy"
81
107
s . overwrite (
@@ -97,14 +123,7 @@ const devHtmlHook: IndexHtmlTransformHook = async (
97
123
p . value &&
98
124
assetAttrs . includes ( p . name )
99
125
) {
100
- const url = p . value . content || ''
101
- if ( startsWithSingleSlashRE . test ( url ) ) {
102
- s . overwrite (
103
- p . value . loc . start . offset ,
104
- p . value . loc . end . offset ,
105
- `"${ config . base + url . slice ( 1 ) } "`
106
- )
107
- }
126
+ processNodeUrl ( p , s , config , htmlPath , originalUrl )
108
127
}
109
128
}
110
129
}
@@ -139,7 +158,7 @@ export function indexHtmlMiddleware(
139
158
if ( fs . existsSync ( filename ) ) {
140
159
try {
141
160
let html = fs . readFileSync ( filename , 'utf-8' )
142
- html = await server . transformIndexHtml ( url , html )
161
+ html = await server . transformIndexHtml ( url , html , req . originalUrl )
143
162
return send ( req , res , html , 'html' )
144
163
} catch ( e ) {
145
164
return next ( e )
0 commit comments