@solidjs/start 0.5.9 → 0.6.0

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/config/index.d.ts CHANGED
@@ -1,24 +1,19 @@
1
- import { AppOptions } from "vinxi";
2
- import { InlineConfig } from "vite";
1
+ import type { AppOptions } from "vinxi";
2
+ import type { CustomizableConfig } from "vinxi/dist/types/lib/vite-dev";
3
3
  import type { Options } from "vite-plugin-solid";
4
4
 
5
+ type SolidStartInlineConfig = {
6
+ ssr?: boolean;
7
+ solid?: Options;
8
+ extensions?: string[];
9
+ server?: AppOptions["server"];
10
+ appRoot?: string;
11
+ middleware?: string;
12
+ islands?: boolean;
13
+ devOverlay?: boolean;
14
+ vite?:
15
+ | CustomizableConfig
16
+ | ((options: { router: "server" | "client" | "server-function" }) => CustomizableConfig);
17
+ };
5
18
 
6
- type SolidStartInlineConfig = Omit<InlineConfig, "router"> & {
7
- start?: {
8
- /**
9
- * true: streaming mode
10
- * false: csr only
11
- * async: ssr is in async mode
12
- * sync: ssr is in sync mode
13
- */
14
- ssr?: boolean | "async" | "sync",
15
- solid?: Options,
16
- extensions?: string[],
17
- server?: AppOptions['server'],
18
- appRoot?: string,
19
- middleware?: string,
20
- islands?: boolean
21
- }
22
- }
23
-
24
- export declare function defineConfig(baseConfig?: SolidStartInlineConfig)
19
+ export declare function defineConfig(baseConfig?: SolidStartInlineConfig): any;
package/config/index.js CHANGED
@@ -38,11 +38,12 @@ function solidStartServerFsRouter(config) {
38
38
  }
39
39
 
