@solidjs/start 2.0.0-alpha.0 → 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.
Files changed (108) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/client/mount.d.ts +1 -7
  3. package/dist/client/mount.js +1 -99
  4. package/dist/config/constants.js +2 -2
  5. package/dist/config/dev-server.js +10 -0
  6. package/dist/config/fs-router.js +10 -22
  7. package/dist/config/fs-routes/fs-watcher.js +4 -4
  8. package/dist/config/fs-routes/index.js +4 -6
  9. package/dist/config/fs-routes/router.js +10 -11
  10. package/dist/config/fs-routes/tree-shake.js +12 -21
  11. package/dist/config/index.js +42 -42
  12. package/dist/config/lazy.js +42 -12
  13. package/dist/config/manifest.js +4 -3
  14. package/dist/config/vite-utils.d.ts +5 -0
  15. package/dist/config/vite-utils.js +7 -3
  16. package/dist/http/index.d.ts +1 -4
  17. package/dist/http/index.js +3 -5
  18. package/dist/index.d.ts +0 -1
  19. package/dist/middleware/index.d.ts +5 -2
  20. package/dist/middleware/index.js +6 -1
  21. package/dist/router.jsx +2 -2
  22. package/dist/server/StartServer.jsx +2 -0
  23. package/dist/server/assets/PatchVirtualDevStyles.d.ts +4 -0
  24. package/dist/server/assets/PatchVirtualDevStyles.jsx +28 -0
  25. package/dist/server/assets/index.js +1 -1
  26. package/dist/server/assets/render.jsx +2 -2
  27. package/dist/server/collect-styles.js +9 -21
  28. package/dist/server/fetchEvent.spec.js +1 -1
  29. package/dist/server/handler.js +30 -15
  30. package/dist/server/index.d.ts +1 -0
  31. package/dist/server/manifest/dev-client-manifest.js +1 -1
  32. package/dist/server/manifest/dev-ssr-manifest.js +1 -1
  33. package/dist/server/manifest/prod-ssr-manifest.js +7 -12
  34. package/dist/server/routes.js +3 -3
  35. package/dist/server/server-fns-runtime.js +2 -2
  36. package/dist/server/server-functions-handler.js +6 -11
  37. package/dist/server/server-runtime.js +8 -8
  38. package/dist/server/spa/StartServer.jsx +2 -0
  39. package/dist/shared/dev-overlay/CodeView.d.ts +1 -1
  40. package/dist/shared/dev-overlay/CodeView.jsx +23 -34
  41. package/dist/shared/dev-overlay/DevOverlayDialog.jsx +4 -4
  42. package/dist/shared/dev-overlay/get-source-map.d.ts +1 -1
  43. package/dist/shared/dev-overlay/get-source-map.js +5 -5
  44. package/dist/shared/dev-overlay/icons.d.ts +10 -10
  45. package/dist/shared/dev-overlay/icons.jsx +91 -91
  46. package/dist/shared/dev-overlay/index.jsx +1 -1
  47. package/dist/shared/lazy.js +4 -2
  48. package/env.d.ts +9 -0
  49. package/package.json +5 -4
  50. package/scripts/build.js +3 -3
  51. package/scripts/validate-imports.js +8 -8
  52. package/src/client/mount.ts +1 -114
  53. package/src/config/constants.ts +3 -3
  54. package/src/config/dev-server.ts +107 -99
  55. package/src/config/fs-router.ts +140 -155
  56. package/src/config/fs-routes/fs-watcher.ts +57 -61
  57. package/src/config/fs-routes/index.ts +117 -119
  58. package/src/config/fs-routes/router.ts +12 -13
  59. package/src/config/fs-routes/tree-shake.ts +342 -363
  60. package/src/config/index.ts +42 -43
  61. package/src/config/lazy.ts +47 -16
  62. package/src/config/manifest.ts +8 -7
  63. package/src/config/vite-utils.ts +9 -9
  64. package/src/env.d.ts +10 -28
  65. package/src/http/index.ts +105 -142
  66. package/src/index.tsx +0 -12
  67. package/src/internal.d.ts +1 -1
  68. package/src/middleware/index.ts +42 -49
  69. package/src/router.tsx +4 -3
  70. package/src/server/StartServer.tsx +3 -7
  71. package/src/server/assets/PatchVirtualDevStyles.tsx +31 -0
  72. package/src/server/assets/index.ts +1 -1
  73. package/src/server/assets/render.tsx +6 -2
  74. package/src/server/collect-styles.ts +49 -73
  75. package/src/server/fetchEvent.spec.ts +71 -75
  76. package/src/server/fetchEvent.ts +17 -17
  77. package/src/server/handler.ts +138 -129
  78. package/src/server/index.tsx +13 -0
  79. package/src/server/manifest/client-manifest.ts +1 -1
  80. package/src/server/manifest/dev-client-manifest.ts +7 -5
  81. package/src/server/manifest/dev-ssr-manifest.ts +8 -6
  82. package/src/server/manifest/prod-client-manifest.ts +7 -4
  83. package/src/server/manifest/prod-ssr-manifest.ts +78 -94
  84. package/src/server/manifest/ssr-manifest.ts +4 -2
  85. package/src/server/routes.ts +96 -108
  86. package/src/server/server-fns-runtime.ts +3 -3
  87. package/src/server/server-functions-handler.ts +294 -319
  88. package/src/server/server-runtime.ts +13 -13
  89. package/src/server/spa/StartServer.tsx +2 -0
  90. package/src/server/spa/handler.ts +12 -12
  91. package/src/server/types.ts +46 -46
  92. package/src/server/util.ts +4 -4
  93. package/src/shared/ErrorBoundary.tsx +1 -1
  94. package/src/shared/HttpHeader.tsx +20 -20
  95. package/src/shared/HttpStatusCode.ts +14 -14
  96. package/src/shared/clientOnly.ts +3 -3
  97. package/src/shared/dev-overlay/CodeView.tsx +43 -46
  98. package/src/shared/dev-overlay/DevOverlayDialog.tsx +4 -4
  99. package/src/shared/dev-overlay/createStackFrame.ts +59 -62
  100. package/src/shared/dev-overlay/env.d.ts +2 -2
  101. package/src/shared/dev-overlay/get-source-map.ts +5 -7
  102. package/src/shared/dev-overlay/icons.tsx +289 -121
  103. package/src/shared/dev-overlay/index.tsx +1 -1
  104. package/src/shared/lazy.ts +4 -3
  105. package/src/shared/serverFunction.ts +1 -1
  106. package/src/virtual.d.ts +10 -10
  107. package/tsconfig.json +2 -2
  108. package/vitest.config.ts +2 -2
