Skip to content

Commit

Permalink
fix(html): relative paths without leading dot wasn't rewritten (#14591)
Browse files Browse the repository at this point in the history
  • Loading branch information
sapphi-red authored Oct 12, 2023
1 parent 31333bb commit 0a38e3b
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 25 deletions.
4 changes: 3 additions & 1 deletion packages/vite/src/node/server/middlewares/indexHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ function shouldPreTransform(url: string, config: ResolvedConfig) {
)
}

const startsWithWordCharRE = /^\w/

const processNodeUrl = (
attr: Token.Attribute,
sourceCodeLocation: Token.Location,
Expand All @@ -118,7 +120,7 @@ const processNodeUrl = (
preTransformRequest(server, fullUrl, devBase)
}
} else if (
url[0] === '.' &&
(url[0] === '.' || startsWithWordCharRE.test(url)) &&
originalUrl &&
originalUrl !== '/' &&
htmlPath === '/index.html'
Expand Down
51 changes: 28 additions & 23 deletions playground/assets/__tests__/assets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import {
} from '~utils'

const assetMatch = isBuild
? /\/foo\/assets\/asset-\w{8}\.png/
: '/foo/nested/asset.png'
? /\/foo\/bar\/assets\/asset-\w{8}\.png/
: '/foo/bar/nested/asset.png'

const iconMatch = `/foo/icon.png`
const iconMatch = `/foo/bar/icon.png`

const fetchPath = (p: string) => {
return fetch(path.posix.join(viteTestUrl, p), {
Expand Down Expand Up @@ -63,7 +63,7 @@ test('should fallback to index.html when accessing non-existant html file', asyn
describe('injected scripts', () => {
test('@vite/client', async () => {
const hasClient = await page.$(
'script[type="module"][src="/foo/@vite/client"]',
'script[type="module"][src="/foo/bar/@vite/client"]',
)
if (isBuild) {
expect(hasClient).toBeFalsy()
Expand All @@ -74,7 +74,7 @@ describe('injected scripts', () => {

test('html-proxy', async () => {
const hasHtmlProxy = await page.$(
'script[type="module"][src^="/foo/index.html?html-proxy"]',
'script[type="module"][src^="/foo/bar/index.html?html-proxy"]',
)
if (isBuild) {
expect(hasHtmlProxy).toBeFalsy()
Expand Down Expand Up @@ -115,7 +115,7 @@ describe('asset imports from js', () => {

test('from /public (json)', async () => {
expect(await page.textContent('.public-json-import')).toMatch(
'/foo/foo.json',
'/foo/bar/foo.json',
)
expect(await page.textContent('.public-json-import-content'))
.toMatchInlineSnapshot(`
Expand Down Expand Up @@ -207,7 +207,7 @@ describe('css url() references', () => {
})

test('base64 inline', async () => {
const match = isBuild ? `data:image/png;base64` : `/foo/nested/icon.png`
const match = isBuild ? `data:image/png;base64` : `/foo/bar/nested/icon.png`
expect(await getBg('.css-url-base64-inline')).toMatch(match)
expect(await getBg('.css-url-quotes-base64-inline')).toMatch(match)
const icoMatch = isBuild ? `data:image/x-icon;base64` : `favicon.ico`
Expand Down Expand Up @@ -245,8 +245,8 @@ describe('image', () => {
srcset.split(', ').forEach((s) => {
expect(s).toMatch(
isBuild
? /\/foo\/assets\/asset-\w{8}\.png \dx/
: /\/foo\/nested\/asset.png \dx/,
? /\/foo\/bar\/assets\/asset-\w{8}\.png \dx/
: /\/foo\/bar\/nested\/asset.png \dx/,
)
})
})
Expand Down Expand Up @@ -289,7 +289,7 @@ test('?url import', async () => {
? `data:application/javascript;base64,${Buffer.from(src).toString(
'base64',
)}`
: `/foo/foo.js`,
: `/foo/bar/foo.js`,
)
})

Expand All @@ -299,7 +299,7 @@ test('?url import on css', async () => {
expect(txt).toEqual(
isBuild
? `data:text/css;base64,${Buffer.from(src).toString('base64')}`
: '/foo/css/icons.css',
: '/foo/bar/css/icons.css',
)
})

Expand All @@ -311,7 +311,7 @@ describe('unicode url', () => {
? `data:application/javascript;base64,${Buffer.from(src).toString(
'base64',
)}`
: `/foo/テスト-測試-white space.js`,
: `/foo/bar/テスト-測試-white space.js`,
)
})
})
Expand Down Expand Up @@ -350,41 +350,46 @@ test('new URL(..., import.meta.url) without extension', async () => {

test('new URL(`${dynamic}`, import.meta.url)', async () => {
expect(await page.textContent('.dynamic-import-meta-url-1')).toMatch(
isBuild ? 'data:image/png;base64' : '/foo/nested/icon.png',
isBuild ? 'data:image/png;base64' : '/foo/bar/nested/icon.png',
)
expect(await page.textContent('.dynamic-import-meta-url-2')).toMatch(
assetMatch,
)
expect(await page.textContent('.dynamic-import-meta-url-js')).toMatch(
isBuild ? 'data:application/javascript;base64' : '/foo/nested/test.js',
isBuild ? 'data:application/javascript;base64' : '/foo/bar/nested/test.js',
)
})

test('new URL(`./${dynamic}?abc`, import.meta.url)', async () => {
expect(await page.textContent('.dynamic-import-meta-url-1-query')).toMatch(
isBuild ? 'data:image/png;base64' : '/foo/nested/icon.png?abc',
isBuild ? 'data:image/png;base64' : '/foo/bar/nested/icon.png?abc',
)
expect(await page.textContent('.dynamic-import-meta-url-2-query')).toMatch(
isBuild
? /\/foo\/assets\/asset-\w{8}\.png\?abc/
: '/foo/nested/asset.png?abc',
? /\/foo\/bar\/assets\/asset-\w{8}\.png\?abc/
: '/foo/bar/nested/asset.png?abc',
)
})

test('new URL(`./${1 === 0 ? static : dynamic}?abc`, import.meta.url)', async () => {
expect(await page.textContent('.dynamic-import-meta-url-1-ternary')).toMatch(
isBuild ? 'data:image/png;base64' : '/foo/nested/icon.png?abc',
isBuild ? 'data:image/png;base64' : '/foo/bar/nested/icon.png?abc',
)
expect(await page.textContent('.dynamic-import-meta-url-2-ternary')).toMatch(
isBuild
? /\/foo\/assets\/asset-\w{8}\.png\?abc/
: '/foo/nested/asset.png?abc',
? /\/foo\/bar\/assets\/asset-\w{8}\.png\?abc/
: '/foo/bar/nested/asset.png?abc',
)
})

test('new URL(`non-existent`, import.meta.url)', async () => {
// the inlined script tag is extracted in a separate file
const importMetaUrl = new URL(
isBuild ? '/foo/bar/assets/index.js' : '/foo/bar/index.html',
page.url(),
)
expect(await page.textContent('.non-existent-import-meta-url')).toMatch(
new URL('non-existent', page.url()).pathname,
new URL('non-existent', importMetaUrl).pathname,
)
})

Expand Down Expand Up @@ -464,14 +469,14 @@ test('url() contains file in publicDir, in <style> tag', async () => {

test.skip('url() contains file in publicDir, as inline style', async () => {
// TODO: To investigate why `await getBg('.inline-style-public') === "url("http://localhost:5173/icon.png")"`
// It supposes to be `url("http://localhost:5173/foo/icon.png")`
// It supposes to be `url("http://localhost:5173/foo/bar/icon.png")`
// (I built the playground to verify)
expect(await getBg('.inline-style-public')).toContain(iconMatch)
})

test.runIf(isBuild)('assets inside <noscript> is rewrote', async () => {
const indexHtml = readFile('./dist/foo/index.html')
expect(indexHtml).toMatch(
/<img class="noscript" src="\/foo\/assets\/asset-\w+\.png" \/>/,
/<img class="noscript" src="\/foo\/bar\/assets\/asset-\w+\.png" \/>/,
)
})
2 changes: 1 addition & 1 deletion playground/assets/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import path from 'node:path'
import { defineConfig } from 'vite'

export default defineConfig({
base: '/foo',
base: '/foo/bar',
publicDir: 'static',
resolve: {
alias: {
Expand Down

0 comments on commit 0a38e3b

Please sign in to comment.