Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix: srcset handling in html (#6419)
  • Loading branch information
poyoho committed May 19, 2022
1 parent c85e51a commit a0ee4ff
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 29 deletions.
20 changes: 13 additions & 7 deletions packages/vite/src/node/server/middlewares/indexHtml.ts
Expand Up @@ -27,7 +27,8 @@ import {
ensureWatchedFile,
fsPathFromId,
injectQuery,
normalizePath
normalizePath,
processSrcSetSync
} from '../../utils'
import type { ModuleGraph } from '../moduleGraph'

Expand Down Expand Up @@ -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)}"`
)
}
}
Expand Down
50 changes: 32 additions & 18 deletions packages/vite/src/node/utils.ts
Expand Up @@ -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) || []
Expand All @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion playground/assets/__tests__/assets.spec.ts
Expand Up @@ -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/
)
})
})
Expand Down
10 changes: 8 additions & 2 deletions playground/env/__tests__/env.spec.ts
Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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
Expand Up @@ -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)
Expand All @@ -31,6 +32,7 @@ <h1>Environment Variables</h1>
document.querySelector(el).textContent = text
}
</script>
<script type="module" src="./index.js"></script>

<style>
.pre {
Expand Down
5 changes: 5 additions & 0 deletions playground/env/index.js
@@ -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
@@ -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.