@@ -10,89 +10,81 @@ import { decorateHandler, decorateMiddleware } from "./fetchEvent.ts";
10
10
  import { getSsrManifest } from "./manifest/ssr-manifest.ts";
11
11
  import { matchAPIRoute } from "./routes.ts";
12
12
  import { handleServerFunction } from "./server-functions-handler.ts";
13
- import type {
14
- APIEvent,
15
- FetchEvent,
16
- HandlerOptions,
17
- PageEvent,
18
- } from "./types.ts";
13
+ import type { APIEvent, FetchEvent, HandlerOptions, PageEvent } from "./types.ts";
19
14
  import { getExpectedRedirectStatus } from "./util.ts";
20
15
 
21
16
  const SERVER_FN_BASE = "/_server";
22
17
 
23
18
  export function createBaseHandler(
24
- createPageEvent: (e: FetchEvent) => Promise<PageEvent>,
25
- fn: (context: PageEvent) => JSX.Element,
26
- options:
27
- | HandlerOptions
28
- | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>) = {},
19
+ createPageEvent: (e: FetchEvent) => Promise<PageEvent>,
20
+ fn: (context: PageEvent) => JSX.Element,
21
+ options: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>) = {},
29
22
  ) {
30
- const handler = defineHandler({
31
- middleware: middleware.length ? middleware.map(decorateMiddleware): undefined,
32
- handler: decorateHandler(async (e: H3Event) => {
33
- const event = getRequestEvent()!;
34
- const url = new URL(event.request.url);
35
- const pathname = url.pathname;
23
+ const handler = defineHandler({
24
+ middleware: middleware.length ? middleware.map(decorateMiddleware) : undefined,
25
+ handler: decorateHandler(async (e: H3Event) => {
26
+ const event = getRequestEvent()!;
27
+ const url = new URL(event.request.url);
28
+ const pathname = stripBaseUrl(url.pathname);
36
29
 
37
- const serverFunctionTest = join(import.meta.env.BASE_URL, SERVER_FN_BASE);
38
- if (pathname.startsWith(serverFunctionTest)) {
39
- const serverFnResponse = await handleServerFunction(e);
30
+ if (pathname.startsWith(SERVER_FN_BASE)) {
31
+ const serverFnResponse = await handleServerFunction(e);
40
32
 
41
33
  if (serverFnResponse instanceof Response)
42
34
  return produceResponseWithEventHeaders(serverFnResponse);
43
35
 
44
- return new Response(serverFnResponse as any, {
45
- headers: e.res.headers,
46
- });
47
- }
48
-
49
- const match = matchAPIRoute(pathname, event.request.method);
50
- if (match) {
51
- const mod = await match.handler.import();
52
- const fn =
53
- event.request.method === "HEAD"
54
- ? mod["HEAD"] || mod["GET"]
55
- : mod[event.request.method];
56
- (event as APIEvent).params = match.params || {};
57
- // @ts-expect-error
58
- sharedConfig.context = { event };
59
- const res = await fn!(event);
36
+ return new Response(serverFnResponse as any, {
37
+ headers: e.res.headers,
38
+ });
39
+ }
40
+
41
+ const match = matchAPIRoute(pathname, event.request.method);
42
+ if (match) {
43
+ const mod = await match.handler.import();
44
+ const fn =
45
+ event.request.method === "HEAD" ? mod["HEAD"] || mod["GET"] : mod[event.request.method];
46
+ (event as APIEvent).params = match.params || {};
47
+ // @ts-expect-error
48
+ sharedConfig.context = { event };
49
+ const res = await fn!(event);
60
50
  if (res !== undefined) {
61
- if(res instanceof Response) return produceResponseWithEventHeaders(res)
51
+ if (res instanceof Response) return produceResponseWithEventHeaders(res);
62
52
 
63
53
  return res;
64
54
  }
65
- if (event.request.method !== "GET") {
66
- throw new Error(
67
- `API handler for ${event.request.method} "${event.request.url}" did not return a response.`,
68
- );
69
- }
70
- if (!match.isPage) return;
71
- }
72
-
73
- const context = await createPageEvent(event);
74
-
75
- const resolvedOptions =
76
- typeof options === "function" ? await options(context) : { ...options };
77
- const mode = resolvedOptions.mode || "stream";
78
- if (resolvedOptions.nonce) context.nonce = resolvedOptions.nonce;
79
-
80
- if (mode === "sync" || !import.meta.env.START_SSR) {
81
- const html = renderToString(() => {
82
- (sharedConfig.context as any).event = context;
83
- return fn(context);
84
- });
85
- context.complete = true;
86
-
87
- if (context.response && context.response.headers.get("Location")) {
55
+ if (event.request.method !== "GET") {
56
+ throw new Error(
57
+ `API handler for ${event.request.method} "${event.request.url}" did not return a response.`,
58
+ );
59
+ }
60
+ if (!match.isPage) return;
61
+ }
62
+
63
+ const context = await createPageEvent(event);
64
+
65
+ const resolvedOptions =
66
+ typeof options === "function" ? await options(context) : { ...options };
67
+ const mode = resolvedOptions.mode || "stream";
68
+ if (resolvedOptions.nonce) context.nonce = resolvedOptions.nonce;
69
+
70
+ if (mode === "sync" || !import.meta.env.START_SSR) {
71
+ const html = renderToString(() => {
72
+ (sharedConfig.context as any).event = context;
73
+ return fn(context);
74
+ }, resolvedOptions);
75
+ context.complete = true;
76
+
77
+ if (context.response && context.response.headers.get("Location")) {
88
78
  const status = getExpectedRedirectStatus(context.response);
89
79
  return redirect(context.response.headers.get("Location")!, status);
90
80
  }
91
81
 
92
- return html;
93
- }
82
+ event.response.headers.set("content-type", "text/html");
83
+
84
+ return html;
85
+ }
94
86
 
95
- if (resolvedOptions.onCompleteAll) {
87
+ if (resolvedOptions.onCompleteAll) {
96
88
  const og = resolvedOptions.onCompleteAll;
97
89
  resolvedOptions.onCompleteAll = options => {
98
90
  handleStreamCompleteRedirect(context)(options);
@@ -107,10 +99,10 @@ export function createBaseHandler(
107
99
  };
108
100
  } else resolvedOptions.onCompleteShell = handleShellCompleteRedirect(context, e);
109
101
 
110
- const _stream = renderToStream(() => {
111
- (sharedConfig.context as any).event = context;
112
- return fn(context);
113
- }, resolvedOptions);
102
+ const _stream = renderToStream(() => {
103
+ (sharedConfig.context as any).event = context;
104
+ return fn(context);
105
+ }, resolvedOptions);
114
106
  const stream = _stream as typeof _stream & PromiseLike<string>; // stream has a hidden 'then' method
115
107
 
116
108
  if (context.response && context.response.headers.get("Location")) {
@@ -118,48 +110,46 @@ export function createBaseHandler(
118
110
  return redirect(context.response.headers.get("Location")!, status);
119
111
  }
120
112
 
121
- if (mode === "async") return await stream
113
+ if (mode === "async") return await stream;
122
114
 
123
115
  delete (stream as any).then;
124
116
 
125
117
  // using TransformStream in dev can cause solid-start-dev-server to crash
126
118
  // when stream is cancelled
127
- if(globalThis.USING_SOLID_START_DEV_SERVER) return stream
119
+ if (globalThis.USING_SOLID_START_DEV_SERVER) return stream;
128
120
 
129
121
  // returning stream directly breaks cloudflare workers
130
122
  const { writable, readable } = new TransformStream();
131
123
  stream.pipeTo(writable);
132
- return readable
133
- }),
134
- });
124
+ return readable;
125
+ }),
126
+ });
135
127
 
136
- const app = new H3();
128
+ const app = new H3();
137
129
 
138
130
  app.use(handler);
139
131
 
140
- return app;
132
+ return app;
141
133
  }
142
134
 
143
135
  export function createHandler(
144
- fn: (context: PageEvent) => JSX.Element,
145
- options:
146
- | HandlerOptions
147
- | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>) = {},
136
+ fn: (context: PageEvent) => JSX.Element,
137
+ options: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>) = {},
148
138
  ) {
149
- return createBaseHandler(createPageEvent, fn, options);
139
+ return createBaseHandler(createPageEvent, fn, options);
150
140
  }
151
141
 
152
142
  export async function createPageEvent(ctx: FetchEvent) {
153
- ctx.response.headers.set("Content-Type", "text/html");
154
- // const prevPath = ctx.request.headers.get("x-solid-referrer");
155
- // const mutation = ctx.request.headers.get("x-solid-mutation") === "true";
156
- const manifest = getSsrManifest(import.meta.env.SSR && import.meta.env.DEV ? "ssr": "client");
143
+ ctx.response.headers.set("Content-Type", "text/html");
144
+ // const prevPath = ctx.request.headers.get("x-solid-referrer");
145
+ // const mutation = ctx.request.headers.get("x-solid-mutation") === "true";
146
+ const manifest = getSsrManifest(import.meta.env.SSR && import.meta.env.DEV ? "ssr" : "client");
157
147
 
158
- // Handle Vite build.cssCodeSplit
159
- // When build.cssCodeSplit is false, a single CSS file is generated with the key style.css
160
- const mergedCSS = import.meta.env.PROD ? await manifest.getAssets('style.css'): [];
148
+ // Handle Vite build.cssCodeSplit
149
+ // When build.cssCodeSplit is false, a single CSS file is generated with the key style.css
150
+ const mergedCSS = import.meta.env.PROD ? await manifest.getAssets("style.css") : [];
161
151
 
162
- const assets = [
152
+ const assets = [
163
153
  ...mergedCSS,
164
154
  ...(await manifest.getAssets(import.meta.env.START_CLIENT_ENTRY)),
165
155
  ...(await manifest.getAssets(import.meta.env.START_APP_ENTRY)),
@@ -169,52 +159,49 @@ export async function createPageEvent(ctx: FetchEvent) {
169
159
  // )
170
160
  // : [])
171
161
  ];
172
- const pageEvent: PageEvent = Object.assign(ctx, {
173
- assets,
174
- router: {
175
- submission: initFromFlash(ctx) as any,
176
- },
177
- routes: createRoutes(),
178
- // prevUrl: prevPath || "",
179
- // mutation: mutation,
180
- // $type: FETCH_EVENT,
181
- complete: false,
182
- $islands: new Set<string>(),
183
- });
184
-
185
- return pageEvent;
162
+ const pageEvent: PageEvent = Object.assign(ctx, {
163
+ assets,
164
+ router: {
165
+ submission: initFromFlash(ctx) as any,
166
+ },
167
+ routes: createRoutes(),
168
+ // prevUrl: prevPath || "",
169
+ // mutation: mutation,
170
+ // $type: FETCH_EVENT,
171
+ complete: false,
172
+ $islands: new Set<string>(),
173
+ });
174
+
175
+ return pageEvent;
186
176
  }
187
177
 
188
178
  function initFromFlash(ctx: FetchEvent) {
189
- const flash = getCookie(ctx.nativeEvent, "flash");
190
- if (!flash) return;
191
- try {
192
- const param = JSON.parse(flash);
193
- if (!param || !param.result) return;
194
- const input = [
195
- ...param.input.slice(0, -1),
196
- new Map(param.input[param.input.length - 1]),
197
- ];
198
- const result = param.error ? new Error(param.result) : param.result;
199
- return {
200
- input,
201
- url: param.url,
202
- pending: false,
203
- result: param.thrown ? undefined : result,
204
- error: param.thrown ? result : undefined,
205
- };
206
- } catch (e) {
207
- console.error(e);
208
- } finally {
209
- setCookie(ctx.nativeEvent, "flash", "", { maxAge: 0 });
210
- }
179
+ const flash = getCookie(ctx.nativeEvent, "flash");
180
+ if (!flash) return;
181
+ try {
182
+ const param = JSON.parse(flash);
183
+ if (!param || !param.result) return;
184
+ const input = [...param.input.slice(0, -1), new Map(param.input[param.input.length - 1])];
185
+ const result = param.error ? new Error(param.result) : param.result;
186
+ return {
187
+ input,
188
+ url: param.url,
189
+ pending: false,
190
+ result: param.thrown ? undefined : result,
191
+ error: param.thrown ? result : undefined,
192
+ };
193
+ } catch (e) {
194
+ console.error(e);
195
+ } finally {
196
+ setCookie(ctx.nativeEvent, "flash", "", { maxAge: 0 });
197
+ }
211
198
  }
212
199
 
213
200
  function handleShellCompleteRedirect(context: PageEvent, e: H3Event) {
214
201
  return () => {
215
202
  if (context.response && context.response.headers.get("Location")) {
216
203
  const status = getExpectedRedirectStatus(context.response);
217
- e.res.status = status
204
+ e.res.status = status;
218
205
  e.res.headers.set("Location", context.response.headers.get("Location")!);
219
206
  }
220
207
  };
@@ -234,17 +221,39 @@ function produceResponseWithEventHeaders(res: Response) {
234
221
  let ret = res;
235
222
 
236
223
  // Response.redirect returns an immutable value, so we clone on any redirect just in case
237
- if(300 <= res.status && res.status < 400) {
224
+ if (300 <= res.status && res.status < 400) {
225
+ const cookies = res.headers.getSetCookie?.() ?? [];
226
+ const headers = new Headers();
227
+ res.headers.forEach((value, key) => {
228
+ if (key.toLowerCase() !== "set-cookie") {
229
+ headers.set(key, value);
230
+ }
231
+ });
232
+ for (const cookie of cookies) {
233
+ headers.append("Set-Cookie", cookie);
234
+ }
238
235
  ret = new Response(res.body, {
239
236
  status: res.status,
240
237
  statusText: res.statusText,
241
- headers: Object.fromEntries(res.headers.entries())
238
+ headers,
242
239
  });
243
240
  }
244
241
 
245
- for(const [name, value] of event.response.headers) {
246
- ret.headers.set(name, value);
242
+ const eventCookies = event.response.headers.getSetCookie?.() ?? [];
243
+ for (const cookie of eventCookies) {
244
+ ret.headers.append("Set-Cookie", cookie);
247
245
  }
248
246
 
249
- return ret
247
+ for (const [name, value] of event.response.headers) {
248
+ if (name.toLowerCase() !== "set-cookie") {
249
+ ret.headers.set(name, value);
250
+ }
251
+ }
252
+
253
+ return ret;
254
+ }
255
+
256
+ function stripBaseUrl(path: string) {
257
+ if (import.meta.env.BASE_URL === "/" || import.meta.env.BASE_URL === "") return path;
258
+ return path.slice(import.meta.env.BASE_URL.length);
250
259
  }
@@ -3,6 +3,19 @@ export { getServerFunctionMeta } from "../shared/serverFunction.ts";
3
3
  export { StartServer } from "./StartServer.tsx";
4
4
  export { createHandler } from "./handler.ts";
5
5
 
6
+ export type {
7
+ APIEvent,
8
+ APIHandler,
9
+ Asset,
10
+ ContextMatches,
11
+ DocumentComponentProps,
12
+ FetchEvent,
13
+ HandlerOptions,
14
+ PageEvent,
15
+ ResponseStub,
16
+ ServerFunctionMeta,
17
+ } from "./types.ts";
18
+
6
19
  /**
7
20
  * Checks if user has set a redirect status in the response.
8
21
  * If not, falls back to the 302 (temporary redirect)
@@ -2,7 +2,7 @@ import { getClientDevManifest } from "./dev-client-manifest.ts";
2
2
  import { getClientProdManifest } from "./prod-client-manifest.ts";
3
3
 
4
4
  export function getClientManifest() {
5
- return import.meta.env.DEV ? getClientDevManifest() : getClientProdManifest();
5
+ return import.meta.env.DEV ? getClientDevManifest() : getClientProdManifest();
6
6
  }
7
7
 
8
8
  export { getClientManifest as getManifest };
@@ -3,17 +3,19 @@ import { join } from "pathe";
3
3
  export function getClientDevManifest() {
4
4
  return {
5
5
  import(id) {
6
- return import(/* @vite-ignore */ join("/", id))
6
+ return import(/* @vite-ignore */ join("/", id));
7
7
  },
8
8
  async getAssets(id) {
9
9
  const assetsPath = `/@manifest/client/${Date.now()}/assets?id=${id}`;
10
10
 
11
11
  const assets = (await import(/* @vite-ignore */ assetsPath)).default;
12
12
 
13
- return await Promise.all(assets.map(async (v: any) => ({
14
- ...v,
15
- children: await v.children()
16
- })));
13
+ return await Promise.all(
14
+ assets.map(async (v: any) => ({
15
+ ...v,
16
+ children: await v.children(),
17
+ })),
18
+ );
17
19
  },
18
20
  } satisfies StartManifest & { import(id: string): Promise<any> };
19
21
  }
@@ -8,14 +8,16 @@ export function getSsrDevManifest(environment: "client" | "ssr") {
8
8
 
9
9
  const assets = (await import(/* @vite-ignore */ assetsPath)).default;
10
10
 
11
- return await Promise.all(assets.map(async (v: any) => ({
12
- ...v,
13
- children: await v.children()
14
- })));
11
+ return await Promise.all(
12
+ assets.map(async (v: any) => ({
13
+ ...v,
14
+ children: await v.children(),
15
+ })),
16
+ );
15
17
  },
16
18
  } satisfies StartManifest & {
17
- path(id: string): string;
18
- };
19
+ path(id: string): string;
20
+ };
19
21
  }
