diff --git a/src/build/vite/dev.ts b/src/build/vite/dev.ts index 52682b009e..14509ee84a 100644 --- a/src/build/vite/dev.ts +++ b/src/build/vite/dev.ts @@ -6,7 +6,7 @@ import type { RunnerRPCHooks, UpgradeContext } from "env-runner"; import { IncomingMessage, ServerResponse } from "node:http"; import { NodeRequest, sendNodeResponse } from "srvx/node"; import { createViteHotChannel } from "env-runner/vite"; -import { basename, dirname, join, normalize } from "pathe"; +import { basename, dirname, isAbsolute, join, normalize, relative } from "pathe"; import { debounce } from "perfect-debounce"; import { withBase, withoutBase } from "ufo"; import { scanHandlers } from "../../scan.ts"; @@ -250,7 +250,8 @@ export async function configureViteDevServer(ctx: NitroPluginContext, server: Vi nitroEnv.devServer.onMessage(async (message: any) => { if (message?.__rpc === "transformHTML") { try { - const html = (await server.transformIndexHtml("/", message.data)).replace( + const htmlURL = _htmlTemplateURL(nitro.options.renderer?.template, server.config.root); + const html = (await server.transformIndexHtml(htmlURL, message.data)).replace( "", `{{{ globalThis.__nitro_vite_envs__?.["ssr"]?.fetch($REQUEST) || "" }}}` ); @@ -444,3 +445,12 @@ export function matchesMiddlewareRoute(route: string | undefined, url: string): const boundary = path[route.length]; return !boundary || boundary === "/" || boundary === "."; } + +// Vite derives the HTML file path from the URL, which relative imports (e.g. in inline ` + + +

html template

+ + diff --git a/test/vite/html-template-fixture/src/style.css b/test/vite/html-template-fixture/src/style.css new file mode 100644 index 0000000000..e9a20421be --- /dev/null +++ b/test/vite/html-template-fixture/src/style.css @@ -0,0 +1,3 @@ +.imported-style { + color: rebeccapurple; +} diff --git a/test/vite/html-template-fixture/vite.config.ts b/test/vite/html-template-fixture/vite.config.ts new file mode 100644 index 0000000000..dc884054e6 --- /dev/null +++ b/test/vite/html-template-fixture/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "vite"; +import { nitro } from "nitro/vite"; + +export default defineConfig({ + plugins: [nitro()], +}); diff --git a/test/vite/html-template.test.ts b/test/vite/html-template.test.ts new file mode 100644 index 0000000000..8fe7b91b0d --- /dev/null +++ b/test/vite/html-template.test.ts @@ -0,0 +1,39 @@ +import { fileURLToPath } from "node:url"; +import type { ViteDevServer } from "vite"; +import { beforeAll, afterAll, describe, expect, test } from "vitest"; + +const { createServer } = (await import( + process.env.NITRO_VITE_PKG || "vite" +)) as typeof import("vite"); + +describe("vite:html template", () => { + let server: ViteDevServer; + let serverURL: string; + + const rootDir = fileURLToPath(new URL("./html-template-fixture", import.meta.url)); + + beforeAll(async () => { + server = await createServer({ root: rootDir, logLevel: "warn" }); + await server.listen("0" as unknown as number); + const addr = server.httpServer?.address() as { + port: number; + address: string; + family: string; + }; + serverURL = `http://${addr.family === "IPv6" ? `[${addr.address}]` : addr.address}:${addr.port}`; + }, 30_000); + + afterAll(async () => { + await server?.close(); + }); + + // Relative imports in inline `