@solidjs/start 0.5.10 → 0.6.1

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.
@@ -1,3 +1,4 @@
1
+ // @refresh skip
1
2
  // @ts-ignore
2
3
  import App from "#start/app";
3
4
  import type { JSX } from "solid-js";
package/client/index.tsx CHANGED
@@ -1,3 +1,6 @@
1
+ // @refresh skip
2
+ // TODO rename to index.tsx?
1
3
  import "vinxi/client";
2
4
  export { StartClient } from "./StartClient";
3
5
  export { mount } from "./mount";
6
+
@@ -1,3 +1,4 @@
1
+ // @refresh skip
1
2
  import "vinxi/client";
2
3
  export function StartClient() {
3
4
  return null;
@@ -1,3 +1,4 @@
1
+ // @refresh skip
1
2
  import type { JSX } from "solid-js";
2
3
  import { render, type MountableElement } from "solid-js/web";
3
4
  import "vinxi/client";
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
  },
@@ -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,8 +1,9 @@
1
1
  {
2
2
  "name": "@solidjs/start",
3
- "version": "0.5.10",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "author": "Ryan Carniato",
6
+ "license": "MIT",
6
7
  "publishConfig": {
7
8
  "access": "public"
8
9
  },
@@ -43,12 +44,12 @@
43
44
  },
44
45
  "devDependencies": {
45
46
  "solid-js": "^1.8.15",
46
- "vinxi": "^0.2.1"
47
+ "vinxi": "^0.3.9"
47
48
  },