20
22
 
21
23
  export { getSsrDevManifest as getSsrManifest };
@@ -2,17 +2,20 @@ export function getClientProdManifest() {
2
2
  return {
3
3
  import(id) {
4
4
  // @ts-ignore
5
- return import(/* @vite-ignore */ window.manifest[id].output)
5
+ return import(/* @vite-ignore */ window.manifest[id].output);
6
6
  },
7
7
  async getAssets(id) {
8
8
  if (id.startsWith("./")) id = id.slice(2);
9
9
 
10
10
  // @ts-ignore
11
- return window.manifest[id]?.assets ?? []
11
+ return window.manifest[id]?.assets ?? [];
12
12
  },
13
13
  async json() {
14
14
  // @ts-ignore
15
- return window.manifest
15
+ return window.manifest;
16
16
  },
17
- } satisfies StartManifest & { json(): Promise<Record<string, any>>, import(id: string): Promise<any>; }
17
+ } satisfies StartManifest & {
18
+ json(): Promise<Record<string, any>>;
19
+ import(id: string): Promise<any>;
20
+ };
18
21
  }
@@ -5,121 +5,105 @@ import type { Asset } from "../assets/render.tsx";
5
5
 
6
6
  // Only reads from client manifest atm, might need server support for islands
7
7
  export function getSsrProdManifest() {
8
- const viteManifest = clientViteManifest;
9
- return {
10
- path(id: string) {
8
+ const viteManifest = clientViteManifest;
9
+ return {
10
+ path(id: string) {
11
11
  if (id.startsWith("./")) id = id.slice(2);
12
12
 
13
- const viteManifestEntry =
14
- clientViteManifest[id /*import.meta.env.START_CLIENT_ENTRY*/];
15
- if (!viteManifestEntry)
16
- throw new Error(`No entry found in vite manifest for '${id}'`);
13
+ const viteManifestEntry = clientViteManifest[id /*import.meta.env.START_CLIENT_ENTRY*/];
14
+ if (!viteManifestEntry) throw new Error(`No entry found in vite manifest for '${id}'`);
17
15
 
18
- return join("/", viteManifestEntry.file);
19
- },
20
- async getAssets(id) {
16
+ return join("/", viteManifestEntry.file);
17
+ },
18
+ async getAssets(id) {
21
19
  if (id.startsWith("./")) id = id.slice(2);
22
20
 
23
- return createHtmlTagsForAssets(
24
- findAssetsInViteManifest(clientViteManifest, id),
25
- );
26
- },
27
- async json() {
28
- const json: Record<string, any> = {};
21
+ return createHtmlTagsForAssets(findAssetsInViteManifest(clientViteManifest, id));
22
+ },
23
+ async json() {
24
+ const json: Record<string, any> = {};
29
25
 
30
- const entryKeys = Object.keys(viteManifest)
31
- .filter((id) => viteManifest[id]?.isEntry || viteManifest[id]?.isDynamicEntry)
32
- .map((id) => id);
26
+ const entryKeys = Object.keys(viteManifest)
27
+ .filter(id => viteManifest[id]?.isEntry || viteManifest[id]?.isDynamicEntry)
28
+ .map(id => id);
33
29
 
34
- for (const entryKey of entryKeys) {
35
- json[entryKey] = {
36
- output: join("/", viteManifest[entryKey]!.file),
37
- assets: await this.getAssets(entryKey),
38
- };
39
- }
30
+ for (const entryKey of entryKeys) {
31
+ json[entryKey] = {
32
+ output: join("/", viteManifest[entryKey]!.file),
33
+ assets: await this.getAssets(entryKey),
34
+ };
35
+ }
40
36
 
41
- return json;
42
- },
43
- } satisfies StartManifest & {
44
- json(): Promise<Record<string, any>>;
45
- path(id: string): string;
46
- };
37
+ return json;
38
+ },
39
+ } satisfies StartManifest & {
40
+ json(): Promise<Record<string, any>>;
41
+ path(id: string): string;
42
+ };
47
43
  }
