Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(html): relative paths without leading dot wasn't rewritten #14591

Merged
merged 2 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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