Skip to content

Commit a0ee4ff

Browse files
authored
fix: srcset handling in html (#6419)
1 parent c85e51a commit a0ee4ff

File tree

7 files changed

+66
-29
lines changed

7 files changed

+66
-29
lines changed

packages/vite/src/node/server/middlewares/indexHtml.ts

+13-7
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ import {
2727
ensureWatchedFile,
2828
fsPathFromId,
2929
injectQuery,
30-
normalizePath
30+
normalizePath,
31+
processSrcSetSync
3132
} from '../../utils'
3233
import type { ModuleGraph } from '../moduleGraph'
3334

@@ -92,18 +93,23 @@ const processNodeUrl = (
9293
originalUrl !== '/' &&
9394
htmlPath === '/index.html'
9495
) {
95-
// #3230 if some request url (localhost:5173/a/b) return to fallback html, the relative assets
96+
const replacer = (url: string) =>
97+
path.posix.join(
98+
config.base,
99+
path.posix.relative(originalUrl, config.base),
100+
url.slice(1)
101+
)
102+
103+
// #3230 if some request url (localhost:3000/a/b) return to fallback html, the relative assets
96104
// path will add `/a/` prefix, it will caused 404.
97105
// rewrite before `./index.js` -> `localhost:5173/a/index.js`.
98106
// rewrite after `../index.js` -> `localhost:5173/index.js`.
99107
s.overwrite(
100108
node.value!.loc.start.offset,
101109
node.value!.loc.end.offset,
102-
`"${path.posix.join(
103-
path.posix.relative(originalUrl, '/'),
104-
url.slice(1)
105-
)}"`,
106-
{ contentOnly: true }
110+
node.name === 'srcset'
111+
? `"${processSrcSetSync(url, ({ url }) => replacer(url))}"`
112+
: `"${replacer(url)}"`
107113
)
108114
}
109115
}

packages/vite/src/node/utils.ts

+32-18
Original file line numberDiff line numberDiff line change
@@ -560,11 +560,16 @@ interface ImageCandidate {
560560
}
561561
const escapedSpaceCharacters = /( |\\t|\\n|\\f|\\r)+/g
562562
const imageSetUrlRE = /^(?:[\w\-]+\(.*?\)|'.*?'|".*?"|\S*)/
563-
export async function processSrcSet(
564-
srcs: string,
565-
replacer: (arg: ImageCandidate) => Promise<string>
566-
): Promise<string> {
567-
const imageCandidates: ImageCandidate[] = splitSrcSet(srcs)
563+
function reduceSrcset(ret: { url: string; descriptor: string }[]) {
564+
return ret.reduce((prev, { url, descriptor }, index) => {
565+
descriptor ??= ''
566+
return (prev +=
567+
url + ` ${descriptor}${index === ret.length - 1 ? '' : ', '}`)
568+
}, '')
569+
}
570+
571+
function splitSrcSetDescriptor(srcs: string): ImageCandidate[] {
572+
return splitSrcSet(srcs)
568573
.map((s) => {
569574
const src = s.replace(escapedSpaceCharacters, ' ').trim()
570575
const [url] = imageSetUrlRE.exec(src) || []
@@ -575,21 +580,30 @@ export async function processSrcSet(
575580
}
576581
})
577582
.filter(({ url }) => !!url)
583+
}
578584

579-
const ret = await Promise.all(
580-
imageCandidates.map(async ({ url, descriptor }) => {
581-
return {
582-
url: await replacer({ url, descriptor }),
583-
descriptor
584-
}
585-
})
586-
)
585+
export function processSrcSet(
586+
srcs: string,
587+
replacer: (arg: ImageCandidate) => Promise<string>
588+
): Promise<string> {
589+
return Promise.all(
590+
splitSrcSetDescriptor(srcs).map(async ({ url, descriptor }) => ({
591+
url: await replacer({ url, descriptor }),
592+
descriptor
593+
}))
594+
).then((ret) => reduceSrcset(ret))
595+
}
587596

588-
return ret.reduce((prev, { url, descriptor }, index) => {
589-
descriptor ??= ''
590-
return (prev +=
591-
url + ` ${descriptor}${index === ret.length - 1 ? '' : ', '}`)
592-
}, '')
597+
export function processSrcSetSync(
598+
srcs: string,
599+
replacer: (arg: ImageCandidate) => string
600+
): string {
601+
return reduceSrcset(
602+
splitSrcSetDescriptor(srcs).map(({ url, descriptor }) => ({
603+
url: replacer({ url, descriptor }),
604+
descriptor
605+
}))
606+
)
593607
}
594608

595609
function splitSrcSet(srcs: string) {

playground/assets/__tests__/assets.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ describe('image', () => {
192192
expect(s).toMatch(
193193
isBuild
194194
? /\/foo\/assets\/asset\.\w{8}\.png \d{1}x/
195-
: /\.\/nested\/asset\.png \d{1}x/
195+
: /\/foo\/nested\/asset\.png \d{1}x/
196196
)
197197
})
198198
})

playground/env/__tests__/env.spec.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { isBuild, page } from '~utils'
33
const mode = isBuild ? `production` : `development`
44

55
test('base', async () => {
6-
expect(await page.textContent('.base')).toBe('/')
6+
expect(await page.textContent('.base')).toBe('/env/')
77
})
88

99
test('mode', async () => {
@@ -46,9 +46,15 @@ test('env object', async () => {
4646
VITE_EFFECTIVE_MODE_FILE_NAME: `.env.${mode}`,
4747
CUSTOM_PREFIX_ENV_VARIABLE: '1',
4848
VITE_CUSTOM_ENV_VARIABLE: '1',
49-
BASE_URL: '/',
49+
BASE_URL: '/env/',
5050
MODE: mode,
5151
DEV: !isBuild,
5252
PROD: isBuild
5353
})
5454
})
55+
56+
if (!isBuild) {
57+
test('relative url import script return import.meta.url', async () => {
58+
expect(await page.textContent('.url')).toMatch('/env/index.js')
59+
})
60+
}

playground/env/index.html

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ <h1>Environment Variables</h1>
1414
<p>import.meta.env.VITE_INLINE: <code class="inline"></code></p>
1515
<p>process.env.NODE_ENV: <code class="node-env"></code></p>
1616
<p>import.meta.env: <span class="pre env-object"></span></p>
17+
<p>import.meta.url: <span class="pre url"></span></p>
1718

1819
<script type="module">
1920
text('.base', import.meta.env.BASE_URL)
@@ -31,6 +32,7 @@ <h1>Environment Variables</h1>
3132
document.querySelector(el).textContent = text
3233
}
3334
</script>
35+
<script type="module" src="./index.js"></script>
3436

3537
<style>
3638
.pre {

playground/env/index.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
text('.url', import.meta.url)
2+
3+
function text(el, text) {
4+
document.querySelector(el).textContent = text
5+
}

playground/env/vite.config.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
const { defineConfig } = require('vite')
22

33
module.exports = defineConfig({
4-
envPrefix: ['VITE_', 'CUSTOM_PREFIX_']
4+
base: '/env/',
5+
envPrefix: ['VITE_', 'CUSTOM_PREFIX_'],
6+
build: {
7+
outDir: 'dist/env'
8+
}
59
})

0 commit comments

Comments
 (0)