48
44
 
49
45
  function createHtmlTagsForAssets(assets: string[]) {
50
- return assets
51
- .filter(
52
- (asset) =>
53
- asset.endsWith(".css") ||
54
- asset.endsWith(".js") ||
55
- asset.endsWith(".ts") ||
56
- asset.endsWith(".mjs"),
57
- )
58
- .map<Asset>((asset) => ({
59
- tag: "link",
60
- attrs: {
61
- href: '/' + asset,
62
- key: asset,
63
- ...(asset.endsWith(".css")
64
- ? { rel: "stylesheet" }
65
- : { rel: "modulepreload" }),
66
- },
67
- }));
46
+ return assets
47
+ .filter(
48
+ asset =>
49
+ asset.endsWith(".css") ||
50
+ asset.endsWith(".js") ||
51
+ asset.endsWith(".ts") ||
52
+ asset.endsWith(".mjs"),
53
+ )
54
+ .map<Asset>(asset => ({
55
+ tag: "link",
56
+ attrs: {
57
+ href: "/" + asset,
58
+ key: asset,
59
+ ...(asset.endsWith(".css") ? { rel: "stylesheet" } : { rel: "modulepreload" }),
60
+ },
61
+ }));
68
62
  }
69
63
 
70
64
  const entryId = import.meta.env.START_CLIENT_ENTRY.slice(2);
