Skip to content

Commit

Permalink
fix: srcset handling in html (#6419)
Browse files Browse the repository at this point in the history
poyoho authored May 19, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent c85e51a commit a0ee4ff
Showing 7 changed files with 66 additions and 29 deletions.
20 changes: 13 additions & 7 deletions packages/vite/src/node/server/middlewares/indexHtml.ts
Original file line number Diff line number Diff line change
@@ -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)}"`
)
}
}
50 changes: 32 additions & 18 deletions packages/vite/src/node/utils.ts
Original file line number Diff line number Diff line change
@@ -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))
}

return ret.reduce((prev, { url, descriptor }, index) => {
descriptor ??= ''
return (prev +=
url + ` ${descriptor}${index === ret.length - 1 ? '' : ', '}`)
}, '')
export function processSrcSetSync(
srcs: string,
replacer: (arg: ImageCandidate) => string
): string {
return reduceSrcset(
splitSrcSetDescriptor(srcs).map(({ url, descriptor }) => ({
url: replacer({ url, descriptor }),
descriptor
}))
)
}

function splitSrcSet(srcs: string) {
2 changes: 1 addition & 1 deletion playground/assets/__tests__/assets.spec.ts
Original file line number Diff line number Diff line change
@@ -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/
)
})
})
10 changes: 8 additions & 2 deletions playground/env/__tests__/env.spec.ts
Original file line number Diff line number Diff line change
@@ -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')
})
}
2 changes: 2 additions & 0 deletions playground/env/index.html
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ <h1>Environment Variables</h1>
<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 @@ <h1>Environment Variables</h1>
document.querySelector(el).textContent = text
}
</script>
<script type="module" src="./index.js"></script>

<style>
.pre {
5 changes: 5 additions & 0 deletions playground/env/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
text('.url', import.meta.url)

function text(el, text) {
document.querySelector(el).textContent = text
}
6 changes: 5 additions & 1 deletion playground/env/vite.config.js
Original file line number Diff line number Diff line change
@@ -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'
}
})

0 comments on commit a0ee4ff

Please sign in to comment.