Skip to content

Commit 983c75e

Browse files
committed
fix: patch virtual module null byte in data-vite-dev-id
1 parent 28e9822 commit 983c75e

File tree

4 files changed

+36
-1
lines changed

4 files changed

+36
-1
lines changed

packages/start/src/config/manifest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export function manifest(start: SolidStartOptions): PluginOption {
7070
tag: "style",
7171
attrs: {
7272
type: "text/css",
73-
"data-vite-dev-id": "${key}",
73+
"data-vite-dev-id": "${wrapId(key)}",
7474
"data-vite-ref": "0",
7575
},
7676
children: () => import("${wrapId(value)}?inline").then(mod => mod.default),

packages/start/src/server/StartServer.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import App from "solid-start:app";
55

66
import { ErrorBoundary, TopErrorBoundary } from "../shared/ErrorBoundary.tsx";
77
import { useAssets } from "./assets/index.ts";
8+
import PatchVirtualDevStyles from "./assets/PatchVirtualDevStyles.tsx";
89
import { getSsrManifest } from "./manifest/ssr-manifest.ts";
910
import type { DocumentComponentProps, PageEvent } from "./types.ts";
1011

@@ -29,6 +30,7 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
2930
assets={<HydrationScript />}
3031
scripts={
3132
<>
33+
<PatchVirtualDevStyles nonce={nonce} />
3234
<script
3335
type="module"
3436
nonce={nonce}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Patches the data-vite-dev-id attribute for style tags of virtual modules
3+
*
4+
* Per Vite's convention, virtual module ids are prefixed with \0 (null byte):
5+
* https://vite.dev/guide/api-plugin#virtual-modules-convention
6+
*
7+
* However this null byte cannot be server rendered properly.
8+
* Vite client runtime then fails to find style's with wrong null bytes,
9+
* and instead inserts duplicate style's.
10+
*
11+
* This patch replaces the serializable /@id/__x00__ with the proper null byte,
12+
* and has to run before Vite's client runtime:
13+
* https://github.com/vitejs/vite/blob/130e7181a55c524383c63bbfb1749d0ff7185cad/packages/vite/src/client/client.ts#L529
14+
*
15+
* TODO: This should be solved in Vite directly!
16+
*/
17+
const patch = function () {
18+
document.querySelectorAll<HTMLElement>("style[data-vite-dev-id]").forEach(function (el) {
19+
el.setAttribute("data-vite-dev-id", el.dataset.viteDevId!.replace("/@id/__x00__", "\0"));
20+
});
21+
};
22+
23+
const serializedPatch = `(${patch.toString()})();`;
24+
25+
const PatchVirtualDevStyles = (props: { nonce?: string }) => {
26+
if (!import.meta.env.PROD) {
27+
return <script nonce={props.nonce} innerHTML={serializedPatch} />;
28+
}
29+
};
30+
31+
export default PatchVirtualDevStyles;

packages/start/src/server/spa/StartServer.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { getSsrManifest } from "../manifest/ssr-manifest.ts";
66

77
import { TopErrorBoundary } from "../../shared/ErrorBoundary.tsx";
88
import { useAssets } from "../assets/index.ts";
9+
import PatchVirtualDevStyles from "../assets/PatchVirtualDevStyles.tsx";
910
import type { DocumentComponentProps, PageEvent } from "../types.ts";
1011

1112
const docType = ssr("<!DOCTYPE html>");
@@ -27,6 +28,7 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
2728
<props.document
2829
scripts={
2930
<>
31+
<PatchVirtualDevStyles nonce={nonce} />
3032
<script
3133
type="module"
3234
src={getSsrManifest("client").path(import.meta.env.START_CLIENT_ENTRY)}

0 commit comments

Comments
 (0)