Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Test Index HTML</title>
</head>
<body>
<div id="app"></div>
<script type="module">
console.log('test module loaded')
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import fs from 'node:fs'
import path from 'node:path'
import { describe, expect, onTestFinished, test } from 'vitest'
import { createServer } from '../../../server'
import { FS_PREFIX } from '../../../constants'

const FIXTURE_DIR = path.resolve(import.meta.dirname, 'fixtures')
const HTML_PATH = path.resolve(FIXTURE_DIR, 'root/index.html')
const HTML_CONTENT = fs.readFileSync(HTML_PATH, 'utf-8')

async function createTestServer(rootDir?: string) {
const root = path.resolve(import.meta.dirname, rootDir ?? 'fixtures/root')

const server = await createServer({
configFile: false,
root,
logLevel: 'error',
server: {
middlewareMode: true,
ws: false,
},
optimizeDeps: {
noDiscovery: true,
include: [],
},
})

onTestFinished(() => server.close())
return server
}

describe('indexHtml middleware — /@fs/ inline script proxy cache', () => {
test('inline <script type="module"> in an /@fs/ HTML file is loadable via the html-proxy module', async () => {
const server = await createTestServer()
const fsUrl = path.posix.join(FS_PREFIX, HTML_PATH)
Comment thread
JarekToro marked this conversation as resolved.

const transformed = await server.transformIndexHtml(fsUrl, HTML_CONTENT)

expect(transformed).toContain('html-proxy')
expect(transformed).toContain('index=0')

const proxyUrlMatch = transformed.match(/src="([^"]*html-proxy[^"]*)"/)
expect(
proxyUrlMatch,
'devHtmlHook should have rewritten the inline <script> to a ?html-proxy src',
).toBeTruthy()

const proxyModuleUrl = proxyUrlMatch![1]

const result =
await server.environments.client.transformRequest(proxyModuleUrl)

expect(
result,
'proxy module should resolve without a cache-miss error',
).not.toBeNull()
expect(result!.code).toContain('module loaded')
})

test('inline <script type="module"> in an HTML file served from root is loadable via the html-proxy module', async () => {
const server = await createTestServer('fixtures/root')
const url = '/index.html'

const htmlPath = path.resolve(
import.meta.dirname,
'fixtures/root/index.html',
)
const htmlContent = fs.readFileSync(htmlPath, 'utf-8')

const transformed = await server.transformIndexHtml(url, htmlContent)

expect(transformed).toContain('html-proxy')
expect(transformed).toContain('index=0')

const proxyUrlMatch = transformed.match(/src="([^"]*html-proxy[^"]*)"/)
expect(
proxyUrlMatch,
'devHtmlHook should rewrite the inline <script> to a ?html-proxy src',
).toBeTruthy()

const proxyModuleUrl = proxyUrlMatch![1]
const result =
await server.environments.client.transformRequest(proxyModuleUrl)

expect(result, 'proxy module should resolve without error').not.toBeNull()
expect(result!.code).toContain('module loaded')
})
})
7 changes: 5 additions & 2 deletions packages/vite/src/node/server/middlewares/indexHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,11 @@ const devHtmlHook: IndexHtmlTransformHook = async (

const trailingSlash = htmlPath.endsWith('/')
if (!trailingSlash && fs.existsSync(filename)) {
proxyModulePath = htmlPath
proxyModuleUrl = proxyModulePath
// If htmlPath is a /@fs/ URL (e.g. vitest-browser always uses this form
// for testerHtmlPath), normalise to an absolute FS path so proxyCacheUrl
// is always root-relative.
proxyModulePath = htmlPath.startsWith(FS_PREFIX) ? filename : htmlPath

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason it cannot be proxyModulePath = proxyModuleUrl = filename?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well I know the issue is specific to htmlpaths that prefix with /@fs/ and not all paths. So to avoid changing to logic for the parts that work the fix is specific to the paths that fail.

The htmlpath can differ from the file name and the proxy code relies on ensuring the key is correct, which is what the problem specific to /@fs/ was causing so it could inadvertently break the key downstream if we just change them all.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I agree with the choice, but if changing proxyModulePath = proxyModuleUrl = filename would break something, then that means /@fs/ case can still partially broken. I was just wondering if we can get that one ahead.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessary getting ahead with the fix, but it's good to acknowledge the limitation of /@fs/ on Vite side if any. If that's the case, maybe Vitest side should workaround this too.

proxyModuleUrl = htmlPath
Comment thread
sapphi-red marked this conversation as resolved.
} else {
// There are users of vite.transformIndexHtml calling it with url '/'
// for SSR integrations #7993, filename is root for this case
Expand Down