48
49
  "dependencies": {
49
- "@vinxi/plugin-directives": "^0.2.0",
50
- "@vinxi/server-components": "^0.2.0",
51
- "@vinxi/server-functions": "^0.2.1",
50
+ "@vinxi/plugin-directives": "^0.3.0",
51
+ "@vinxi/server-components": "^0.3.0",
52
+ "@vinxi/server-functions": "^0.3.0",
52
53
  "defu": "^6.1.2",
53
54
  "error-stack-parser": "^2.1.4",
54
55
  "html-to-image": "^1.11.11",
@@ -1,3 +1,4 @@
1
+ // @refresh skip
1
2
  // @ts-ignore
2
3
  import App from "#start/app";
3
4
  import type { Component, JSX } from "solid-js";
@@ -32,6 +33,8 @@ function matchRoute(matches: any[], routes: any[], matched = []): any[] | undefi
32
33
 
33
34
  export function StartServer(props: { document: Component<DocumentComponentProps> }) {
34
35
  const context = getRequestEvent() as PageEvent;
36
+ // @ts-ignore
37
+ const nonce = context.nonce;
35
38
 
36
39
  let assets: Asset[] = [];
37
40
  Promise.resolve().then(async () => {
@@ -39,15 +42,14 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
39
42
  if (context.router && context.router.matches) {
40
43
  // @ts-ignore
41
44
  const matches = [...context.router.matches];
42
- while (matches.length && (!matches[0].info || !matches[0].info.filesystem))
43
- matches.shift();
45
+ while (matches.length && (!matches[0].info || !matches[0].info.filesystem)) matches.shift();
44
46
  const matched = matches.length && matchRoute(matches, context.routes);
45
47
  if (matched) {
46
48
  for (let i = 0; i < matched.length; i++) {
47
49
  const segment = matched[i];
48
50
  const part = import.meta.env.MANIFEST[import.meta.env.START_ISLANDS ? "ssr" : "client"]!
49
51
  .inputs[segment["$component"].src]!;
50
- const asset = await part.assets() as any;
52
+ const asset = (await part.assets()) as any;
51
53
  assets.push.apply(assets, asset);
52
54
  }
53
55
  } else console.warn("No route matched for preloading js assets");
@@ -74,18 +76,37 @@ export function StartServer(props: { document: Component<DocumentComponentProps>
74
76
  </>
75
77
  }
76
78
  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
- </>
79
+ nonce ? (
80
+ <>
81
+ <script
82
+ nonce={nonce}
83
+ innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`}
84
+ />
85
+ <script
86
+ type="module"
87
+ nonce={nonce}
88
+ async
89
+ src={
90
+ import.meta.env.MANIFEST["client"]!.inputs[
91
+ import.meta.env.MANIFEST["client"]!.handler
92
+ ]!.output.path
93
+ }
94
+ />
95
+ </>
96
+ ) : (
97
+ <>
98
+ <script innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`} />
99
+ <script
100
+ type="module"
101
+ async
102
+ src={
103
+ import.meta.env.MANIFEST["client"]!.inputs[
104
+ import.meta.env.MANIFEST["client"]!.handler
105
+ ]!.output.path
106
+ }
107
+ />
108
+ </>
109
+ )
89
110
  }
90
111
  >
91
112
  {!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
  }
package/server/index.tsx CHANGED
@@ -1,3 +1,5 @@
1
+ // @refresh skip
2
+ // TODO rename to index.ts?
1
3
  export { StartServer } from "./StartServer";
2
4
  export { createHandler } from "./handler";
3
5
  export * from "./types";
@@ -1,5 +1,6 @@
1
- import { type Component, type ComponentProps, lazy, sharedConfig } from "solid-js";
2
- import { getRequestEvent, Hydration, NoHydration } from "solid-js/web";
1
+ // @refresh skip
2
+ import { lazy, sharedConfig, type Component, type ComponentProps } from "solid-js";
3
+ import { Hydration, NoHydration, getRequestEvent } from "solid-js/web";
3
4
  // import { IslandManifest } from "./types";
4
5
  import { splitProps } from "./utils";
5
6
 
@@ -1,3 +1,5 @@
1
+ // @refresh skip
2
+ // TODO rename to utils.ts?
1
3
  // @ts-nocheck
2
4
  import { $PROXY } from "solid-js";
3
5
 
@@ -9,13 +9,14 @@ function initFromFlash(ctx: FetchEvent) {
9
9
  const flash = getCookie(ctx, "flash");
10
10
  if (!flash) return;
11
11
  let param = JSON.parse(flash);
12
- if (!param || !param.result) return [];
12
+ if (!param || !param.result) return;
13
13
  const input = [...param.input.slice(0, -1), new Map(param.input[param.input.length - 1])];
14
14
  setCookie(ctx, "flash", "", { maxAge: 0 });
15
15
  return {
16
+ input,
16
17
  url: param.url,
18
+ pending: false,
17
19
  result: param.error ? new Error(param.result) : param.result,
18
- input
19
20
  };
20
21
  }
21
22
 
@@ -36,7 +37,7 @@ export async function createPageEvent(ctx: FetchEvent) {
36
37
  : [])
37
38
  ],
38
39
  router: {
39
- submission: initFromFlash(ctx)
40
+ submission: initFromFlash(ctx) as any
40
41
  },
41
42
  routes: createRoutes(),
42
43
  // prevUrl: prevPath || "",
@@ -1,3 +1,5 @@
1
+ // @refresh skip
2
+ // TODO rename to renderAsset.ts?
1
3
  import type { JSX } from "solid-js";
2
4
  import type { Asset } from "./types";
3
5
 
@@ -1,3 +1,4 @@
1
+ // @refresh skip
1
2
  // @ts-ignore
2
3
  import type { Component } from "solid-js";
3
4
  import { NoHydration, getRequestEvent, ssr } from "solid-js/web";
@@ -8,29 +9,44 @@ const docType = ssr("<!DOCTYPE html>");
8
9
 
9
10
  export function StartServer(props: { document: Component<DocumentComponentProps> }) {
10
11
  const context = getRequestEvent() as PageEvent;
12
+ // @ts-ignore
13
+ const nonce = context.nonce;
11
14
  return (
12
15
  <NoHydration>
13
16
  {docType as unknown as any}
14
17
  <props.document
15
- assets={
16
- <>
17
- {context.assets.map((m: any) => renderAsset(m))}
18
- </>
19
- }
18
+ assets={<>{context.assets.map((m: any) => renderAsset(m))}</>}
20
19
  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
- </>
20
+ nonce ? (
21
+ <>
22
+ <script
23
+ nonce={nonce}
24
+ innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`}
25
+ />
26
+ <script
27
+ type="module"
28
+ src={
29
+ import.meta.env.MANIFEST["client"]!.inputs[
30
+ import.meta.env.MANIFEST["client"]!.handler
31
+ ]!.output.path
32
+ }
33
+ />
34
+ </>
35
+ ) : (
36
+ <>
37
+ <script innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`} />
38
+ <script
39
+ type="module"
40
+ src={
41
+ import.meta.env.MANIFEST["client"]!.inputs[
42
+ import.meta.env.MANIFEST["client"]!.handler
43
+ ]!.output.path
44
+ }
45
+ />
46
+ </>
47
+ )
32
48
  }
33
- ></props.document>
49
+ />
34
50
  </NoHydration>
35
51
  );
36
52
  }
@@ -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) {
@@ -1,3 +1,5 @@
1
+ // @refresh skip
2
+ // TODO rename to index.ts?
1
3
  export * from "../types";
2
4
  export { StartServer } from "./StartServer";
3
5
  export { createHandler } from "./handler";
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,14 +1,23 @@
1
+ // @refresh skip
1
2
  import { ErrorBoundary as DefaultErrorBoundary, type ParentProps } from "solid-js";
3
+ import { isServer } from "solid-js/web";
2
4
  import { HttpStatusCode } from "./HttpStatusCode";
3
5
  import { DevOverlay } from "./dev-overlay";
4
6
 
5
- export function ErrorBoundary(props: ParentProps) {
6
- if (import.meta.env.DEV) {
7
- return <DevOverlay>{props.children}</DevOverlay>;
8
- }
9
- return (
10
- <DefaultErrorBoundary fallback={<HttpStatusCode code={500} />}>
11
- {props.children}
12
- </DefaultErrorBoundary>
13
- );
14
- }
7
+ export const ErrorBoundary = import.meta.env.DEV && import.meta.env.START_DEV_OVERLAY
8
+ ? (props: ParentProps) => <DevOverlay>{props.children}</DevOverlay>
9
+ : (props: ParentProps) => {
10
+ const message = isServer ? "500 | Internal Server Error" : "Error | Uncaught Client Exception";
11
+ return (
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
+ >
20
+ {props.children}
21
+ </DefaultErrorBoundary>
22
+ )
23
+ };
@@ -30,6 +30,6 @@ export function createRoutes() {
30
30
  }
31
31
 
32
32
  let routes: any[];
33
- export const FileRoutes = () => {
34
- return isServer ? (getRequestEvent() as PageEvent).routes : routes || (routes = createRoutes());
35
- };
33
+ export const FileRoutes = isServer
34
+ ? () => (getRequestEvent() as PageEvent).routes
35
+ : () => routes || (routes = createRoutes());
@@ -1,9 +1,16 @@
1
+ // @refresh skip
1
2
  import { onCleanup } from "solid-js";
2
3
  import { getRequestEvent, isServer } from "solid-js/web";
3
4
  import type { PageEvent } from "../server/types";
4
5
 
5
- export function HttpHeader(props: { name: string; value: string; append?: boolean }) {
6
- if (isServer) {
6
+ export interface HttpHeaderProps {
7
+ name: string;
8
+ value: string;
9
+ append?: boolean;
10
+ }
11
+
12
+ export const HttpHeader = isServer
13
+ ? (props: HttpHeaderProps) => {
7
14
  const event = getRequestEvent() as PageEvent;
8
15
 
9
16
  if (props.append) event.response.headers.append(props.name, props.value);
@@ -23,7 +30,6 @@ export function HttpHeader(props: { name: string; value: string; append?: boolea
23
30
  if (values.length) event.response.headers.set(props.name, values.join(","));
24
31
  else event.response.headers.delete(props.name);
25
32
  });
33
+ return null;
26
34
  }
27
-
28
- return null;
29
- }
35
+ : (_props: HttpHeaderProps) => null;
@@ -1,13 +1,19 @@
1
+ // @refresh skip
1
2
  import { onCleanup } from "solid-js";
2
3
  import { getRequestEvent, isServer } from "solid-js/web";
3
4
  import type { PageEvent } from "../server/types";
4
5
 
5
- export function HttpStatusCode(props: { code: number, text?: string }) {
6
- if (isServer) {
6
+ export interface HttpStatusCodeProps {
7
+ code: number;
8
+ text?: string;
9
+ }
10
+
11
+ export const HttpStatusCode = isServer
12
+ ? (props: HttpStatusCodeProps) => {
7
13
  const event = getRequestEvent() as PageEvent;
8
14
  event.response.status = props.code;
9
15
  event.response.statusText = props.text;
10
16
  onCleanup(() => !event.nativeEvent.handled && (event.response.status = 200));
17
+ return null;
11
18
  }
12
- return null;
13
- }
19
+ : (_props: HttpStatusCodeProps) => null;
@@ -1,3 +1,4 @@
1
+ // @refresh skip
1
2
  import type { Component, ComponentProps, JSX } from "solid-js";
2
3
  import { createMemo, createSignal, onMount, sharedConfig, splitProps, untrack } from "solid-js";
3
4
  import { isServer } from "solid-js/web";
@@ -1,3 +1,4 @@
1
+ // @refresh skip
1
2
  import type { BuiltinLanguage, Highlighter } from 'shikiji';
2
3
  import { getHighlighterCore, loadWasm } from 'shikiji/core';
3
4
  import { createEffect, createResource, type JSX } from 'solid-js';
@@ -1,3 +1,4 @@
1
+ // @refresh skip
1
2
  import ErrorStackParser from 'error-stack-parser';
2
3
  import * as htmlToImage from 'html-to-image';
3
4
  import type { JSX } from 'solid-js';
@@ -1,3 +1,4 @@
1
+ // @refresh skip
1
2
  import type { JSX } from 'solid-js';
2
3
 
3
4
  export function ArrowRightIcon(
@@ -1,3 +1,4 @@
1
+ // @refresh skip
1
2
  import {
2
3
  ErrorBoundary,
3
4
  Show,
package/shared/index.tsx CHANGED
@@ -1,3 +1,5 @@
1
+ // @refresh skip
2
+ // TODO rename to index.ts?
1
3
  export { FileRoutes } from "./FileRoutes";
2
4
  export { GET } from "./GET";
3
5
  export { HttpHeader } from "./HttpHeader";
@@ -1,3 +1,5 @@
1
+ // @refresh skip
2
+ // TODO rename to lazyRoute.ts?
1
3
  /// <reference types="vinxi/types/client" />
2
4
  import { createComponent, lazy, onCleanup, type Component, type JSX } from "solid-js";
3
5
  import { appendStyles, cleanupStyles, preloadStyles, updateStyles } from "vinxi/css";