diff --git a/packages/vite/src/node/server/middlewares/indexHtml.ts b/packages/vite/src/node/server/middlewares/indexHtml.ts index c9d9228a0d79ef..96d05c418c1ae1 100644 --- a/packages/vite/src/node/server/middlewares/indexHtml.ts +++ b/packages/vite/src/node/server/middlewares/indexHtml.ts @@ -92,6 +92,8 @@ function shouldPreTransform(url: string, config: ResolvedConfig) { ) } +const startsWithWordCharRE = /^\w/ + const processNodeUrl = ( attr: Token.Attribute, sourceCodeLocation: Token.Location, @@ -118,7 +120,7 @@ const processNodeUrl = ( preTransformRequest(server, fullUrl, devBase) } } else if ( - url[0] === '.' && + (url[0] === '.' || startsWithWordCharRE.test(url)) && originalUrl && originalUrl !== '/' && htmlPath === '/index.html' diff --git a/playground/assets/__tests__/assets.spec.ts b/playground/assets/__tests__/assets.spec.ts index 43a93a19276440..77a0ca11c6c810 100644 --- a/playground/assets/__tests__/assets.spec.ts +++ b/playground/assets/__tests__/assets.spec.ts @@ -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), { @@ -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() @@ -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() @@ -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(` @@ -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` @@ -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/, ) }) }) @@ -289,7 +289,7 @@ test('?url import', async () => { ? `data:application/javascript;base64,${Buffer.from(src).toString( 'base64', )}` - : `/foo/foo.js`, + : `/foo/bar/foo.js`, ) }) @@ -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', ) }) @@ -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`, ) }) }) @@ -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, ) }) @@ -464,7 +469,7 @@ test('url() contains file in publicDir, in