@solidjs/start 2.0.0-alpha.1 → 2.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/config/dev-server.js +10 -0
- package/dist/config/fs-routes/router.js +5 -6
- package/dist/config/index.js +9 -6
- package/dist/config/lazy.js +33 -3
- package/dist/config/manifest.js +3 -2
- package/dist/config/vite-utils.d.ts +5 -0
- package/dist/config/vite-utils.js +7 -3
- package/dist/middleware/index.d.ts +5 -2
- package/dist/middleware/index.js +6 -1
- package/dist/server/StartServer.jsx +2 -0
- package/dist/server/assets/PatchVirtualDevStyles.d.ts +4 -0
- package/dist/server/assets/PatchVirtualDevStyles.jsx +28 -0
- package/dist/server/collect-styles.js +9 -21
- package/dist/server/handler.js +1 -0
- package/dist/server/spa/StartServer.jsx +2 -0
- package/package.json +1 -1
- package/src/config/dev-server.ts +12 -0
- package/src/config/fs-routes/router.ts +5 -6
- package/src/config/index.ts +12 -10
- package/src/config/lazy.ts +34 -3
- package/src/config/manifest.ts +3 -2
- package/src/config/vite-utils.ts +7 -3
- package/src/middleware/index.ts +6 -3
- package/src/server/StartServer.tsx +2 -0
- package/src/server/assets/PatchVirtualDevStyles.tsx +31 -0
- package/src/server/collect-styles.ts +9 -26
- package/src/server/handler.ts +2 -0
- package/src/server/spa/StartServer.tsx +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @solidjs/start
|
|
2
2
|
|
|
3
|
+
## 2.0.0-alpha.2
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 10bf932: Fix path resolution on Windows
|
|
8
|
+
- 40d5a27: fix onBeforeResponse
|
|
9
|
+
- 9201e71: fix text/html missing when ssr is false
|
|
10
|
+
- a9cd2cc: add `vite preview` support
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- 7077a49: Fixed CSS from shared chunks not being collected via the chunk name.
|
|
15
|
+
- a620eeb: Fixed virtual module CSS not being collected in vite dev.
|
|
16
|
+
|
|
3
17
|
## 2.0.0-alpha.1
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -5,6 +5,16 @@ export function devServer() {
|
|
|
5
5
|
return [
|
|
6
6
|
{
|
|
7
7
|
name: "solid-start-dev-server",
|
|
8
|
+
configurePreviewServer(server) {
|
|
9
|
+
return () => {
|
|
10
|
+
server.middlewares.use(async (req, res) => {
|
|
11
|
+
res.setHeader("content-encoding", "identity");
|
|
12
|
+
const webReq = new NodeRequest({ req, res });
|
|
13
|
+
const def = await import(process.cwd() + "/dist/server/entry-server.js");
|
|
14
|
+
sendNodeResponse(res, await def.default.fetch(webReq));
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
},
|
|
8
18
|
configureServer(viteDevServer) {
|
|
9
19
|
globalThis.VITE_DEV_SERVER = viteDevServer;
|
|
10
20
|
return async () => {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { init } from "es-module-lexer";
|
|
2
|
-
import { parse } from "es-module-lexer";
|
|
1
|
+
import { init, parse } from "es-module-lexer";
|
|
3
2
|
import esbuild from "esbuild";
|
|
4
3
|
import fg from "fast-glob";
|
|
5
4
|
import fs from "fs";
|
|
6
5
|
import micromatch from "micromatch";
|
|
7
6
|
import { posix } from "path";
|
|
8
7
|
import { pathToRegexp } from "path-to-regexp";
|
|
9
|
-
import {
|
|
8
|
+
import { normalizePath } from "vite";
|
|
10
9
|
export { pathToRegexp };
|
|
11
10
|
export const glob = (path) => fg.sync(path, { absolute: true });
|
|
12
11
|
export function cleanPath(src, config) {
|
|
@@ -76,7 +75,7 @@ export class BaseFileSystemRouter extends EventTarget {
|
|
|
76
75
|
this.routes.push(route);
|
|
77
76
|
}
|
|
78
77
|
async addRoute(src) {
|
|
79
|
-
src =
|
|
78
|
+
src = normalizePath(src);
|
|
80
79
|
if (this.isRoute(src)) {
|
|
81
80
|
try {
|
|
82
81
|
const route = this.toRoute(src);
|
|
@@ -99,7 +98,7 @@ export class BaseFileSystemRouter extends EventTarget {
|
|
|
99
98
|
}));
|
|
100
99
|
}
|
|
101
100
|
async updateRoute(src) {
|
|
102
|
-
src =
|
|
101
|
+
src = normalizePath(src);
|
|
103
102
|
if (this.isRoute(src)) {
|
|
104
103
|
try {
|
|
105
104
|
const route = this.toRoute(src);
|
|
@@ -115,7 +114,7 @@ export class BaseFileSystemRouter extends EventTarget {
|
|
|
115
114
|
}
|
|
116
115
|
}
|
|
117
116
|
removeRoute(src) {
|
|
118
|
-
src =
|
|
117
|
+
src = normalizePath(src);
|
|
119
118
|
if (this.isRoute(src)) {
|
|
120
119
|
const path = this.toPath(src);
|
|
121
120
|
if (path === undefined) {
|
package/dist/config/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { TanStackServerFnPlugin } from "@tanstack/server-functions-plugin";
|
|
2
2
|
import { defu } from "defu";
|
|
3
3
|
import { globSync } from "node:fs";
|
|
4
|
-
import { extname, isAbsolute, join
|
|
4
|
+
import { extname, isAbsolute, join } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { normalizePath } from "vite";
|
|
6
7
|
import solid from "vite-plugin-solid";
|
|
7
8
|
import { DEFAULT_EXTENSIONS, VIRTUAL_MODULES, VITE_ENVIRONMENTS } from "./constants.js";
|
|
8
9
|
import { devServer } from "./dev-server.js";
|
|
@@ -112,8 +113,10 @@ export function solidStart(options) {
|
|
|
112
113
|
define: {
|
|
113
114
|
"import.meta.env.MANIFEST": `globalThis.MANIFEST`,
|
|
114
115
|
"import.meta.env.START_SSR": JSON.stringify(start.ssr),
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
// Use JSON.stringify so backslashes on Windows are escaped and
|
|
117
|
+
// esbuild receives a valid JS string literal for the define value
|
|
118
|
+
"import.meta.env.START_APP_ENTRY": JSON.stringify(appEntryPath),
|
|
119
|
+
"import.meta.env.START_CLIENT_ENTRY": JSON.stringify(handlers.client),
|
|
117
120
|
"import.meta.env.START_DEV_OVERLAY": JSON.stringify(start.devOverlay),
|
|
118
121
|
},
|
|
119
122
|
builder: {
|
|
@@ -160,19 +163,19 @@ export function solidStart(options) {
|
|
|
160
163
|
{
|
|
161
164
|
envConsumer: "client",
|
|
162
165
|
envName: VITE_ENVIRONMENTS.client,
|
|
163
|
-
getRuntimeCode: () => `import { createServerReference } from "${
|
|
166
|
+
getRuntimeCode: () => `import { createServerReference } from "${normalizePath(fileURLToPath(new URL("../server/server-runtime", import.meta.url)))}"`,
|
|
164
167
|
replacer: opts => `createServerReference('${opts.functionId}')`,
|
|
165
168
|
},
|
|
166
169
|
{
|
|
167
170
|
envConsumer: "server",
|
|
168
171
|
envName: VITE_ENVIRONMENTS.server,
|
|
169
|
-
getRuntimeCode: () => `import { createServerReference } from '${
|
|
172
|
+
getRuntimeCode: () => `import { createServerReference } from '${normalizePath(fileURLToPath(new URL("../server/server-fns-runtime", import.meta.url)))}'`,
|
|
170
173
|
replacer: opts => `createServerReference(${opts.fn}, '${opts.functionId}')`,
|
|
171
174
|
},
|
|
172
175
|
],
|
|
173
176
|
provider: {
|
|
174
177
|
envName: VITE_ENVIRONMENTS.server,
|
|
175
|
-
getRuntimeCode: () => `import { createServerReference } from '${
|
|
178
|
+
getRuntimeCode: () => `import { createServerReference } from '${normalizePath(fileURLToPath(new URL("../server/server-fns-runtime", import.meta.url)))}'`,
|
|
176
179
|
replacer: opts => `createServerReference(${opts.fn}, '${opts.functionId}')`,
|
|
177
180
|
},
|
|
178
181
|
}),
|
package/dist/config/lazy.js
CHANGED
|
@@ -35,13 +35,42 @@ const importTransform = () => {
|
|
|
35
35
|
const fileEndingRegex = /(ts|js)x(\?.*)?$/;
|
|
36
36
|
const lazy = () => {
|
|
37
37
|
const cwd = process.cwd().replaceAll(osSep, sep);
|
|
38
|
+
/**
|
|
39
|
+
* Maps module ids to their client-specific shared chunk names.
|
|
40
|
+
* Modules in shared chunks need to find their assets via the chunk name, instead of their module id.
|
|
41
|
+
*
|
|
42
|
+
* Vite includes assets of such modules in the manifest via the chunk name:
|
|
43
|
+
* https://github.com/vitejs/vite/blob/4be37a8389c67873880f826b01fe40137e1c29a7/packages/vite/src/node/plugins/manifest.ts#L179
|
|
44
|
+
* https://github.com/vitejs/vite/blob/4be37a8389c67873880f826b01fe40137e1c29a7/packages/vite/src/node/plugins/manifest.ts#L319
|
|
45
|
+
*
|
|
46
|
+
* Rollup occassionally creates shared chunks automatically,
|
|
47
|
+
* but they can also be manually created by the user via:
|
|
48
|
+
* https://rollupjs.org/configuration-options/#output-manualchunks
|
|
49
|
+
*
|
|
50
|
+
* More infos on Rollup's logic:
|
|
51
|
+
* https://github.com/rollup/rollup/issues/3772#issuecomment-689955168
|
|
52
|
+
*/
|
|
53
|
+
const sharedChunkNames = {};
|
|
38
54
|
return {
|
|
39
55
|
name: "solid-lazy-css",
|
|
40
56
|
enforce: "pre",
|
|
41
|
-
|
|
42
|
-
|
|
57
|
+
generateBundle(_, bundle) {
|
|
58
|
+
if (this.environment.name !== VITE_ENVIRONMENTS.client)
|
|
59
|
+
return;
|
|
60
|
+
for (const chunk of Object.values(bundle)) {
|
|
61
|
+
if (chunk.type !== "chunk" || !chunk.isDynamicEntry || chunk.facadeModuleId)
|
|
62
|
+
continue;
|
|
63
|
+
// Has to follow Vites implementation:
|
|
64
|
+
// https://github.com/vitejs/vite/blob/4be37a8389c67873880f826b01fe40137e1c29a7/packages/vite/src/node/plugins/manifest.ts#L179
|
|
65
|
+
const chunkName = `_${basename(chunk.fileName)}`;
|
|
66
|
+
for (const id of chunk.moduleIds) {
|
|
67
|
+
sharedChunkNames[id] = chunkName;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
43
70
|
},
|
|
44
71
|
async transform(src, id) {
|
|
72
|
+
if (this.environment.name !== VITE_ENVIRONMENTS.server)
|
|
73
|
+
return;
|
|
45
74
|
if (!id.match(fileEndingRegex))
|
|
46
75
|
return;
|
|
47
76
|
// The transformed files either import "lazy" or css files
|
|
@@ -52,7 +81,8 @@ const lazy = () => {
|
|
|
52
81
|
const hasDefaultExport = src.indexOf("export default") !== -1;
|
|
53
82
|
if (hasDefaultExport) {
|
|
54
83
|
const localId = relative(cwd, id);
|
|
55
|
-
|
|
84
|
+
const chunkName = sharedChunkNames[id];
|
|
85
|
+
plugins.push(idTransform(chunkName ?? localId));
|
|
56
86
|
}
|
|
57
87
|
const hasLazy = src.indexOf("lazy(") !== -1;
|
|
58
88
|
if (hasLazy)
|
package/dist/config/manifest.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { findStylesInModuleGraph } from "../server/collect-styles.js";
|
|
2
2
|
import { VIRTUAL_MODULES } from "./constants.js";
|
|
3
|
+
import { wrapId } from "./vite-utils.js";
|
|
3
4
|
export function manifest(start) {
|
|
4
5
|
let devServer = undefined;
|
|
5
6
|
return {
|
|
@@ -61,10 +62,10 @@ export function manifest(start) {
|
|
|
61
62
|
tag: "style",
|
|
62
63
|
attrs: {
|
|
63
64
|
type: "text/css",
|
|
64
|
-
"data-vite-dev-id": "${key}",
|
|
65
|
+
"data-vite-dev-id": "${wrapId(key)}",
|
|
65
66
|
"data-vite-ref": "0",
|
|
66
67
|
},
|
|
67
|
-
children: () => import("${value}?inline").then(mod => mod.default),
|
|
68
|
+
children: () => import("${wrapId(value)}?inline").then(mod => mod.default),
|
|
68
69
|
}`);
|
|
69
70
|
return `export default [${cssAssets.join(",")}]`;
|
|
70
71
|
}
|
|
@@ -4,6 +4,11 @@ export declare const FS_PREFIX = "/@fs/";
|
|
|
4
4
|
export declare const VALID_ID_PREFIX = "/@id/";
|
|
5
5
|
export declare const NULL_BYTE_PLACEHOLDER = "__x00__";
|
|
6
6
|
export declare function normalizeResolvedIdToUrl(environment: DevEnvironment, url: string, resolved: Rollup.PartialResolvedId): string;
|
|
7
|
+
/**
|
|
8
|
+
* Inspired by:
|
|
9
|
+
* https://github.com/withastro/astro/blob/fddde5fad81007795eb263c7fd0cea096b8e2cba/packages/astro/src/core/util.ts#L115
|
|
10
|
+
* https://github.com/vitejs/vite/blob/130e7181a55c524383c63bbfb1749d0ff7185cad/packages/vite/src/shared/utils.ts#L11
|
|
11
|
+
*/
|
|
7
12
|
export declare function wrapId(id: string): string;
|
|
8
13
|
export declare function unwrapId(id: string): string;
|
|
9
14
|
export declare function normalizeViteImportAnalysisUrl(environment: DevEnvironment, id: string): string;
|
|
@@ -7,6 +7,7 @@ export function cleanUrl(url) {
|
|
|
7
7
|
export const FS_PREFIX = `/@fs/`;
|
|
8
8
|
export const VALID_ID_PREFIX = `/@id/`;
|
|
9
9
|
export const NULL_BYTE_PLACEHOLDER = `__x00__`;
|
|
10
|
+
const NULL_BYTE_REGEX = /^\0/;
|
|
10
11
|
export function normalizeResolvedIdToUrl(environment, url, resolved) {
|
|
11
12
|
const root = environment.config.root;
|
|
12
13
|
const depsOptimizer = environment.depsOptimizer;
|
|
@@ -38,10 +39,13 @@ export function normalizeResolvedIdToUrl(environment, url, resolved) {
|
|
|
38
39
|
}
|
|
39
40
|
return url;
|
|
40
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Inspired by:
|
|
44
|
+
* https://github.com/withastro/astro/blob/fddde5fad81007795eb263c7fd0cea096b8e2cba/packages/astro/src/core/util.ts#L115
|
|
45
|
+
* https://github.com/vitejs/vite/blob/130e7181a55c524383c63bbfb1749d0ff7185cad/packages/vite/src/shared/utils.ts#L11
|
|
46
|
+
*/
|
|
41
47
|
export function wrapId(id) {
|
|
42
|
-
return id.
|
|
43
|
-
? id
|
|
44
|
-
: VALID_ID_PREFIX + id.replace("\0", NULL_BYTE_PLACEHOLDER);
|
|
48
|
+
return id.replace(NULL_BYTE_REGEX, `${VALID_ID_PREFIX}${NULL_BYTE_PLACEHOLDER}`);
|
|
45
49
|
}
|
|
46
50
|
export function unwrapId(id) {
|
|
47
51
|
return id.startsWith(VALID_ID_PREFIX)
|
|
@@ -9,10 +9,13 @@ type ResponseMiddlewareResponseParam = {
|
|
|
9
9
|
body?: Awaited<EventHandlerResponse>;
|
|
10
10
|
};
|
|
11
11
|
export type ResponseMiddleware = (event: FetchEvent, response: ResponseMiddlewareResponseParam) => Response | Promise<Response> | void | Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Creates middleware for handling requests and responses.
|
|
14
|
+
*
|
|
15
|
+
* @see https://docs.solidjs.com/solid-start/reference/server/create-middleware
|
|
16
|
+
*/
|
|
12
17
|
export declare function createMiddleware(args: {
|
|
13
|
-
/** @deprecated Use H3 `Middleware` */
|
|
14
18
|
onRequest?: RequestMiddleware | RequestMiddleware[] | undefined;
|
|
15
|
-
/** @deprecated Use H3 `Middleware` */
|
|
16
19
|
onBeforeResponse?: ResponseMiddleware | ResponseMiddleware[] | undefined;
|
|
17
20
|
} | Middleware[]): Middleware[];
|
|
18
21
|
export {};
|
package/dist/middleware/index.js
CHANGED
|
@@ -13,12 +13,17 @@ function wrapResponseMiddleware(onBeforeResponse) {
|
|
|
13
13
|
const resp = await next();
|
|
14
14
|
const fetchEvent = getFetchEvent(h3Event);
|
|
15
15
|
const mwResponse = await onBeforeResponse(fetchEvent, {
|
|
16
|
-
body: resp
|
|
16
|
+
body: resp,
|
|
17
17
|
});
|
|
18
18
|
if (mwResponse)
|
|
19
19
|
return mwResponse;
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Creates middleware for handling requests and responses.
|
|
24
|
+
*
|
|
25
|
+
* @see https://docs.solidjs.com/solid-start/reference/server/create-middleware
|
|
26
|
+
*/
|
|
22
27
|
export function createMiddleware(args) {
|
|
23
28
|
if (Array.isArray(args))
|
|
24
29
|
return args;
|
|
@@ -2,6 +2,7 @@ import { Hydration, HydrationScript, NoHydration, getRequestEvent, ssr } from "s
|
|
|
2
2
|
import App from "solid-start:app";
|
|
3
3
|
import { ErrorBoundary, TopErrorBoundary } from "../shared/ErrorBoundary.jsx";
|
|
4
4
|
import { useAssets } from "./assets/index.js";
|
|
5
|
+
import PatchVirtualDevStyles from "./assets/PatchVirtualDevStyles.jsx";
|
|
5
6
|
import { getSsrManifest } from "./manifest/ssr-manifest.js";
|
|
6
7
|
const docType = ssr("<!DOCTYPE html>");
|
|
7
8
|
/**
|
|
@@ -17,6 +18,7 @@ export function StartServer(props) {
|
|
|
17
18
|
{docType}
|
|
18
19
|
<TopErrorBoundary>
|
|
19
20
|
<props.document assets={<HydrationScript />} scripts={<>
|
|
21
|
+
<PatchVirtualDevStyles nonce={nonce}/>
|
|
20
22
|
<script type="module" nonce={nonce} async src={getSsrManifest("client").path(import.meta.env.START_CLIENT_ENTRY)}/>
|
|
21
23
|
</>}>
|
|
22
24
|
{!import.meta.env.START_ISLANDS ? (<Hydration>
|
|
@@ -0,0 +1,28 @@
|
|
|
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("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
|
+
const serializedPatch = `(${patch.toString()})();`;
|
|
23
|
+
const PatchVirtualDevStyles = (props) => {
|
|
24
|
+
if (!import.meta.env.PROD) {
|
|
25
|
+
return <script nonce={props.nonce} innerHTML={serializedPatch}/>;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
export default PatchVirtualDevStyles;
|
|
@@ -1,28 +1,16 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (!node) {
|
|
7
|
-
const resolvedId = await vite.pluginContainer.resolveId(file, undefined);
|
|
8
|
-
if (!resolvedId)
|
|
2
|
+
async function getViteModuleNode(vite, file, importer) {
|
|
3
|
+
try {
|
|
4
|
+
const res = await vite.fetchModule(file, importer);
|
|
5
|
+
if (!("id" in res))
|
|
9
6
|
return;
|
|
10
|
-
|
|
11
|
-
node = vite.moduleGraph.getModuleById(file);
|
|
12
|
-
}
|
|
13
|
-
if (!node) {
|
|
14
|
-
nodePath = resolve(nodePath);
|
|
15
|
-
node = await vite.moduleGraph.getModuleByUrl(file);
|
|
16
|
-
}
|
|
17
|
-
if (!node) {
|
|
18
|
-
await vite.moduleGraph.ensureEntryFromUrl(nodePath, false);
|
|
19
|
-
node = vite.moduleGraph.getModuleById(nodePath);
|
|
7
|
+
return vite.moduleGraph.getModuleById(res.id);
|
|
20
8
|
}
|
|
21
|
-
|
|
9
|
+
catch (err) { }
|
|
22
10
|
}
|
|
23
|
-
async function findModuleDependencies(vite, file, deps, crawledFiles = new Set()) {
|
|
11
|
+
async function findModuleDependencies(vite, file, deps, crawledFiles = new Set(), importer) {
|
|
24
12
|
crawledFiles.add(file);
|
|
25
|
-
const module = await getViteModuleNode(vite, file);
|
|
13
|
+
const module = await getViteModuleNode(vite, file, importer);
|
|
26
14
|
if (!module?.id || deps.has(module))
|
|
27
15
|
return;
|
|
28
16
|
deps.add(module);
|
|
@@ -40,7 +28,7 @@ async function findModuleDependencies(vite, file, deps, crawledFiles = new Set()
|
|
|
40
28
|
if (crawledFiles.has(dep)) {
|
|
41
29
|
continue;
|
|
42
30
|
}
|
|
43
|
-
await findModuleDependencies(vite, dep, deps, crawledFiles);
|
|
31
|
+
await findModuleDependencies(vite, dep, deps, crawledFiles, module.id);
|
|
44
32
|
}
|
|
45
33
|
}
|
|
46
34
|
// Vite doesn't expose these so we just copy the list for now
|
package/dist/server/handler.js
CHANGED
|
@@ -58,6 +58,7 @@ export function createBaseHandler(createPageEvent, fn, options = {}) {
|
|
|
58
58
|
const status = getExpectedRedirectStatus(context.response);
|
|
59
59
|
return redirect(context.response.headers.get("Location"), status);
|
|
60
60
|
}
|
|
61
|
+
event.response.headers.set("content-type", "text/html");
|
|
61
62
|
return html;
|
|
62
63
|
}
|
|
63
64
|
if (resolvedOptions.onCompleteAll) {
|
|
@@ -2,6 +2,7 @@ import { NoHydration, getRequestEvent, ssr } from "solid-js/web";
|
|
|
2
2
|
import { getSsrManifest } from "../manifest/ssr-manifest.js";
|
|
3
3
|
import { TopErrorBoundary } from "../../shared/ErrorBoundary.jsx";
|
|
4
4
|
import { useAssets } from "../assets/index.js";
|
|
5
|
+
import PatchVirtualDevStyles from "../assets/PatchVirtualDevStyles.jsx";
|
|
5
6
|
const docType = ssr("<!DOCTYPE html>");
|
|
6
7
|
/**
|
|
7
8
|
*
|
|
@@ -16,6 +17,7 @@ export function StartServer(props) {
|
|
|
16
17
|
{docType}
|
|
17
18
|
<TopErrorBoundary>
|
|
18
19
|
<props.document scripts={<>
|
|
20
|
+
<PatchVirtualDevStyles nonce={nonce}/>
|
|
19
21
|
<script type="module" src={getSsrManifest("client").path(import.meta.env.START_CLIENT_ENTRY)}/>
|
|
20
22
|
</>}/>
|
|
21
23
|
</TopErrorBoundary>
|
package/package.json
CHANGED
package/src/config/dev-server.ts
CHANGED
|
@@ -11,6 +11,18 @@ export function devServer(): Array<PluginOption> {
|
|
|
11
11
|
return [
|
|
12
12
|
{
|
|
13
13
|
name: "solid-start-dev-server",
|
|
14
|
+
configurePreviewServer(server) {
|
|
15
|
+
return () => {
|
|
16
|
+
server.middlewares.use(async (req, res) => {
|
|
17
|
+
res.setHeader("content-encoding", "identity");
|
|
18
|
+
const webReq = new NodeRequest({ req, res });
|
|
19
|
+
const def: {
|
|
20
|
+
default: { fetch: (req: Request) => Promise<Response> };
|
|
21
|
+
} = await import(process.cwd() + "/dist/server/entry-server.js");
|
|
22
|
+
sendNodeResponse(res, await def.default.fetch(webReq));
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
},
|
|
14
26
|
configureServer(viteDevServer) {
|
|
15
27
|
(globalThis as any).VITE_DEV_SERVER = viteDevServer;
|
|
16
28
|
return async () => {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { init } from "es-module-lexer";
|
|
2
|
-
import { parse } from "es-module-lexer";
|
|
1
|
+
import { init, parse } from "es-module-lexer";
|
|
3
2
|
import esbuild from "esbuild";
|
|
4
3
|
import fg from "fast-glob";
|
|
5
4
|
import fs from "fs";
|
|
@@ -7,7 +6,7 @@ import micromatch from "micromatch";
|
|
|
7
6
|
import { posix } from "path";
|
|
8
7
|
import { pathToRegexp } from "path-to-regexp";
|
|
9
8
|
|
|
10
|
-
import {
|
|
9
|
+
import { normalizePath } from "vite";
|
|
11
10
|
|
|
12
11
|
export { pathToRegexp };
|
|
13
12
|
|
|
@@ -104,7 +103,7 @@ export class BaseFileSystemRouter extends EventTarget {
|
|
|
104
103
|
}
|
|
105
104
|
|
|
106
105
|
async addRoute(src: string) {
|
|
107
|
-
src =
|
|
106
|
+
src = normalizePath(src);
|
|
108
107
|
if (this.isRoute(src)) {
|
|
109
108
|
try {
|
|
110
109
|
const route = this.toRoute(src);
|
|
@@ -130,7 +129,7 @@ export class BaseFileSystemRouter extends EventTarget {
|
|
|
130
129
|
}
|
|
131
130
|
|
|
132
131
|
async updateRoute(src: string) {
|
|
133
|
-
src =
|
|
132
|
+
src = normalizePath(src);
|
|
134
133
|
if (this.isRoute(src)) {
|
|
135
134
|
try {
|
|
136
135
|
const route = this.toRoute(src);
|
|
@@ -146,7 +145,7 @@ export class BaseFileSystemRouter extends EventTarget {
|
|
|
146
145
|
}
|
|
147
146
|
|
|
148
147
|
removeRoute(src: string) {
|
|
149
|
-
src =
|
|
148
|
+
src = normalizePath(src);
|
|
150
149
|
if (this.isRoute(src)) {
|
|
151
150
|
const path = this.toPath(src);
|
|
152
151
|
if (path === undefined) {
|
package/src/config/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { TanStackServerFnPlugin } from "@tanstack/server-functions-plugin";
|
|
2
2
|
import { defu } from "defu";
|
|
3
3
|
import { globSync } from "node:fs";
|
|
4
|
-
import { extname, isAbsolute, join
|
|
4
|
+
import { extname, isAbsolute, join } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { type PluginOption } from "vite";
|
|
6
|
+
import { normalizePath, type PluginOption } from "vite";
|
|
7
7
|
import solid, { type Options as SolidOptions } from "vite-plugin-solid";
|
|
8
8
|
|
|
9
9
|
import { DEFAULT_EXTENSIONS, VIRTUAL_MODULES, VITE_ENVIRONMENTS } from "./constants.ts";
|
|
@@ -126,8 +126,10 @@ export function solidStart(options?: SolidStartOptions): Array<PluginOption> {
|
|
|
126
126
|
define: {
|
|
127
127
|
"import.meta.env.MANIFEST": `globalThis.MANIFEST`,
|
|
128
128
|
"import.meta.env.START_SSR": JSON.stringify(start.ssr),
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
// Use JSON.stringify so backslashes on Windows are escaped and
|
|
130
|
+
// esbuild receives a valid JS string literal for the define value
|
|
131
|
+
"import.meta.env.START_APP_ENTRY": JSON.stringify(appEntryPath),
|
|
132
|
+
"import.meta.env.START_CLIENT_ENTRY": JSON.stringify(handlers.client),
|
|
131
133
|
"import.meta.env.START_DEV_OVERLAY": JSON.stringify(start.devOverlay),
|
|
132
134
|
},
|
|
133
135
|
builder: {
|
|
@@ -173,8 +175,8 @@ export function solidStart(options?: SolidStartOptions): Array<PluginOption> {
|
|
|
173
175
|
envConsumer: "client",
|
|
174
176
|
envName: VITE_ENVIRONMENTS.client,
|
|
175
177
|
getRuntimeCode: () =>
|
|
176
|
-
`import { createServerReference } from "${
|
|
177
|
-
fileURLToPath(new URL("../server/server-runtime", import.meta.url))
|
|
178
|
+
`import { createServerReference } from "${normalizePath(
|
|
179
|
+
fileURLToPath(new URL("../server/server-runtime", import.meta.url))
|
|
178
180
|
)}"`,
|
|
179
181
|
replacer: opts => `createServerReference('${opts.functionId}')`,
|
|
180
182
|
},
|
|
@@ -182,8 +184,8 @@ export function solidStart(options?: SolidStartOptions): Array<PluginOption> {
|
|
|
182
184
|
envConsumer: "server",
|
|
183
185
|
envName: VITE_ENVIRONMENTS.server,
|
|
184
186
|
getRuntimeCode: () =>
|
|
185
|
-
`import { createServerReference } from '${
|
|
186
|
-
fileURLToPath(new URL("../server/server-fns-runtime", import.meta.url))
|
|
187
|
+
`import { createServerReference } from '${normalizePath(
|
|
188
|
+
fileURLToPath(new URL("../server/server-fns-runtime", import.meta.url))
|
|
187
189
|
)}'`,
|
|
188
190
|
replacer: opts => `createServerReference(${opts.fn}, '${opts.functionId}')`,
|
|
189
191
|
},
|
|
@@ -191,8 +193,8 @@ export function solidStart(options?: SolidStartOptions): Array<PluginOption> {
|
|
|
191
193
|
provider: {
|
|
192
194
|
envName: VITE_ENVIRONMENTS.server,
|
|
193
195
|
getRuntimeCode: () =>
|
|
194
|
-
`import { createServerReference } from '${
|
|
195
|
-
fileURLToPath(new URL("../server/server-fns-runtime", import.meta.url))
|
|
196
|
+
`import { createServerReference } from '${normalizePath(
|
|
197
|
+
fileURLToPath(new URL("../server/server-fns-runtime", import.meta.url))
|
|
196
198
|
)}'`,
|
|
197
199
|
replacer: opts => `createServerReference(${opts.fn}, '${opts.functionId}')`,
|
|
198
200
|
},
|
package/src/config/lazy.ts
CHANGED
|
@@ -48,13 +48,43 @@ const fileEndingRegex = /(ts|js)x(\?.*)?$/;
|
|
|
48
48
|
|
|
49
49
|
const lazy = (): PluginOption => {
|
|
50
50
|
const cwd = process.cwd().replaceAll(osSep, sep);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Maps module ids to their client-specific shared chunk names.
|
|
54
|
+
* Modules in shared chunks need to find their assets via the chunk name, instead of their module id.
|
|
55
|
+
*
|
|
56
|
+
* Vite includes assets of such modules in the manifest via the chunk name:
|
|
57
|
+
* https://github.com/vitejs/vite/blob/4be37a8389c67873880f826b01fe40137e1c29a7/packages/vite/src/node/plugins/manifest.ts#L179
|
|
58
|
+
* https://github.com/vitejs/vite/blob/4be37a8389c67873880f826b01fe40137e1c29a7/packages/vite/src/node/plugins/manifest.ts#L319
|
|
59
|
+
*
|
|
60
|
+
* Rollup occassionally creates shared chunks automatically,
|
|
61
|
+
* but they can also be manually created by the user via:
|
|
62
|
+
* https://rollupjs.org/configuration-options/#output-manualchunks
|
|
63
|
+
*
|
|
64
|
+
* More infos on Rollup's logic:
|
|
65
|
+
* https://github.com/rollup/rollup/issues/3772#issuecomment-689955168
|
|
66
|
+
*/
|
|
67
|
+
const sharedChunkNames: Record<string, string> = {};
|
|
68
|
+
|
|
51
69
|
return {
|
|
52
70
|
name: "solid-lazy-css",
|
|
53
71
|
enforce: "pre",
|
|
54
|
-
|
|
55
|
-
|
|
72
|
+
generateBundle(_, bundle) {
|
|
73
|
+
if (this.environment.name !== VITE_ENVIRONMENTS.client) return;
|
|
74
|
+
|
|
75
|
+
for (const chunk of Object.values(bundle)) {
|
|
76
|
+
if (chunk.type !== "chunk" || !chunk.isDynamicEntry || chunk.facadeModuleId) continue;
|
|
77
|
+
|
|
78
|
+
// Has to follow Vites implementation:
|
|
79
|
+
// https://github.com/vitejs/vite/blob/4be37a8389c67873880f826b01fe40137e1c29a7/packages/vite/src/node/plugins/manifest.ts#L179
|
|
80
|
+
const chunkName = `_${basename(chunk.fileName)}`;
|
|
81
|
+
for (const id of chunk.moduleIds) {
|
|
82
|
+
sharedChunkNames[id] = chunkName;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
56
85
|
},
|
|
57
86
|
async transform(src, id) {
|
|
87
|
+
if (this.environment.name !== VITE_ENVIRONMENTS.server) return;
|
|
58
88
|
if (!id.match(fileEndingRegex)) return;
|
|
59
89
|
|
|
60
90
|
// The transformed files either import "lazy" or css files
|
|
@@ -66,7 +96,8 @@ const lazy = (): PluginOption => {
|
|
|
66
96
|
const hasDefaultExport = src.indexOf("export default") !== -1;
|
|
67
97
|
if (hasDefaultExport) {
|
|
68
98
|
const localId = relative(cwd, id);
|
|
69
|
-
|
|
99
|
+
const chunkName = sharedChunkNames[id];
|
|
100
|
+
plugins.push(idTransform(chunkName ?? localId));
|
|
70
101
|
}
|
|
71
102
|
|
|
72
103
|
const hasLazy = src.indexOf("lazy(") !== -1;
|
package/src/config/manifest.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { type PluginOption, type ViteDevServer } from "vite";
|
|
|
3
3
|
import { findStylesInModuleGraph } from "../server/collect-styles.ts";
|
|
4
4
|
import { VIRTUAL_MODULES } from "./constants.ts";
|
|
5
5
|
import { type SolidStartOptions } from "./index.ts";
|
|
6
|
+
import { wrapId } from "./vite-utils.ts";
|
|
6
7
|
|
|
7
8
|
export function manifest(start: SolidStartOptions): PluginOption {
|
|
8
9
|
let devServer: ViteDevServer = undefined!;
|
|
@@ -69,10 +70,10 @@ export function manifest(start: SolidStartOptions): PluginOption {
|
|
|
69
70
|
tag: "style",
|
|
70
71
|
attrs: {
|
|
71
72
|
type: "text/css",
|
|
72
|
-
"data-vite-dev-id": "${key}",
|
|
73
|
+
"data-vite-dev-id": "${wrapId(key)}",
|
|
73
74
|
"data-vite-ref": "0",
|
|
74
75
|
},
|
|
75
|
-
children: () => import("${value}?inline").then(mod => mod.default),
|
|
76
|
+
children: () => import("${wrapId(value)}?inline").then(mod => mod.default),
|
|
76
77
|
}`,
|
|
77
78
|
);
|
|
78
79
|
|
package/src/config/vite-utils.ts
CHANGED
|
@@ -12,6 +12,7 @@ export const FS_PREFIX = `/@fs/`;
|
|
|
12
12
|
export const VALID_ID_PREFIX = `/@id/`;
|
|
13
13
|
|
|
14
14
|
export const NULL_BYTE_PLACEHOLDER = `__x00__`;
|
|
15
|
+
const NULL_BYTE_REGEX = /^\0/;
|
|
15
16
|
|
|
16
17
|
export function normalizeResolvedIdToUrl(
|
|
17
18
|
environment: DevEnvironment,
|
|
@@ -52,10 +53,13 @@ export function normalizeResolvedIdToUrl(
|
|
|
52
53
|
return url;
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Inspired by:
|
|
58
|
+
* https://github.com/withastro/astro/blob/fddde5fad81007795eb263c7fd0cea096b8e2cba/packages/astro/src/core/util.ts#L115
|
|
59
|
+
* https://github.com/vitejs/vite/blob/130e7181a55c524383c63bbfb1749d0ff7185cad/packages/vite/src/shared/utils.ts#L11
|
|
60
|
+
*/
|
|
55
61
|
export function wrapId(id: string): string {
|
|
56
|
-
return id.
|
|
57
|
-
? id
|
|
58
|
-
: VALID_ID_PREFIX + id.replace("\0", NULL_BYTE_PLACEHOLDER);
|
|
62
|
+
return id.replace(NULL_BYTE_REGEX, `${VALID_ID_PREFIX}${NULL_BYTE_PLACEHOLDER}`);
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
export function unwrapId(id: string): string {
|
package/src/middleware/index.ts
CHANGED
|
@@ -36,18 +36,21 @@ function wrapResponseMiddleware(onBeforeResponse: ResponseMiddleware): Middlewar
|
|
|
36
36
|
|
|
37
37
|
const fetchEvent = getFetchEvent(h3Event);
|
|
38
38
|
const mwResponse = await onBeforeResponse(fetchEvent, {
|
|
39
|
-
body:
|
|
39
|
+
body: resp,
|
|
40
40
|
});
|
|
41
41
|
if (mwResponse) return mwResponse;
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Creates middleware for handling requests and responses.
|
|
47
|
+
*
|
|
48
|
+
* @see https://docs.solidjs.com/solid-start/reference/server/create-middleware
|
|
49
|
+
*/
|
|
45
50
|
export function createMiddleware(
|
|
46
51
|
args:
|
|
47
52
|
| {
|
|
48
|
-
/** @deprecated Use H3 `Middleware` */
|
|
49
53
|
onRequest?: RequestMiddleware | RequestMiddleware[] | undefined;
|
|
50
|
-
/** @deprecated Use H3 `Middleware` */
|
|
51
54
|
onBeforeResponse?: ResponseMiddleware | ResponseMiddleware[] | undefined;
|
|
52
55
|
}
|
|
53
56
|
| Middleware[],
|
|
@@ -5,6 +5,7 @@ import App from "solid-start:app";
|
|
|
5
5
|
|
|
6
6
|
import { ErrorBoundary, TopErrorBoundary } from "../shared/ErrorBoundary.tsx";
|
|
7
7
|
import { useAssets } from "./assets/index.ts";
|
|
8
|
+
import PatchVirtualDevStyles from "./assets/PatchVirtualDevStyles.tsx";
|
|
8
9
|
import { getSsrManifest } from "./manifest/ssr-manifest.ts";
|
|
9
10
|
import type { DocumentComponentProps, PageEvent } from "./types.ts";
|
|
10
11
|
|
|
@@ -29,6 +30,7 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
|
|
|
29
30
|
assets={<HydrationScript />}
|
|
30
31
|
scripts={
|
|
31
32
|
<>
|
|
33
|
+
<PatchVirtualDevStyles nonce={nonce} />
|
|
32
34
|
<script
|
|
33
35
|
type="module"
|
|
34
36
|
nonce={nonce}
|
|
@@ -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;
|
|
@@ -1,30 +1,12 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { resolve } from "pathe";
|
|
3
2
|
import type { DevEnvironment, EnvironmentModuleNode } from "vite";
|
|
4
3
|
|
|
5
|
-
async function getViteModuleNode(vite: DevEnvironment, file: string) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (!resolvedId) return;
|
|
12
|
-
|
|
13
|
-
nodePath = resolvedId.id;
|
|
14
|
-
node = vite.moduleGraph.getModuleById(file);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (!node) {
|
|
18
|
-
nodePath = resolve(nodePath);
|
|
19
|
-
node = await vite.moduleGraph.getModuleByUrl(file);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (!node) {
|
|
23
|
-
await vite.moduleGraph.ensureEntryFromUrl(nodePath, false);
|
|
24
|
-
node = vite.moduleGraph.getModuleById(nodePath);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return node;
|
|
4
|
+
async function getViteModuleNode(vite: DevEnvironment, file: string, importer?: string) {
|
|
5
|
+
try {
|
|
6
|
+
const res = await vite.fetchModule(file, importer);
|
|
7
|
+
if (!("id" in res)) return;
|
|
8
|
+
return vite.moduleGraph.getModuleById(res.id);
|
|
9
|
+
} catch (err) {}
|
|
28
10
|
}
|
|
29
11
|
|
|
30
12
|
async function findModuleDependencies(
|
|
@@ -32,9 +14,10 @@ async function findModuleDependencies(
|
|
|
32
14
|
file: string,
|
|
33
15
|
deps: Set<EnvironmentModuleNode>,
|
|
34
16
|
crawledFiles = new Set<string>(),
|
|
17
|
+
importer?: string,
|
|
35
18
|
) {
|
|
36
19
|
crawledFiles.add(file);
|
|
37
|
-
const module = await getViteModuleNode(vite, file);
|
|
20
|
+
const module = await getViteModuleNode(vite, file, importer);
|
|
38
21
|
if (!module?.id || deps.has(module)) return;
|
|
39
22
|
|
|
40
23
|
deps.add(module);
|
|
@@ -53,7 +36,7 @@ async function findModuleDependencies(
|
|
|
53
36
|
if (crawledFiles.has(dep)) {
|
|
54
37
|
continue;
|
|
55
38
|
}
|
|
56
|
-
await findModuleDependencies(vite, dep, deps, crawledFiles);
|
|
39
|
+
await findModuleDependencies(vite, dep, deps, crawledFiles, module.id);
|
|
57
40
|
}
|
|
58
41
|
}
|
|
59
42
|
|
package/src/server/handler.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { getSsrManifest } from "../manifest/ssr-manifest.ts";
|
|
|
6
6
|
|
|
7
7
|
import { TopErrorBoundary } from "../../shared/ErrorBoundary.tsx";
|
|
8
8
|
import { useAssets } from "../assets/index.ts";
|
|
9
|
+
import PatchVirtualDevStyles from "../assets/PatchVirtualDevStyles.tsx";
|
|
9
10
|
import type { DocumentComponentProps, PageEvent } from "../types.ts";
|
|
10
11
|
|
|
11
12
|
const docType = ssr("<!DOCTYPE html>");
|
|
@@ -27,6 +28,7 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
|
|
|
27
28
|
<props.document
|
|
28
29
|
scripts={
|
|
29
30
|
<>
|
|
31
|
+
<PatchVirtualDevStyles nonce={nonce} />
|
|
30
32
|
<script
|
|
31
33
|
type="module"
|
|
32
34
|
src={getSsrManifest("client").path(import.meta.env.START_CLIENT_ENTRY)}
|