fix: srcset handling in html (#6419)

This commit is contained in:
yoho 2022-05-20 03:09:33 +08:00 committed by GitHub
parent c85e51aaea
commit a0ee4ffeab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 66 additions and 29 deletions

View File

@ -27,7 +27,8 @@ import {
ensureWatchedFile,
fsPathFromId,
injectQuery,
normalizePath
normalizePath,
processSrcSetSync
} from '../../utils'
import type { ModuleGraph } from '../moduleGraph'
@ -92,18 +93,23 @@ const processNodeUrl = (
originalUrl !== '/' &&
htmlPath === '/index.html'
) {
// #3230 if some request url (localhost:5173/a/b) return to fallback html, the relative assets
const replacer = (url: string) =>
path.posix.join(
config.base,
path.posix.relative(originalUrl, config.base),
url.slice(1)
)
// #3230 if some request url (localhost:3000/a/b) return to fallback html, the relative assets
// path will add `/a/` prefix, it will caused 404.
// rewrite before `./index.js` -> `localhost:5173/a/index.js`.
// rewrite after `../index.js` -> `localhost:5173/index.js`.
s.overwrite(
node.value!.loc.start.offset,
node.value!.loc.end.offset,
`"${path.posix.join(
path.posix.relative(originalUrl, '/'),
url.slice(1)
)}"`,
{ contentOnly: true }
node.name === 'srcset'
? `"${processSrcSetSync(url, ({ url }) => replacer(url))}"`
: `"${replacer(url)}"`
)
}
}

View File

@ -560,11 +560,16 @@ interface ImageCandidate {
}
const escapedSpaceCharacters = /( |\\t|\\n|\\f|\\r)+/g
const imageSetUrlRE = /^(?:[\w\-]+\(.*?\)|'.*?'|".*?"|\S*)/
export async function processSrcSet(
srcs: string,
replacer: (arg: ImageCandidate) => Promise<string>
): Promise<string> {
const imageCandidates: ImageCandidate[] = splitSrcSet(srcs)
function reduceSrcset(ret: { url: string; descriptor: string }[]) {
return ret.reduce((prev, { url, descriptor }, index) => {
descriptor ??= ''
return (prev +=
url + ` ${descriptor}${index === ret.length - 1 ? '' : ', '}`)
}, '')
}
function splitSrcSetDescriptor(srcs: string): ImageCandidate[] {
return splitSrcSet(srcs)
.map((s) => {
const src = s.replace(escapedSpaceCharacters, ' ').trim()
const [url] = imageSetUrlRE.exec(src) || []
@ -575,21 +580,30 @@ export async function processSrcSet(
}
})
.filter(({ url }) => !!url)
}
const ret = await Promise.all(
imageCandidates.map(async ({ url, descriptor }) => {
return {
url: await replacer({ url, descriptor }),
descriptor
}
})
export function processSrcSet(
srcs: string,
replacer: (arg: ImageCandidate) => Promise<string>
): Promise<string> {
return Promise.all(
splitSrcSetDescriptor(srcs).map(async ({ url, descriptor }) => ({
url: await replacer({ url, descriptor }),
descriptor
}))
).then((ret) => reduceSrcset(ret))
}
export function processSrcSetSync(
srcs: string,
replacer: (arg: ImageCandidate) => string
): string {
return reduceSrcset(
splitSrcSetDescriptor(srcs).map(({ url, descriptor }) => ({
url: replacer({ url, descriptor }),
descriptor
}))
)
return ret.reduce((prev, { url, descriptor }, index) => {
descriptor ??= ''
return (prev +=
url + ` ${descriptor}${index === ret.length - 1 ? '' : ', '}`)
}, '')
}
function splitSrcSet(srcs: string) {

View File

@ -192,7 +192,7 @@ describe('image', () => {
expect(s).toMatch(
isBuild
? /\/foo\/assets\/asset\.\w{8}\.png \d{1}x/
: /\.\/nested\/asset\.png \d{1}x/
: /\/foo\/nested\/asset\.png \d{1}x/
)
})
})

View File

@ -3,7 +3,7 @@ import { isBuild, page } from '~utils'
const mode = isBuild ? `production` : `development`
test('base', async () => {
expect(await page.textContent('.base')).toBe('/')
expect(await page.textContent('.base')).toBe('/env/')
})
test('mode', async () => {
@ -46,9 +46,15 @@ test('env object', async () => {
VITE_EFFECTIVE_MODE_FILE_NAME: `.env.${mode}`,
CUSTOM_PREFIX_ENV_VARIABLE: '1',
VITE_CUSTOM_ENV_VARIABLE: '1',
BASE_URL: '/',
BASE_URL: '/env/',
MODE: mode,
DEV: !isBuild,
PROD: isBuild
})
})
if (!isBuild) {
test('relative url import script return import.meta.url', async () => {
expect(await page.textContent('.url')).toMatch('/env/index.js')
})
}

View File

@ -14,6 +14,7 @@
<p>import.meta.env.VITE_INLINE: <code class="inline"></code></p>
<p>process.env.NODE_ENV: <code class="node-env"></code></p>
<p>import.meta.env: <span class="pre env-object"></span></p>
<p>import.meta.url: <span class="pre url"></span></p>
<script type="module">
text('.base', import.meta.env.BASE_URL)
@ -31,6 +32,7 @@
document.querySelector(el).textContent = text
}
</script>
<script type="module" src="./index.js"></script>
<style>
.pre {

5
playground/env/index.js vendored Normal file
View File

@ -0,0 +1,5 @@
text('.url', import.meta.url)
function text(el, text) {
document.querySelector(el).textContent = text
}

View File

@ -1,5 +1,9 @@
const { defineConfig } = require('vite')
module.exports = defineConfig({
envPrefix: ['VITE_', 'CUSTOM_PREFIX_']
base: '/env/',
envPrefix: ['VITE_', 'CUSTOM_PREFIX_'],
build: {
outDir: 'dist/env'
}
})