71
65
  let entryImports: string[] | undefined = undefined;
72
66
 
73
67
  function findAssetsInViteManifest(
74
- manifest: Manifest,
75
- id: string,
76
- assetMap = new Map(),
77
- stack: string[] = [],
68
+ manifest: Manifest,
69
+ id: string,
70
+ assetMap = new Map(),
71
+ stack: string[] = [],
78
72
  ) {
79
- if (stack.includes(id)) {
80
- return [];
81
- }
73
+ if (stack.includes(id)) {
74
+ return [];
75
+ }
82
76
 
83
- const cached = assetMap.get(id);
84
- if (cached) {
85
- return cached;
86
- }
87
- const chunk = manifest[id];
88
- if (!chunk) {
89
- return [];
90
- }
77
+ const cached = assetMap.get(id);
78
+ if (cached) {
79
+ return cached;
80
+ }
81
+ const chunk = manifest[id];
82
+ if (!chunk) {
83
+ return [];
84
+ }
91
85
 
92
- if (!entryImports) {
93
- entryImports = [
94
- entryId,
95
- ...(manifest[entryId]?.imports ?? [])
96
- ];
97
- }
86
+ if (!entryImports) {
87
+ entryImports = [entryId, ...(manifest[entryId]?.imports ?? [])];
88
+ }
98
89
 
99
- // Only include entry imports, if we are specifically crawling the entry
100
- // Chunks (e.g. routes) that import something from entry, should not render entry css redundantly
101
- const excludeEntryImports = id !== entryId;
90
+ // Only include entry imports, if we are specifically crawling the entry
91
+ // Chunks (e.g. routes) that import something from entry, should not render entry css redundantly
92
+ const excludeEntryImports = id !== entryId;
102
93
 
103
- const assets = chunk.css?.filter(Boolean) || [];
104
- if (chunk.imports) {
105
- stack.push(id);
106
- for (let i = 0, l = chunk.imports.length; i < l; i++) {
107
- const importId = chunk.imports[i];
108
- if (!importId || (excludeEntryImports && entryImports.includes(importId))) continue;
109
- assets.push(
110
- ...findAssetsInViteManifest(
111
- manifest,
112
- importId,
113
- assetMap,
114
- stack,
115
- ),
116
- );
117
- }
118
- stack.pop();
119
- }
120
- assets.push(chunk.file);
121
- const all = Array.from(new Set(assets));
122
- assetMap.set(id, all);
94
+ const assets = chunk.css?.filter(Boolean) || [];
95
+ if (chunk.imports) {
96
+ stack.push(id);
97
+ for (let i = 0, l = chunk.imports.length; i < l; i++) {
98
+ const importId = chunk.imports[i];
99
+ if (!importId || (excludeEntryImports && entryImports.includes(importId))) continue;
100
+ assets.push(...findAssetsInViteManifest(manifest, importId, assetMap, stack));
101
+ }
102
+ stack.pop();
103
+ }
104
+ assets.push(chunk.file);
105
+ const all = Array.from(new Set(assets));
106
+ assetMap.set(id, all);
123
107
 
124
- return all;
108
+ return all;
125
109
  }