fix: avoid vite html transform retention

This commit is contained in:
Dotta committed 2026-04-14 11:53:57 -05:00
1 parent c32b56398e
commit 1ab9cd8dfe
2 files changed
+24 -9

No files matched your search

@@ -1,7 +1,7 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import { afterEach, describe, expect, it } from "vitest";
import { createCachedViteHtmlRenderer, type ViteWatcherHost } from "../vite-html-renderer.js";
function createWatcher() {
@@ -50,10 +50,12 @@ describe("createCachedViteHtmlRenderer", () => {
const renderer = createCachedViteHtmlRenderer({ vite, uiRoot: tempDir });
await expect(renderer.render("/")).resolves.toContain("/@vite/client");
await expect(renderer.render("/")).resolves.toContain('"/@react-refresh"');
const first = await renderer.render("/");
const second = await renderer.render("/issues");
expect(first).toBe(second);
expect(first.match(/\/@vite\/client/g)?.length).toBe(1);
expect(first).toContain("window.$RefreshReg$");
fs.writeFileSync(
indexPath,
@@ -67,12 +69,12 @@ describe("createCachedViteHtmlRenderer", () => {
renderer.dispose();
});
it("does not duplicate the vite client tag when it already exists", async () => {
it("does not duplicate the vite client tag or react refresh preamble when already present", async () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "paperclip-vite-html-"));
tempDirs.push(tempDir);
fs.writeFileSync(
path.join(tempDir, "index.html"),
'<html><body><script type="module" src="/@vite/client"></script></body></html>',
'<html><head><script type="module">import { injectIntoGlobalHook } from "/@react-refresh";injectIntoGlobalHook(window);window.$RefreshReg$ = () => {};window.$RefreshSig$ = () => (type) => type;</script></head><body><script type="module" src="/@vite/client"></script><script type="module" src="/src/main.tsx"></script></body></html>',
"utf8",
);
@@ -84,5 +86,6 @@ describe("createCachedViteHtmlRenderer", () => {
const html = await renderer.render("/");
expect(html.match(/\/@vite\/client/g)?.length).toBe(1);
expect(html.match(/\/@react-refresh/g)?.length).toBe(1);
});
});
+18 -6
View File
@@ -18,13 +18,25 @@ export interface CachedViteHtmlRenderer {
const WATCHER_EVENTS: ViteWatcherEvent[] = ["add", "change", "unlink"];
const MAIN_ENTRY_TAG = '<script type="module" src="/src/main.tsx"></script>';
const VITE_CLIENT_TAG = '<script type="module" src="/@vite/client"></script>';
const REACT_REFRESH_PREAMBLE = `<script type="module">
import { injectIntoGlobalHook } from "/@react-refresh";
injectIntoGlobalHook(window);
window.$RefreshReg$ = () => {};
window.$RefreshSig$ = () => (type) => type;
</script>`;
function injectViteClient(html: string): string {
if (html.includes(VITE_CLIENT_TAG)) return html;
if (html.includes(MAIN_ENTRY_TAG)) {
return html.replace(MAIN_ENTRY_TAG, `${VITE_CLIENT_TAG}\n ${MAIN_ENTRY_TAG}`);
function injectViteDevPreamble(html: string): string {
let injectedHtml = html;
if (!injectedHtml.includes('"/@react-refresh"') && !injectedHtml.includes("'/@react-refresh'")) {
injectedHtml = injectedHtml.includes("</head>")
? injectedHtml.replace("</head>", ` ${REACT_REFRESH_PREAMBLE}\n </head>`)
: `${REACT_REFRESH_PREAMBLE}\n${injectedHtml}`;
}
return html.replace("</body>", ` ${VITE_CLIENT_TAG}\n </body>`);
if (injectedHtml.includes(VITE_CLIENT_TAG)) return injectedHtml;
if (injectedHtml.includes(MAIN_ENTRY_TAG)) {
return injectedHtml.replace(MAIN_ENTRY_TAG, `${VITE_CLIENT_TAG}\n ${MAIN_ENTRY_TAG}`);
}
return injectedHtml.replace("</body>", ` ${VITE_CLIENT_TAG}\n </body>`);
}
export function createCachedViteHtmlRenderer(opts: {
@@ -40,7 +52,7 @@ export function createCachedViteHtmlRenderer(opts: {
function loadHtml(): string {
if (cachedHtml === null) {
const rawTemplate = fs.readFileSync(templatePath, "utf-8");
cachedHtml = brandHtml(injectViteClient(rawTemplate));
cachedHtml = injectViteDevPreamble(brandHtml(rawTemplate));
}
return cachedHtml;
}