40
40
  export function defineConfig(baseConfig = {}) {
41
- let { plugins = [], start = {}, ...userConfig } = baseConfig;
41
+ let { vite = {}, ...start } = baseConfig;
42
42
  const extensions = [...DEFAULT_EXTENSIONS, ...(start.extensions || [])];
43
43
  start = defu(start, {
44
44
  appRoot: "./src",
45
45
  ssr: true,
46
+ devOverlay: true,
46
47
  islands: false,
47
48
  solid: {},
48
49
  server: {
@@ -71,8 +72,8 @@ export function defineConfig(baseConfig = {}) {
71
72
  {
72
73
  name: "public",
73
74
  type: "static",
74
- dir: "./public",
75
- base: "/"
75
+ base: "/",
76
+ dir: "./public"
76
77
  },
77
78
  {
78
79
  name: "ssr",
@@ -85,51 +86,57 @@ export function defineConfig(baseConfig = {}) {
85
86
  routes: solidStartServerFsRouter({ dir: `${start.appRoot}/routes`, extensions }),
86
87
  extensions,
87
88
  target: "server",
88
- plugins: async () => [
89
- config("user", {
90
- ...userConfig,
91
- optimizeDeps: {
92
- ...(userConfig.optimizeDeps || {}),
93
- include: [
94
- ...(userConfig.optimizeDeps?.include || []),
95
- "@solidjs/start > source-map-js",
96
- "@solidjs/start > error-stack-parser"
97
- ]
98
- }
99
- }),
100
- ...(typeof plugins === "function" ? [...(await plugins())] : plugins),
101
-
102
- serverTransform({
103
- runtime: normalize(fileURLToPath(new URL("./server-fns-runtime.ts", import.meta.url)))
104
- }),
105
- start.islands ? serverComponents.server() : null,
106
- solid({ ...start.solid, ssr: true, extensions: extensions.map(ext => `.${ext}`) }),
107
- config("app-server", {
108
- resolve: {
109
- alias: {
110
- "#start/app": join(process.cwd(), start.appRoot, `app${entryExtension}`),
111
- "~": join(process.cwd(), start.appRoot),
112
- ...(!start.ssr
113
- ? {
114
- "@solidjs/start/server": "@solidjs/start/server/spa"
115
- }
116
- : {}),
117
- ...userConfig.resolve?.alias
89
+ plugins: async () => {
90
+ const userConfig = typeof vite === "function" ? await vite({ router: "server" }) : { ...vite };
91
+ const plugins = userConfig.plugins || [];
92
+ delete userConfig.plugins;
93
+ return [
94
+ config("user", {
95
+ ...userConfig,
96
+ optimizeDeps: {
97
+ ...(userConfig.optimizeDeps || {}),
98
+ include: [
99
+ ...(userConfig.optimizeDeps?.include || []),
100
+ "@solidjs/start > source-map-js",
101
+ "@solidjs/start > error-stack-parser"
102
+ ]
118
103
  }
119
- },
120
- cacheDir: "node_modules/.vinxi/server",
121
- define: {
122
- "import.meta.env.START_ISLANDS": JSON.stringify(start.islands),
123
- "import.meta.env.SSR": JSON.stringify(true),
124
- "import.meta.env.START_SSR": JSON.stringify(start.ssr),
125
- ...userConfig.define
126
- }
127
- })
128
- ]
104
+ }),
105
+ ...plugins,
106
+ serverTransform({
107
+ runtime: normalize(fileURLToPath(new URL("./server-fns-runtime.ts", import.meta.url)))
108
+ }),
109
+ start.islands ? serverComponents.server() : null,
110
+ solid({ ...start.solid, ssr: true, extensions: extensions.map(ext => `.${ext}`) }),
111
+ config("app-server", {
112
+ resolve: {
113
+ alias: {
114
+ "#start/app": join(process.cwd(), start.appRoot, `app${entryExtension}`),
115
+ "~": join(process.cwd(), start.appRoot),
116
+ ...(!start.ssr
117
+ ? {
118
+ "@solidjs/start/server": "@solidjs/start/server/spa"
119
+ }
120
+ : {}),
121
+ ...userConfig.resolve?.alias
122
+ }
123
+ },
124
+ cacheDir: "node_modules/.vinxi/server",
125
+ define: {
126
+ "import.meta.env.START_ISLANDS": JSON.stringify(start.islands),
127
+ "import.meta.env.SSR": JSON.stringify(true),
128
+ "import.meta.env.START_SSR": JSON.stringify(start.ssr),
129
+ "import.meta.env.START_DEV_OVERLAY": JSON.stringify(start.devOverlay),
130
+ ...userConfig.define
131
+ }
132
+ })
133
+ ];
134
+ }
129
135
  },
130
136
  {
131
137
  name: "client",
132
138
  type: "client",
139
+ base: "/_build",
133
140
  handler: `${start.appRoot}/entry-client${entryExtension}`,
134
141
  ...(start.islands
135
142
  ? {}
@@ -138,53 +145,58 @@ export function defineConfig(baseConfig = {}) {
138
145
  }),
139
146
  extensions,
140
147
  target: "browser",
141
- plugins: async () => [
142
- config("user", {
143
- ...userConfig,
144
- optimizeDeps: {
145
- ...(userConfig.optimizeDeps || {}),
146
- include: [
147
- ...(userConfig.optimizeDeps?.include || []),
148
- "@solidjs/start > source-map-js",
149
- "@solidjs/start > error-stack-parser"
150
- ]
151
- }
152
- }),
153
- ...(typeof plugins === "function" ? [...(await plugins())] : plugins),
154
- serverFunctions.client({
155
- runtime: normalize(fileURLToPath(new URL("./server-runtime.ts", import.meta.url)))
156
- }),
157
- start.islands ? serverComponents.client() : null,
158
- solid({ ...start.solid, ssr: start.ssr, extensions: extensions.map(ext => `.${ext}`) }),
159
- config("app-client", {
160
- resolve: {
161
- alias: {
162
- "#start/app": join(process.cwd(), start.appRoot, `app${entryExtension}`),
163
- "~": join(process.cwd(), start.appRoot),
164
- ...(start.islands
165
- ? {
166
- "@solidjs/start/client": "@solidjs/start/client/islands"
167
- }
168
- : {}),
169
- ...(!start.ssr
170
- ? {
171
- "@solidjs/start/client": "@solidjs/start/client/spa"
172
- }
173
- : {}),
174
- ...userConfig.resolve?.alias
148
+ plugins: async () => {
149
+ const userConfig = typeof vite === "function" ? await vite({ router: "client" }) : { ...vite };
150
+ const plugins = userConfig.plugins || [];
151
+ delete userConfig.plugins;
152
+ return [
153
+ config("user", {
154
+ ...userConfig,
155
+ optimizeDeps: {
156
+ ...(userConfig.optimizeDeps || {}),
157
+ include: [
158
+ ...(userConfig.optimizeDeps?.include || []),
159
+ "@solidjs/start > source-map-js",
160
+ "@solidjs/start > error-stack-parser"
161
+ ]
162
+ }
163
+ }),
164
+ ...plugins,
165
+ serverFunctions.client({
166
+ runtime: normalize(fileURLToPath(new URL("./server-runtime.ts", import.meta.url)))
167
+ }),
168
+ start.islands ? serverComponents.client() : null,
169
+ solid({ ...start.solid, ssr: start.ssr, extensions: extensions.map(ext => `.${ext}`) }),
170
+ config("app-client", {
171
+ resolve: {
172
+ alias: {
173
+ "#start/app": join(process.cwd(), start.appRoot, `app${entryExtension}`),
174
+ "~": join(process.cwd(), start.appRoot),
175
+ ...(start.islands
176
+ ? {
177
+ "@solidjs/start/client": "@solidjs/start/client/islands"
178
+ }
179
+ : {}),
180
+ ...(!start.ssr
181
+ ? {
182
+ "@solidjs/start/client": "@solidjs/start/client/spa"
183
+ }
184
+ : {}),
185
+ ...userConfig.resolve?.alias
186
+ }
187
+ },
188
+ cacheDir: "node_modules/.vinxi/client",
189
+ define: {
190
+ "import.meta.env.START_ISLANDS": JSON.stringify(start.islands),
191
+ "import.meta.env.SSR": JSON.stringify(false),
192
+ "import.meta.env.START_SSR": JSON.stringify(start.ssr),
193
+ "import.meta.env.START_DEV_OVERLAY": JSON.stringify(start.devOverlay),
194
+ "import.meta.env.SERVER_BASE_URL": JSON.stringify(server?.baseURL ?? ""),
195
+ ...userConfig.define
175
196
  }
176
- },
177
- cacheDir: "node_modules/.vinxi/client",
178
- define: {
179
- "import.meta.env.START_ISLANDS": JSON.stringify(start.islands),
180
- "import.meta.env.SSR": JSON.stringify(false),
181
- "import.meta.env.START_SSR": JSON.stringify(start.ssr),
182
- "import.meta.env.SERVER_BASE_URL": JSON.stringify(server?.baseURL ?? ""),
183
- ...userConfig.define
184
- }
185
- })
186
- ],
187
- base: "/_build"
197
+ })
198
+ ];
199
+ }
188
200
  },
189
201
 
190
202
  {
@@ -192,48 +204,54 @@ export function defineConfig(baseConfig = {}) {
192
204
  type: "http",
193
205
  base: "/_server",
194
206
  handler: normalize(fileURLToPath(new URL("./server-handler.ts", import.meta.url))),
207
+ middleware: start.middleware,
195
208
  target: "server",
196
209
  routes: solidStartServerFsRouter({ dir: `${start.appRoot}/routes`, extensions }),
197
- plugins: async () => [
198
- config("user", {
199
- ...userConfig,
200
- optimizeDeps: {
201
- ...(userConfig.optimizeDeps || {}),
202
- include: [
203
- ...(userConfig.optimizeDeps?.include || []),
204
- "@solidjs/start > source-map-js",
205
- "@solidjs/start > error-stack-parser"
206
- ]
207
- },
208
- cacheDir: "node_modules/.vinxi/server-fns"
209
- }),
210
- ...(typeof plugins === "function" ? [...(await plugins())] : plugins),
211
- serverFunctionServer({
212
- runtime: normalize(fileURLToPath(new URL("./server-fns-runtime.ts", import.meta.url)))
213
- }),
214
- solid({ ...start.solid, ssr: true, extensions: extensions.map(ext => `.${ext}`) }),
215
- config("app-server", {
216
- resolve: {
217
- alias: {
218
- "#start/app": join(process.cwd(), start.appRoot, `app${entryExtension}`),
219
- "~": join(process.cwd(), start.appRoot),
220
- ...(!start.ssr
221
- ? {
222
- "@solidjs/start/server": "@solidjs/start/server/spa"
223
- }
224
- : {}),
225
- ...userConfig.resolve?.alias
210
+ plugins: async () => {
211
+ const userConfig = typeof vite === "function" ? await vite({ router: "server-function" }) : { ...vite };
212
+ const plugins = userConfig.plugins || [];
213
+ delete userConfig.plugins;
214
+ return [
215
+ config("user", {
216
+ ...userConfig,
217
+ optimizeDeps: {
218
+ ...(userConfig.optimizeDeps || {}),
219
+ include: [
220
+ ...(userConfig.optimizeDeps?.include || []),
221
+ "@solidjs/start > source-map-js",
222
+ "@solidjs/start > error-stack-parser"
223
+ ]
224
+ },
225
+ cacheDir: "node_modules/.vinxi/server-fns"
226
+ }),
227
+ ...plugins,
228
+ serverFunctionServer({
229
+ runtime: normalize(fileURLToPath(new URL("./server-fns-runtime.ts", import.meta.url)))
230
+ }),
231
+ solid({ ...start.solid, ssr: true, extensions: extensions.map(ext => `.${ext}`) }),
232
+ config("app-server", {
233
+ resolve: {
234
+ alias: {
235
+ "#start/app": join(process.cwd(), start.appRoot, `app${entryExtension}`),
236
+ "~": join(process.cwd(), start.appRoot),
237
+ ...(!start.ssr
238
+ ? {
239
+ "@solidjs/start/server": "@solidjs/start/server/spa"
240
+ }
241
+ : {}),
242
+ ...userConfig.resolve?.alias
243
+ }
244
+ },
245
+ define: {
246
+ "import.meta.env.START_ISLANDS": JSON.stringify(start.islands),
247
+ "import.meta.env.SSR": JSON.stringify(true),
248
+ "import.meta.env.START_SSR": JSON.stringify(start.ssr),
249
+ "import.meta.env.START_DEV_OVERLAY": JSON.stringify(start.devOverlay),
250
+ ...userConfig.define
226
251
  }
227
- },
228
- define: {
229
- "import.meta.env.START_ISLANDS": JSON.stringify(start.islands),
230
- "import.meta.env.SSR": JSON.stringify(true),
231
- "import.meta.env.START_SSR": JSON.stringify(start.ssr),
232
- ...userConfig.define
233
- }
234
- })
235
- ],
236
- middleware: start.middleware
252
+ })
253
+ ];
254
+ }
237
255
  }
238
256
  ]
239
257
  });
@@ -8,7 +8,7 @@ export function createServerReference(fn: Function, id: string, name: string) {
8
8
  return new Proxy(fn, {
9
9
  get(target, prop, receiver) {
10
10
  if (prop === "url") {
11
- return `${baseURL}/_server/?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}`;
11
+ return `${baseURL}/_server?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}`;
12
12
  }
13
13
  if (prop === "GET") return receiver;
14
14
  },
@@ -150,11 +150,17 @@ async function handleServerFunction(h3Event: H3Event) {
150
150
  // handle no JS success case
151
151
  if (!instance) {
152
152
  const isError = result instanceof Error;
153
- const refererUrl = new URL(request.headers.get("referer")!);
153
+ let redirectUrl = new URL(request.headers.get("referer")!).toString();
154
+ if (result instanceof Response && result.headers.has("Location")) {
155
+ redirectUrl = new URL(
156
+ result.headers.get("Location")!,
157
+ new URL(request.url).origin + import.meta.env.SERVER_BASE_URL
158
+ ).toString();
159
+ }
154
160
  return new Response(null, {
155
161
  status: 302,
156
162
  headers: {
157
- Location: refererUrl.toString(),
163
+ Location: redirectUrl,
158
164
  ...(result
159
165
  ? {
160
166
  "Set-Cookie": `flash=${JSON.stringify({
@@ -172,18 +178,25 @@ async function handleServerFunction(h3Event: H3Event) {
172
178
  return serializeToStream(instance, result);
173
179
  } catch (x) {
174
180
  if (x instanceof Response) {
175
- if (x.status === 302 && !instance) setResponseStatus(h3Event, 302);
181
+ if (singleFlight && instance) {
182
+ x = await handleSingleFlight(event, x);
183
+ }
184
+ if ((x as any).status === 302 && !instance) setResponseStatus(h3Event, 302);
176
185
  // forward headers
177
- if (x.headers) mergeResponseHeaders(h3Event, x.headers);
186
+ if ((x as any).headers) mergeResponseHeaders(h3Event, (x as any).headers);
178
187
  if ((x as any).customBody) {
179
188
  x = (x as any).customBody();
180
- } else if (x.body == undefined) x = null;
189
+ } else if ((x as any).body == undefined) x = null;
190
+ if (instance) {
191
+ setHeader(h3Event, "content-type", "text/javascript");
192
+ return serializeToStream(instance, x);
193
+ }
181
194
  }
182
195
  return x;
183
196
  }
184
197
  }
185
198
 
186
- async function handleSingleFlight(sourceEvent: FetchEvent, result: any) {
199
+ async function handleSingleFlight(sourceEvent: FetchEvent, result: any): Promise<Response> {
187
200
  let revalidate: string[];
188
201
  let url = new URL(sourceEvent.request.headers.get("referer")!).toString();
189
202
  if (result instanceof Response) {
@@ -190,25 +190,26 @@ export function createServerReference(fn: Function, id: string, name: string) {
190
190
  return new Proxy(fn, {
191
191
  get(target, prop, receiver) {
192
192
  if (prop === "url") {
193
- return `${baseURL}/_server/?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}`;
193
+ return `${baseURL}/_server?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}`;
194
194
  }
195
195
  if (prop === "GET") {
196
196
  return receiver.withOptions({ method: "GET" });
197
197
  }
198
198
  if (prop === "withOptions") {
199
+ const url = `${baseURL}/_server/?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}`
199
200
  return (options: RequestInit) => {
200
201
  const fn = (...args: any[]) => {
201
202
  const encodeArgs = options.method && options.method.toUpperCase() === "GET";
202
203
  return fetchServerFunction(
203
204
  encodeArgs
204
- ? receiver.url + (args.length ? `&args=${JSON.stringify(args)}` : "")
205
+ ? url + (args.length ? `&args=${JSON.stringify(args)}` : "")
205
206
  : `${baseURL}/_server`,
206
207
  `${id}#${name}`,
207
208
  options,
208
209
  encodeArgs ? [] : args
209
210
  );
210
211
  };
211
- fn.url = receiver.url;
212
+ fn.url = url;
212
213
  return fn;
213
214
  };
214
215
  }
package/env.d.ts CHANGED
@@ -13,11 +13,8 @@ interface ImportMetaEnv extends Record<`VITE_${string}`, any>, SolidStartMetaEnv
13
13
  }
14
14
 
15
15
  interface SolidStartMetaEnv {
16
- START_ISLANDS_ROUTER: string;
17
- START_INDEX_HTML: string;
18
- START_ENTRY_CLIENT: string;
19
16
  START_SSR: string;
20
17
  START_ISLANDS: string;
21
- START_ENTRY_SERVER: string;
22
- DEBUG: string;
18
+ START_DEV_OVERLAY: string;
19
+ SERVER_BASE_URL: string;
23
20
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidjs/start",
3
- "version": "0.5.9",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "author": "Ryan Carniato",
6
6
  "publishConfig": {
@@ -30,25 +30,25 @@
30
30
  ".": [
31
31
  "./shared/index.tsx"
32
32
  ],
33
- "./middleware": [
33
+ "middleware": [
34
34
  "./middleware/index.ts"
35
35
  ],
36
- "./server": [
36
+ "server": [
37
37
  "./server/index.tsx"
38
38
  ],
39
- "./client": [
39
+ "client": [
40
40
  "./client/index.tsx"
41
41
  ]
42
42
  }
43
43
  },
44
44
  "devDependencies": {
45
45
  "solid-js": "^1.8.15",
46
- "vinxi": "^0.2.1"
46
+ "vinxi": "^0.3.4"
47
47
  },
48
48
  "dependencies": {
49
- "@vinxi/plugin-directives": "^0.2.0",
50
- "@vinxi/server-components": "^0.2.0",
51
- "@vinxi/server-functions": "^0.2.1",
49
+ "@vinxi/plugin-directives": "^0.3.0",
50
+ "@vinxi/server-components": "^0.3.0",
51
+ "@vinxi/server-functions": "^0.3.0",
52
52
  "defu": "^6.1.2",
53
53
  "error-stack-parser": "^2.1.4",
54
54
  "html-to-image": "^1.11.11",
@@ -32,6 +32,8 @@ function matchRoute(matches: any[], routes: any[], matched = []): any[] | undefi
32
32
 
33
33
  export function StartServer(props: { document: Component<DocumentComponentProps> }) {
34
34
  const context = getRequestEvent() as PageEvent;
35
+ // @ts-ignore
36
+ const nonce = context.nonce;
35
37
 
36
38
  let assets: Asset[] = [];
37
39
  Promise.resolve().then(async () => {
@@ -39,15 +41,14 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
39
41
  if (context.router && context.router.matches) {
40
42
  // @ts-ignore
41
43
  const matches = [...context.router.matches];
42
- while (matches.length && (!matches[0].info || !matches[0].info.filesystem))
43
- matches.shift();
44
+ while (matches.length && (!matches[0].info || !matches[0].info.filesystem)) matches.shift();
44
45
  const matched = matches.length && matchRoute(matches, context.routes);
45
46
  if (matched) {
46
47
  for (let i = 0; i < matched.length; i++) {
47
48
  const segment = matched[i];
48
49
  const part = import.meta.env.MANIFEST[import.meta.env.START_ISLANDS ? "ssr" : "client"]!
49
50
  .inputs[segment["$component"].src]!;
50
- const asset = await part.assets() as any;
51
+ const asset = (await part.assets()) as any;
51
52
  assets.push.apply(assets, asset);
52
53
  }
53
54
  } else console.warn("No route matched for preloading js assets");
@@ -74,18 +75,37 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
74
75
  </>
75
76
  }
76
77
  scripts={
77
- <>
78
- <script innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`} />
79
- <script
80
- type="module"
81
- async
82
- src={
83
- import.meta.env.MANIFEST["client"]!.inputs[
84
- import.meta.env.MANIFEST["client"]!.handler
85
- ]!.output.path
86
- }
87
- />
88
- </>
78
+ nonce ? (
79
+ <>
80
+ <script
81
+ nonce={nonce}
82
+ innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`}
83
+ />
84
+ <script
85
+ type="module"
86
+ nonce={nonce}
87
+ async
88
+ src={
89
+ import.meta.env.MANIFEST["client"]!.inputs[
90
+ import.meta.env.MANIFEST["client"]!.handler
91
+ ]!.output.path
92
+ }
93
+ />
94
+ </>
95
+ ) : (
96
+ <>
97
+ <script innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`} />
98
+ <script
99
+ type="module"
100
+ async
101
+ src={
102
+ import.meta.env.MANIFEST["client"]!.inputs[
103
+ import.meta.env.MANIFEST["client"]!.handler
104
+ ]!.output.path
105
+ }
106
+ />
107
+ </>
108
+ )
89
109
  }
90
110
  >
91
111
  {!import.meta.env.START_ISLANDS ? (
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  H3Event,
3
- HTTPEvent,
4
3
  HTTPEventSymbol,
5
4
  appendResponseHeader,
6
5
  getRequestIP,
@@ -45,7 +44,7 @@ export function getFetchEvent(h3Event: H3Event): FetchEvent {
45
44
  return (h3Event as any)[fetchEventSymbol];
46
45
  }
47
46
 
48
- export function mergeResponseHeaders(h3Event: HTTPEvent, headers: Headers) {
47
+ export function mergeResponseHeaders(h3Event: H3Event, headers: Headers) {
49
48
  for (const [key, value] of headers.entries()) {
50
49
  setHeader(h3Event, key, value);
51
50
  }
package/server/handler.ts CHANGED
@@ -2,7 +2,6 @@ import { sharedConfig } from "solid-js";
2
2
  import { renderToStream, renderToString } from "solid-js/web";
3
3
  import { provideRequestEvent } from "solid-js/web/storage";
4
4
  import {
5
- EventHandlerObject,
6
5
  EventHandlerRequest,
7
6
  H3Event,
8
7
  eventHandler,
@@ -13,27 +12,16 @@ import {
13
12
  import { matchAPIRoute } from "../shared/routes";
14
13
  import { getFetchEvent } from "./fetchEvent";
15
14
  import { createPageEvent } from "./pageEvent";
16
- import type { APIEvent, FetchEvent, PageEvent } from "./types";
15
+ import type { APIEvent, FetchEvent, HandlerOptions, PageEvent } from "./types";
17
16
 
18
17
  export function createBaseHandler(
19
18
  fn: (context: PageEvent) => unknown,
20
- options: {
21
- nonce?: string;
22
- renderId?: string;
23
- timeoutMs?: number;
24
- onCompleteAll?: (options: { write: (v: any) => void }) => void;
25
- onCompleteShell?: (options: { write: (v: any) => void }) => void;
26
- createPageEvent?: (event: FetchEvent) => Promise<PageEvent>;
27
- onRequest?: EventHandlerObject["onRequest"];
28
- onBeforeResponse?: EventHandlerObject["onBeforeResponse"];
29
- } = {}
19
+ createPageEvent: (event: FetchEvent) => Promise<PageEvent>,
20
+ options: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>) = {}
30
21
  ) {
31
22
  return eventHandler({
32
- onRequest: options.onRequest,
33
- onBeforeResponse: options.onBeforeResponse,
34
23
  handler: (e: H3Event<EventHandlerRequest>) => {
35
24
  const event = getFetchEvent(e);
36
- const mode = import.meta.env.START_SSR;
37
25
 
38
26
  return provideRequestEvent(event, async () => {
39
27
  // api
@@ -55,7 +43,11 @@ export function createBaseHandler(
55
43
 
56
44
  // render
57
45
  const context = await createPageEvent(event);
58
- if (mode === "sync") {
46
+ if (typeof options === "function") options = await options(context);
47
+ const mode = options.mode || "stream";
48
+ // @ts-ignore
49
+ if (options.nonce) context.nonce = options.nonce;
50
+ if (mode === "sync" || !import.meta.env.START_SSR) {
59
51
  const html = renderToString(() => {
60
52
  (sharedConfig.context as any).event = context;
61
53
  return fn(context);
@@ -115,7 +107,7 @@ function handleStreamCompleteRedirect(context: PageEvent) {
115
107
 
116
108
  export function createHandler(
117
109
  fn: (context: PageEvent) => unknown,
118
- options: Parameters<typeof createBaseHandler>[1] = {}
110
+ options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>)
119
111
  ) {
120
- return createBaseHandler(fn, { ...options, createPageEvent });
112
+ return createBaseHandler(fn, createPageEvent, options);
121
113
  }
@@ -8,29 +8,44 @@ const docType = ssr("<!DOCTYPE html>");
8
8
 
9
9
  export function StartServer(props: { document: Component<DocumentComponentProps> }) {
10
10
  const context = getRequestEvent() as PageEvent;
11
+ // @ts-ignore
12
+ const nonce = context.nonce;
11
13
  return (
12
14
  <NoHydration>
13
15
  {docType as unknown as any}
14
16
  <props.document
15
- assets={
16
- <>
17
- {context.assets.map((m: any) => renderAsset(m))}
18
- </>
19
- }
17
+ assets={<>{context.assets.map((m: any) => renderAsset(m))}</>}
20
18
  scripts={
21
- <>
22
- <script innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`} />
23
- <script
24
- type="module"
25
- src={
26
- import.meta.env.MANIFEST["client"]!.inputs[
27
- import.meta.env.MANIFEST["client"]!.handler
28
- ]!.output.path
29
- }
30
- />
31
- </>
19
+ nonce ? (
20
+ <>
21
+ <script
22
+ nonce={nonce}
23
+ innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`}
24
+ />
25
+ <script
26
+ type="module"
27
+ src={
28
+ import.meta.env.MANIFEST["client"]!.inputs[
29
+ import.meta.env.MANIFEST["client"]!.handler
30
+ ]!.output.path
31
+ }
32
+ />
33
+ </>
34
+ ) : (
35
+ <>
36
+ <script innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`} />
37
+ <script
38
+ type="module"
39
+ src={
40
+ import.meta.env.MANIFEST["client"]!.inputs[
41
+ import.meta.env.MANIFEST["client"]!.handler
42
+ ]!.output.path
43
+ }
44
+ />
45
+ </>
46
+ )
32
47
  }
33
- ></props.document>
48
+ />
34
49
  </NoHydration>
35
50
  );
36
51
  }
@@ -1,11 +1,11 @@
1
1
  import { createBaseHandler } from "../handler";
2
- import { FetchEvent, PageEvent } from "../types";
2
+ import { FetchEvent, HandlerOptions, PageEvent } from "../types";
3
3
 
4
4
  export function createHandler(
5
5
  fn: (context: PageEvent) => unknown,
6
- options?: { nonce?: string; renderId?: string; timeoutMs?: number }
6
+ options?: HandlerOptions | ((context: PageEvent) => HandlerOptions)
7
7
  ) {
8
- return createBaseHandler(fn, { ...options, createPageEvent });
8
+ return createBaseHandler(fn, createPageEvent, options);
9
9
  }
10
10
 
11
11
  export async function createPageEvent(ctx: FetchEvent) {
package/server/types.ts CHANGED
@@ -22,6 +22,14 @@ export type Asset = {
22
22
  attrs: JSX.LinkHTMLAttributes<HTMLLinkElement> & { key?: string };
23
23
  };
24
24
 
25
+ export type HandlerOptions = {
26
+ mode?: "sync" | "async" | "stream";
27
+ nonce?: string;
28
+ renderId?: string;
29
+ onCompleteAll?: (options: { write: (v: any) => void }) => void;
30
+ onCompleteShell?: (options: { write: (v: any) => void }) => void;
31
+ };
32
+
25
33
  export type ContextMatches = {
26
34
  originalPath: string;
27
35
  pattern: string;
@@ -1,13 +1,22 @@
1
1
  import { ErrorBoundary as DefaultErrorBoundary, type ParentProps } from "solid-js";
2
+ import { isServer } from "solid-js/web";
2
3
  import { HttpStatusCode } from "./HttpStatusCode";
3
4
  import { DevOverlay } from "./dev-overlay";
4
5
 
5
6
  export function ErrorBoundary(props: ParentProps) {
6
- if (import.meta.env.DEV) {
7
+ if (import.meta.env.DEV && import.meta.env.START_DEV_OVERLAY) {
7
8
  return <DevOverlay>{props.children}</DevOverlay>;
8
9
  }
10
+ const message = isServer ? "500 | Internal Server Error" : "Error | Uncaught Client Exception";
9
11
  return (
10
- <DefaultErrorBoundary fallback={<HttpStatusCode code={500} />}>
12
+ <DefaultErrorBoundary
13
+ fallback={
14
+ <>
15
+ <span style="font-size:1.5em;text-align:center;position:fixed;left:0px;bottom:55%;width:100%;">{message}</span>
16
+ <HttpStatusCode code={500} />
17
+ </>
18
+ }
19
+ >
11
20
  {props.children}
12
21
  </DefaultErrorBoundary>
13
22
  );