@solidjs/start 1.0.0-rc.1 → 1.0.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.
- package/config/fs-router.js +15 -10
- package/config/index.d.ts +10 -4
- package/config/index.js +13 -7
- package/dist/client/StartClient.d.ts +4 -0
- package/dist/client/StartClient.jsx +4 -0
- package/dist/client/islands.d.ts +4 -0
- package/dist/client/islands.jsx +4 -0
- package/dist/client/mount.d.ts +4 -0
- package/dist/client/mount.js +8 -2
- package/dist/router/FileRoutes.d.ts +4 -0
- package/dist/router/FileRoutes.js +8 -3
- package/dist/router/lazyRoute.js +7 -2
- package/dist/router/routes.d.ts +1 -0
- package/dist/router/routes.js +2 -2
- package/dist/runtime/server-handler.js +4 -1
- package/dist/server/StartServer.d.ts +4 -0
- package/dist/server/StartServer.jsx +30 -23
- package/dist/server/handler.d.ts +10 -1
- package/dist/server/handler.js +22 -3
- package/dist/server/serverFunction.d.ts +4 -0
- package/dist/server/serverFunction.jsx +4 -0
- package/dist/server/spa/StartServer.d.ts +4 -0
- package/dist/server/spa/StartServer.jsx +14 -7
- package/dist/server/spa/handler.d.ts +4 -0
- package/dist/server/spa/handler.js +4 -0
- package/dist/shared/ErrorBoundary.d.ts +1 -0
- package/dist/shared/ErrorBoundary.jsx +28 -8
- package/dist/shared/GET.d.ts +4 -0
- package/dist/shared/GET.js +4 -0
- package/dist/shared/HttpHeader.d.ts +4 -0
- package/dist/shared/HttpHeader.jsx +4 -0
- package/dist/shared/HttpStatusCode.d.ts +4 -0
- package/dist/shared/HttpStatusCode.jsx +4 -0
- package/dist/shared/clientOnly.d.ts +4 -0
- package/dist/shared/clientOnly.jsx +4 -0
- package/dist/shared/dev-overlay/get-source-map.d.ts +0 -1
- package/package.json +6 -2
package/config/fs-router.js
CHANGED
|
@@ -24,6 +24,7 @@ export class SolidStartClientFileRouter extends BaseFileSystemRouter {
|
|
|
24
24
|
|
|
25
25
|
if (src.endsWith(".md") || src.endsWith(".mdx")) {
|
|
26
26
|
return {
|
|
27
|
+
page: true,
|
|
27
28
|
$component: {
|
|
28
29
|
src: src,
|
|
29
30
|
pick: ["$css"]
|
|
@@ -35,10 +36,11 @@ export class SolidStartClientFileRouter extends BaseFileSystemRouter {
|
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
const [_, exports] = analyzeModule(src);
|
|
38
|
-
const hasDefault = exports.find(e => e.n === "default");
|
|
39
|
-
const hasRouteConfig = exports.find(e => e.n === "route");
|
|
39
|
+
const hasDefault = !!exports.find(e => e.n === "default");
|
|
40
|
+
const hasRouteConfig = !!exports.find(e => e.n === "route");
|
|
40
41
|
if (hasDefault) {
|
|
41
42
|
return {
|
|
43
|
+
page: true,
|
|
42
44
|
$component: {
|
|
43
45
|
src: src,
|
|
44
46
|
pick: ["default", "$css"]
|
|
@@ -93,6 +95,7 @@ export class SolidStartServerFileRouter extends BaseFileSystemRouter {
|
|
|
93
95
|
let path = this.toPath(src);
|
|
94
96
|
if (src.endsWith(".md") || src.endsWith(".mdx")) {
|
|
95
97
|
return {
|
|
98
|
+
page: true,
|
|
96
99
|
$component: {
|
|
97
100
|
src: src,
|
|
98
101
|
pick: ["$css"]
|
|
@@ -105,16 +108,18 @@ export class SolidStartServerFileRouter extends BaseFileSystemRouter {
|
|
|
105
108
|
|
|
106
109
|
const [_, exports] = analyzeModule(src);
|
|
107
110
|
const hasRouteConfig = exports.find(e => e.n === "route");
|
|
108
|
-
const hasDefault = exports.find(e => e.n === "default");
|
|
109
|
-
const hasAPIRoutes = exports.find(exp => HTTP_METHODS.includes(exp.n));
|
|
111
|
+
const hasDefault = !!exports.find(e => e.n === "default");
|
|
112
|
+
const hasAPIRoutes = !!exports.find(exp => HTTP_METHODS.includes(exp.n));
|
|
110
113
|
if (hasDefault || hasAPIRoutes) {
|
|
111
114
|
return {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
page: hasDefault,
|
|
116
|
+
$component:
|
|
117
|
+
!this.config.dataOnly && hasDefault
|
|
118
|
+
? {
|
|
119
|
+
src: src,
|
|
120
|
+
pick: ["default", "$css"]
|
|
121
|
+
}
|
|
122
|
+
: undefined,
|
|
118
123
|
$$route: hasRouteConfig
|
|
119
124
|
? {
|
|
120
125
|
src: src,
|
package/config/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { Options } from "vite-plugin-solid";
|
|
|
6
6
|
// atleast until we sort which server options are good to use
|
|
7
7
|
type ViteCustomizableConfig = CustomizableConfig & {
|
|
8
8
|
server?: InlineConfig["server"];
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
|
|
11
11
|
type SolidStartInlineConfig = {
|
|
12
12
|
ssr?: boolean;
|
|
@@ -16,13 +16,19 @@ type SolidStartInlineConfig = {
|
|
|
16
16
|
appRoot?: string;
|
|
17
17
|
routeDir?: string;
|
|
18
18
|
middleware?: string;
|
|
19
|
-
devOverlay?:
|
|
19
|
+
devOverlay?: boolean;
|
|
20
20
|
experimental?: {
|
|
21
21
|
islands?: boolean;
|
|
22
|
-
}
|
|
22
|
+
};
|
|
23
23
|
vite?:
|
|
24
24
|
| ViteCustomizableConfig
|
|
25
25
|
| ((options: { router: "server" | "client" | "server-function" }) => ViteCustomizableConfig);
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/entrypoints/app-config
|
|
31
|
+
*/
|
|
32
|
+
export declare function defineConfig(
|
|
33
|
+
baseConfig?: SolidStartInlineConfig
|
|
34
|
+
): ReturnType<typeof createApp>;
|
package/config/index.js
CHANGED
|
@@ -30,7 +30,8 @@ function solidStartServerFsRouter(config) {
|
|
|
30
30
|
new SolidStartServerFileRouter(
|
|
31
31
|
{
|
|
32
32
|
dir: resolve.absolute(config.dir, router.root),
|
|
33
|
-
extensions: config.extensions ?? DEFAULT_EXTENSIONS
|
|
33
|
+
extensions: config.extensions ?? DEFAULT_EXTENSIONS,
|
|
34
|
+
dataOnly: config.dataOnly
|
|
34
35
|
},
|
|
35
36
|
router,
|
|
36
37
|
app
|
|
@@ -90,7 +91,7 @@ export function defineConfig(baseConfig = {}) {
|
|
|
90
91
|
},
|
|
91
92
|
handler: `${start.appRoot}/entry-server${entryExtension}`,
|
|
92
93
|
middleware: start.middleware,
|
|
93
|
-
routes: solidStartServerFsRouter({ dir: routeDir, extensions }),
|
|
94
|
+
routes: solidStartServerFsRouter({ dir: routeDir, extensions, dataOnly: !start.ssr }),
|
|
94
95
|
extensions,
|
|
95
96
|
target: "server",
|
|
96
97
|
plugins: async () => {
|
|
@@ -133,7 +134,9 @@ export function defineConfig(baseConfig = {}) {
|
|
|
133
134
|
},
|
|
134
135
|
cacheDir: "node_modules/.vinxi/server",
|
|
135
136
|
define: {
|
|
136
|
-
"import.meta.env.START_APP": JSON.stringify(
|
|
137
|
+
"import.meta.env.START_APP": JSON.stringify(
|
|
138
|
+
`${start.appRoot}/app${entryExtension}`
|
|
139
|
+
),
|
|
137
140
|
"import.meta.env.START_ISLANDS": JSON.stringify(start.experimental.islands),
|
|
138
141
|
"import.meta.env.SSR": JSON.stringify(true),
|
|
139
142
|
"import.meta.env.START_SSR": JSON.stringify(start.ssr),
|
|
@@ -201,7 +204,9 @@ export function defineConfig(baseConfig = {}) {
|
|
|
201
204
|
},
|
|
202
205
|
cacheDir: "node_modules/.vinxi/client",
|
|
203
206
|
define: {
|
|
204
|
-
"import.meta.env.START_APP": JSON.stringify(
|
|
207
|
+
"import.meta.env.START_APP": JSON.stringify(
|
|
208
|
+
`${start.appRoot}/app${entryExtension}`
|
|
209
|
+
),
|
|
205
210
|
"import.meta.env.START_ISLANDS": JSON.stringify(start.experimental.islands),
|
|
206
211
|
"import.meta.env.SSR": JSON.stringify(false),
|
|
207
212
|
"import.meta.env.START_SSR": JSON.stringify(start.ssr),
|
|
@@ -213,7 +218,6 @@ export function defineConfig(baseConfig = {}) {
|
|
|
213
218
|
];
|
|
214
219
|
}
|
|
215
220
|
},
|
|
216
|
-
|
|
217
221
|
{
|
|
218
222
|
name: "server-fns",
|
|
219
223
|
type: "http",
|
|
@@ -223,7 +227,7 @@ export function defineConfig(baseConfig = {}) {
|
|
|
223
227
|
),
|
|
224
228
|
middleware: start.middleware,
|
|
225
229
|
target: "server",
|
|
226
|
-
routes: solidStartServerFsRouter({ dir: routeDir, extensions }),
|
|
230
|
+
routes: solidStartServerFsRouter({ dir: routeDir, extensions, dataOnly: !start.ssr }),
|
|
227
231
|
plugins: async () => {
|
|
228
232
|
const userConfig =
|
|
229
233
|
typeof vite === "function" ? await vite({ router: "server-function" }) : { ...vite };
|
|
@@ -263,7 +267,9 @@ export function defineConfig(baseConfig = {}) {
|
|
|
263
267
|
}
|
|
264
268
|
},
|
|
265
269
|
define: {
|
|
266
|
-
"import.meta.env.START_APP": JSON.stringify(
|
|
270
|
+
"import.meta.env.START_APP": JSON.stringify(
|
|
271
|
+
`${start.appRoot}/app${entryExtension}`
|
|
272
|
+
),
|
|
267
273
|
"import.meta.env.START_ISLANDS": JSON.stringify(start.experimental.islands),
|
|
268
274
|
"import.meta.env.SSR": JSON.stringify(true),
|
|
269
275
|
"import.meta.env.START_SSR": JSON.stringify(start.ssr),
|
package/dist/client/islands.d.ts
CHANGED
package/dist/client/islands.jsx
CHANGED
package/dist/client/mount.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import type { JSX } from "solid-js";
|
|
2
2
|
import { type MountableElement } from "solid-js/web";
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/client/mount
|
|
6
|
+
*/
|
|
3
7
|
export declare function mount(fn: () => JSX.Element, el: MountableElement): (() => void) | undefined;
|
package/dist/client/mount.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { createStore } from "solid-js/store";
|
|
2
2
|
import { createComponent, getHydrationKey, getOwner, hydrate } from "solid-js/web";
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/client/mount
|
|
6
|
+
*/
|
|
3
7
|
export function mount(fn, el) {
|
|
4
8
|
if (import.meta.env.START_ISLANDS) {
|
|
5
9
|
const map = new WeakMap();
|
|
@@ -17,7 +21,8 @@ export function mount(fn, el) {
|
|
|
17
21
|
}
|
|
18
22
|
let mod = await import(
|
|
19
23
|
/* @vite-ignore */
|
|
20
|
-
import.meta.env.MANIFEST["client"].chunks[el.dataset.id.split("#")[0]].output
|
|
24
|
+
import.meta.env.MANIFEST["client"].chunks[el.dataset.id.split("#")[0]].output
|
|
25
|
+
.path);
|
|
21
26
|
if (!mod || !el.dataset.hk)
|
|
22
27
|
return;
|
|
23
28
|
let Component = mod[el.dataset.id.split("#")[1]];
|
|
@@ -58,7 +63,8 @@ export function mount(fn, el) {
|
|
|
58
63
|
const islands = document.querySelectorAll("solid-island[data-hk]");
|
|
59
64
|
const assets = new Set();
|
|
60
65
|
islands.forEach((el) => el.dataset.id && assets.add(el.dataset.id));
|
|
61
|
-
Promise.all([...assets].map(asset => import(
|
|
66
|
+
Promise.all([...assets].map(asset => import(
|
|
67
|
+
/* @vite-ignore */ import.meta.env.MANIFEST["client"].chunks[asset.split("#")[0]].output.path)))
|
|
62
68
|
.then(() => {
|
|
63
69
|
islands.forEach((el) => {
|
|
64
70
|
if (el.dataset.when === "idle" && "requestIdleCallback" in window) {
|
|
@@ -10,9 +10,10 @@ export function createRoutes() {
|
|
|
10
10
|
...(route.$$route ? route.$$route.require().route.info : {}),
|
|
11
11
|
filesystem: true
|
|
12
12
|
},
|
|
13
|
-
component:
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
component: route.$component &&
|
|
14
|
+
lazyRoute(route.$component, import.meta.env.START_ISLANDS
|
|
15
|
+
? import.meta.env.MANIFEST["ssr"]
|
|
16
|
+
: import.meta.env.MANIFEST["client"], import.meta.env.MANIFEST["ssr"]),
|
|
16
17
|
children: route.children ? route.children.map(createRoute) : undefined
|
|
17
18
|
};
|
|
18
19
|
}
|
|
@@ -20,6 +21,10 @@ export function createRoutes() {
|
|
|
20
21
|
return routes;
|
|
21
22
|
}
|
|
22
23
|
let routes;
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/routing/file-routes
|
|
27
|
+
*/
|
|
23
28
|
export const FileRoutes = isServer
|
|
24
29
|
? () => getRequestEvent().routes
|
|
25
30
|
: () => routes || (routes = createRoutes());
|
package/dist/router/lazyRoute.js
CHANGED
|
@@ -6,11 +6,16 @@ export default function lazyRoute(component, clientManifest, serverManifest, exp
|
|
|
6
6
|
return lazy(async () => {
|
|
7
7
|
if (import.meta.env.DEV) {
|
|
8
8
|
let manifest = import.meta.env.SSR ? serverManifest : clientManifest;
|
|
9
|
-
|
|
9
|
+
// import() throws if a module doesn't exist, which includes any
|
|
10
|
+
// modules loaded by the route itself, so it's important we catch here
|
|
11
|
+
const mod = await manifest.inputs[component.src].import().catch(() => null);
|
|
12
|
+
// fallback to an empty component as any errors will surface in the vite overlay
|
|
13
|
+
if (!mod)
|
|
14
|
+
return { default: () => [] };
|
|
10
15
|
if (!mod[exported])
|
|
11
16
|
console.error(`Module ${component.src} does not export ${exported}`);
|
|
12
17
|
const Component = mod[exported];
|
|
13
|
-
let assets = await clientManifest.inputs?.[component.src]
|
|
18
|
+
let assets = await clientManifest.inputs?.[component.src]?.assets();
|
|
14
19
|
const styles = assets.filter((asset) => asset.tag === "style");
|
|
15
20
|
if (typeof window !== "undefined" && import.meta.hot) {
|
|
16
21
|
import.meta.hot.on("css-update", data => {
|
package/dist/router/routes.d.ts
CHANGED
package/dist/router/routes.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRouter } from "radix3";
|
|
2
2
|
import fileRoutes from "vinxi/routes";
|
|
3
|
-
export const pageRoutes = defineRoutes(fileRoutes.filter(o => o
|
|
3
|
+
export const pageRoutes = defineRoutes(fileRoutes.filter(o => o.page));
|
|
4
4
|
function defineRoutes(fileRoutes) {
|
|
5
5
|
function processRoute(routes, route, id, full) {
|
|
6
6
|
const parentRoute = Object.values(routes).find(o => {
|
|
@@ -21,7 +21,7 @@ function defineRoutes(fileRoutes) {
|
|
|
21
21
|
}
|
|
22
22
|
export function matchAPIRoute(path, method) {
|
|
23
23
|
const match = router.lookup(path);
|
|
24
|
-
if (match) {
|
|
24
|
+
if (match && match.route) {
|
|
25
25
|
const handler = match.route[`$${method}`];
|
|
26
26
|
if (handler === undefined)
|
|
27
27
|
return;
|
|
@@ -9,6 +9,7 @@ import { eventHandler, setHeader, setResponseStatus } from "vinxi/http";
|
|
|
9
9
|
import invariant from "vinxi/lib/invariant";
|
|
10
10
|
import { cloneEvent, getFetchEvent, mergeResponseHeaders } from "../server/fetchEvent";
|
|
11
11
|
import { createPageEvent } from "../server/pageEvent";
|
|
12
|
+
import { getExpectedRedirectStatus } from "../server/handler";
|
|
12
13
|
function createChunk(data) {
|
|
13
14
|
const encodeData = new TextEncoder().encode(data);
|
|
14
15
|
const bytes = encodeData.length;
|
|
@@ -155,11 +156,13 @@ async function handleServerFunction(h3Event) {
|
|
|
155
156
|
if (!instance) {
|
|
156
157
|
const isError = result instanceof Error;
|
|
157
158
|
let redirectUrl = new URL(request.headers.get("referer")).toString();
|
|
159
|
+
let statusCode = 302;
|
|
158
160
|
if (result instanceof Response && result.headers.has("Location")) {
|
|
159
161
|
redirectUrl = new URL(result.headers.get("Location"), new URL(request.url).origin + import.meta.env.SERVER_BASE_URL).toString();
|
|
162
|
+
statusCode = getExpectedRedirectStatus(result);
|
|
160
163
|
}
|
|
161
164
|
return new Response(null, {
|
|
162
|
-
status:
|
|
165
|
+
status: statusCode,
|
|
163
166
|
headers: {
|
|
164
167
|
Location: redirectUrl,
|
|
165
168
|
...(result
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { Component, JSX } from "solid-js";
|
|
2
2
|
import type { DocumentComponentProps } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/server/start-server
|
|
6
|
+
*/
|
|
3
7
|
export declare function StartServer(props: {
|
|
4
8
|
document: Component<DocumentComponentProps>;
|
|
5
9
|
}): JSX.Element;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @ts-ignore
|
|
3
3
|
import App from "#start/app";
|
|
4
4
|
import { Hydration, HydrationScript, NoHydration, getRequestEvent, ssr, useAssets } from "solid-js/web";
|
|
5
|
-
import { ErrorBoundary } from "../shared/ErrorBoundary";
|
|
5
|
+
import { ErrorBoundary, TopErrorBoundary } from "../shared/ErrorBoundary";
|
|
6
6
|
import { renderAsset } from "./renderAsset";
|
|
7
7
|
const docType = ssr("<!DOCTYPE html>");
|
|
8
8
|
function matchRoute(matches, routes, matched = []) {
|
|
@@ -22,12 +22,17 @@ function matchRoute(matches, routes, matched = []) {
|
|
|
22
22
|
return next;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
*
|
|
27
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/server/start-server
|
|
28
|
+
*/
|
|
25
29
|
export function StartServer(props) {
|
|
26
30
|
const context = getRequestEvent();
|
|
27
31
|
// @ts-ignore
|
|
28
32
|
const nonce = context.nonce;
|
|
29
33
|
let assets = [];
|
|
30
34
|
Promise.resolve().then(async () => {
|
|
35
|
+
let assetPromises = [];
|
|
31
36
|
// @ts-ignore
|
|
32
37
|
if (context.router && context.router.matches) {
|
|
33
38
|
// @ts-ignore
|
|
@@ -40,39 +45,41 @@ export function StartServer(props) {
|
|
|
40
45
|
const segment = matched[i];
|
|
41
46
|
const part = import.meta.env.MANIFEST[import.meta.env.START_ISLANDS ? "ssr" : "client"]
|
|
42
47
|
.inputs[segment["$component"].src];
|
|
43
|
-
|
|
44
|
-
assets.push.apply(assets, asset);
|
|
48
|
+
assetPromises.push(part.assets());
|
|
45
49
|
}
|
|
46
50
|
}
|
|
47
|
-
else
|
|
51
|
+
else if (import.meta.env.DEV)
|
|
48
52
|
console.warn("No route matched for preloading js assets");
|
|
49
53
|
}
|
|
54
|
+
assets = await Promise.all(assetPromises).then(a =>
|
|
50
55
|
// dedupe assets
|
|
51
|
-
|
|
56
|
+
[...new Map(a.flat().map(item => [item.attrs.key, item])).values()].filter(asset => import.meta.env.START_ISLANDS
|
|
52
57
|
? false
|
|
53
58
|
: asset.attrs.rel === "modulepreload" &&
|
|
54
|
-
!context.assets.find((a) => a.attrs.key === asset.attrs.key));
|
|
59
|
+
!context.assets.find((a) => a.attrs.key === asset.attrs.key)));
|
|
55
60
|
});
|
|
56
61
|
useAssets(() => (assets.length ? assets.map(m => renderAsset(m)) : undefined));
|
|
57
62
|
return (<NoHydration>
|
|
58
63
|
{docType}
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
<TopErrorBoundary>
|
|
65
|
+
<props.document assets={<>
|
|
66
|
+
<HydrationScript />
|
|
67
|
+
{context.assets.map((m) => renderAsset(m, nonce))}
|
|
68
|
+
</>} scripts={nonce ? (<>
|
|
69
|
+
<script nonce={nonce} innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`}/>
|
|
70
|
+
<script type="module" nonce={nonce} async src={import.meta.env.MANIFEST["client"].inputs[import.meta.env.MANIFEST["client"].handler].output.path}/>
|
|
71
|
+
</>) : (<>
|
|
72
|
+
<script innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`}/>
|
|
73
|
+
<script type="module" async src={import.meta.env.MANIFEST["client"].inputs[import.meta.env.MANIFEST["client"].handler].output.path}/>
|
|
74
|
+
</>)}>
|
|
75
|
+
{!import.meta.env.START_ISLANDS ? (<Hydration>
|
|
76
|
+
<ErrorBoundary>
|
|
77
|
+
<App />
|
|
78
|
+
</ErrorBoundary>
|
|
79
|
+
</Hydration>) : (<ErrorBoundary>
|
|
71
80
|
<App />
|
|
72
|
-
</ErrorBoundary>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
</ErrorBoundary>)}
|
|
76
|
-
</props.document>
|
|
81
|
+
</ErrorBoundary>)}
|
|
82
|
+
</props.document>
|
|
83
|
+
</TopErrorBoundary>
|
|
77
84
|
</NoHydration>);
|
|
78
85
|
}
|
package/dist/server/handler.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
-
import type { FetchEvent, HandlerOptions, PageEvent } from "./types";
|
|
1
|
+
import type { FetchEvent, HandlerOptions, PageEvent, ResponseStub } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Checks if user has set a redirect status in the response.
|
|
4
|
+
* If not, falls back to the 302 (temporary redirect)
|
|
5
|
+
*/
|
|
6
|
+
export declare function getExpectedRedirectStatus(response: ResponseStub): number;
|
|
2
7
|
export declare function createBaseHandler(fn: (context: PageEvent) => unknown, createPageEvent: (event: FetchEvent) => Promise<PageEvent>, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>)): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/server/create-handler
|
|
11
|
+
*/
|
|
3
12
|
export declare function createHandler(fn: (context: PageEvent) => unknown, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>)): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
package/dist/server/handler.js
CHANGED
|
@@ -5,6 +5,18 @@ import { eventHandler, sendRedirect, setHeader, setResponseStatus } from "vinxi/
|
|
|
5
5
|
import { matchAPIRoute } from "../router/routes";
|
|
6
6
|
import { getFetchEvent } from "./fetchEvent";
|
|
7
7
|
import { createPageEvent } from "./pageEvent";
|
|
8
|
+
// according to https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages
|
|
9
|
+
const validRedirectStatuses = new Set([301, 302, 303, 307, 308]);
|
|
10
|
+
/**
|
|
11
|
+
* Checks if user has set a redirect status in the response.
|
|
12
|
+
* If not, falls back to the 302 (temporary redirect)
|
|
13
|
+
*/
|
|
14
|
+
export function getExpectedRedirectStatus(response) {
|
|
15
|
+
if (response.status && validRedirectStatuses.has(response.status)) {
|
|
16
|
+
return response.status;
|
|
17
|
+
}
|
|
18
|
+
return 302;
|
|
19
|
+
}
|
|
8
20
|
export function createBaseHandler(fn, createPageEvent, options = {}) {
|
|
9
21
|
return eventHandler({
|
|
10
22
|
handler: (e) => {
|
|
@@ -39,7 +51,8 @@ export function createBaseHandler(fn, createPageEvent, options = {}) {
|
|
|
39
51
|
}, resolvedOptions);
|
|
40
52
|
context.complete = true;
|
|
41
53
|
if (context.response && context.response.headers.get("Location")) {
|
|
42
|
-
|
|
54
|
+
const status = getExpectedRedirectStatus(context.response);
|
|
55
|
+
return sendRedirect(e, context.response.headers.get("Location"), status);
|
|
43
56
|
}
|
|
44
57
|
return html;
|
|
45
58
|
}
|
|
@@ -66,7 +79,8 @@ export function createBaseHandler(fn, createPageEvent, options = {}) {
|
|
|
66
79
|
return fn(context);
|
|
67
80
|
}, resolvedOptions);
|
|
68
81
|
if (context.response && context.response.headers.get("Location")) {
|
|
69
|
-
|
|
82
|
+
const status = getExpectedRedirectStatus(context.response);
|
|
83
|
+
return sendRedirect(e, context.response.headers.get("Location"), status);
|
|
70
84
|
}
|
|
71
85
|
if (mode === "async")
|
|
72
86
|
return stream;
|
|
@@ -81,7 +95,8 @@ export function createBaseHandler(fn, createPageEvent, options = {}) {
|
|
|
81
95
|
function handleShellCompleteRedirect(context, e) {
|
|
82
96
|
return () => {
|
|
83
97
|
if (context.response && context.response.headers.get("Location")) {
|
|
84
|
-
|
|
98
|
+
const status = getExpectedRedirectStatus(context.response);
|
|
99
|
+
setResponseStatus(e, status);
|
|
85
100
|
setHeader(e, "Location", context.response.headers.get("Location"));
|
|
86
101
|
}
|
|
87
102
|
};
|
|
@@ -93,6 +108,10 @@ function handleStreamCompleteRedirect(context) {
|
|
|
93
108
|
to && write(`<script>window.location="${to}"</script>`);
|
|
94
109
|
};
|
|
95
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
*
|
|
113
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/server/create-handler
|
|
114
|
+
*/
|
|
96
115
|
export function createHandler(fn, options) {
|
|
97
116
|
return createBaseHandler(fn, createPageEvent, options);
|
|
98
117
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { Component } from "solid-js";
|
|
2
2
|
import type { DocumentComponentProps } from "../types";
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/server/start-server
|
|
6
|
+
*/
|
|
3
7
|
export declare function StartServer(props: {
|
|
4
8
|
document: Component<DocumentComponentProps>;
|
|
5
9
|
}): import("solid-js").JSX.Element;
|
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import { NoHydration, getRequestEvent, ssr } from "solid-js/web";
|
|
2
|
+
import { TopErrorBoundary } from "../../shared/ErrorBoundary";
|
|
2
3
|
import { renderAsset } from "../renderAsset";
|
|
3
4
|
const docType = ssr("<!DOCTYPE html>");
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/server/start-server
|
|
8
|
+
*/
|
|
4
9
|
export function StartServer(props) {
|
|
5
10
|
const context = getRequestEvent();
|
|
6
11
|
// @ts-ignore
|
|
7
12
|
const nonce = context.nonce;
|
|
8
13
|
return (<NoHydration>
|
|
9
14
|
{docType}
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
<TopErrorBoundary>
|
|
16
|
+
<props.document assets={<>{context.assets.map((m) => renderAsset(m))}</>} scripts={nonce ? (<>
|
|
17
|
+
<script nonce={nonce} innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`}/>
|
|
18
|
+
<script type="module" src={import.meta.env.MANIFEST["client"].inputs[import.meta.env.MANIFEST["client"].handler].output.path}/>
|
|
19
|
+
</>) : (<>
|
|
20
|
+
<script innerHTML={`window.manifest = ${JSON.stringify(context.manifest)}`}/>
|
|
21
|
+
<script type="module" src={import.meta.env.MANIFEST["client"].inputs[import.meta.env.MANIFEST["client"].handler].output.path}/>
|
|
22
|
+
</>)}/>
|
|
23
|
+
</TopErrorBoundary>
|
|
17
24
|
</NoHydration>);
|
|
18
25
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import { FetchEvent, HandlerOptions, PageEvent } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/server/create-handler
|
|
5
|
+
*/
|
|
2
6
|
export declare function createHandler(fn: (context: PageEvent) => unknown, options?: HandlerOptions | ((context: PageEvent) => HandlerOptions)): import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<any>>;
|
|
3
7
|
export declare function createPageEvent(ctx: FetchEvent): Promise<PageEvent>;
|
|
@@ -1,16 +1,36 @@
|
|
|
1
1
|
// @refresh skip
|
|
2
|
-
import { ErrorBoundary as DefaultErrorBoundary } from "solid-js";
|
|
2
|
+
import { ErrorBoundary as DefaultErrorBoundary, catchError } from "solid-js";
|
|
3
3
|
import { isServer } from "solid-js/web";
|
|
4
4
|
import { HttpStatusCode } from "./HttpStatusCode";
|
|
5
5
|
import { DevOverlay } from "./dev-overlay";
|
|
6
6
|
export const ErrorBoundary = import.meta.env.DEV && import.meta.env.START_DEV_OVERLAY
|
|
7
7
|
? (props) => <DevOverlay>{props.children}</DevOverlay>
|
|
8
8
|
: (props) => {
|
|
9
|
-
const message = isServer
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
const message = isServer
|
|
10
|
+
? "500 | Internal Server Error"
|
|
11
|
+
: "Error | Uncaught Client Exception";
|
|
12
|
+
return (<DefaultErrorBoundary fallback={error => {
|
|
13
|
+
console.error(error);
|
|
14
|
+
return (<>
|
|
15
|
+
<span style="font-size:1.5em;text-align:center;position:fixed;left:0px;bottom:55%;width:100%;">
|
|
16
|
+
{message}
|
|
17
|
+
</span>
|
|
18
|
+
<HttpStatusCode code={500}/>
|
|
19
|
+
</>);
|
|
20
|
+
}}>
|
|
21
|
+
{props.children}
|
|
22
|
+
</DefaultErrorBoundary>);
|
|
16
23
|
};
|
|
24
|
+
export const TopErrorBoundary = (props) => {
|
|
25
|
+
let isError = false;
|
|
26
|
+
const res = catchError(() => props.children, err => {
|
|
27
|
+
console.error(err);
|
|
28
|
+
isError = !!err;
|
|
29
|
+
});
|
|
30
|
+
return isError ? (<>
|
|
31
|
+
<span style="font-size:1.5em;text-align:center;position:fixed;left:0px;bottom:55%;width:100%;">
|
|
32
|
+
500 | Internal Server Error
|
|
33
|
+
</span>
|
|
34
|
+
<HttpStatusCode code={500}/>
|
|
35
|
+
</>) : (res);
|
|
36
|
+
};
|
package/dist/shared/GET.d.ts
CHANGED
package/dist/shared/GET.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// @refresh skip
|
|
2
2
|
import { onCleanup } from "solid-js";
|
|
3
3
|
import { getRequestEvent, isServer } from "solid-js/web";
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/server/http-header
|
|
7
|
+
*/
|
|
4
8
|
export const HttpHeader = isServer
|
|
5
9
|
? (props) => {
|
|
6
10
|
const event = getRequestEvent();
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// @refresh skip
|
|
2
2
|
import { onCleanup } from "solid-js";
|
|
3
3
|
import { getRequestEvent, isServer } from "solid-js/web";
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/server/http-status-code
|
|
7
|
+
*/
|
|
4
8
|
export const HttpStatusCode = isServer
|
|
5
9
|
? (props) => {
|
|
6
10
|
const event = getRequestEvent();
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { Component, ComponentProps, JSX } from "solid-js";
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/client/client-only
|
|
5
|
+
*/
|
|
2
6
|
export default function clientOnly<T extends Component<any>>(fn: () => Promise<{
|
|
3
7
|
default: T;
|
|
4
8
|
}>): (props: ComponentProps<T> & {
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { createMemo, createSignal, onMount, sharedConfig, splitProps, untrack } from "solid-js";
|
|
2
2
|
import { isServer } from "solid-js/web";
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* Read more: https://docs.solidjs.com/solid-start/reference/client/client-only
|
|
6
|
+
*/
|
|
3
7
|
// not using Suspense
|
|
4
8
|
export default function clientOnly(fn) {
|
|
5
9
|
if (isServer)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidjs/start",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Ryan Carniato",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,7 +29,11 @@
|
|
|
29
29
|
"./server/spa": "./dist/server/spa/index.jsx",
|
|
30
30
|
"./client": "./dist/client/index.jsx",
|
|
31
31
|
"./client/islands": "./dist/client/islands.jsx",
|
|
32
|
-
"./client/spa": "./dist/client/spa/index.jsx"
|
|
32
|
+
"./client/spa": "./dist/client/spa/index.jsx",
|
|
33
|
+
"./env": {
|
|
34
|
+
"types": "./env.d.ts",
|
|
35
|
+
"import": null
|
|
36
|
+
}
|
|
33
37
|
},
|
|
34
38
|
"typesVersions": {
|
|
35
39
|
"*": {
|