@solidjs/start 0.4.2 → 0.4.3
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 +5 -0
- package/config/index.js +12 -12
- package/config/server-fns-runtime.jsx +1 -1
- package/config/server-handler.js +37 -23
- package/config/server-runtime.jsx +9 -1
- package/package.json +13 -8
- package/server/handler.tsx +6 -1
- package/server/spa/StartServer.tsx +0 -1
- package/shared/ErrorBoundary.tsx +16 -39
- package/shared/dev-overlay/CodeView.tsx +74 -0
- package/shared/dev-overlay/DevOverlayDialog.tsx +277 -0
- package/shared/dev-overlay/createStackFrame.ts +57 -0
- package/shared/dev-overlay/download.ts +6 -0
- package/shared/dev-overlay/env.d.ts +4 -0
- package/shared/dev-overlay/get-source-map.ts +35 -0
- package/shared/dev-overlay/icons.tsx +287 -0
- package/shared/dev-overlay/index.tsx +60 -0
- package/shared/dev-overlay/styles.css +287 -0
- package/shared/routes.ts +3 -2
package/config/index.d.ts
CHANGED
|
@@ -3,6 +3,11 @@ import { InlineConfig } from "vite";
|
|
|
3
3
|
|
|
4
4
|
type SolidStartInlineConfig = Omit<InlineConfig, "router"> & {
|
|
5
5
|
start?: {
|
|
6
|
+
/**
|
|
7
|
+
* true: streaming mode
|
|
8
|
+
* false: csr only
|
|
9
|
+
* async: ssr is in async mode
|
|
10
|
+
*/
|
|
6
11
|
ssr?: boolean | "async",
|
|
7
12
|
extensions?: string[],
|
|
8
13
|
server?: AppOptions['server'],
|
package/config/index.js
CHANGED
|
@@ -38,29 +38,27 @@ function solidStartServerFsRouter(config) {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export function defineConfig(baseConfig = {}) {
|
|
41
|
-
let { plugins = [], start = {},
|
|
41
|
+
let { plugins = [], start = {}, ...userConfig } = baseConfig;
|
|
42
42
|
const extensions = [...DEFAULT_EXTENSIONS, ...(start.extensions || [])];
|
|
43
43
|
start = defu(start, {
|
|
44
44
|
appRoot: "./src",
|
|
45
45
|
ssr: true,
|
|
46
46
|
islands: false,
|
|
47
|
-
server: { base },
|
|
48
47
|
solid: {}
|
|
49
48
|
});
|
|
50
49
|
let server = start.server;
|
|
51
50
|
if (!start.ssr) {
|
|
52
51
|
server = { ...server, prerender: { routes: ["/"] } };
|
|
53
52
|
}
|
|
54
|
-
|
|
55
|
-
let entryExtension = ".tsx"
|
|
53
|
+
let entryExtension = ".tsx";
|
|
56
54
|
if (existsSync(join(process.cwd(), start.appRoot, "app.jsx"))) {
|
|
57
|
-
entryExtension = ".jsx"
|
|
55
|
+
entryExtension = ".jsx";
|
|
58
56
|
}
|
|
59
57
|
|
|
60
58
|
return createApp({
|
|
61
59
|
server: {
|
|
62
60
|
compressPublicAssets: {
|
|
63
|
-
brotli: true
|
|
61
|
+
brotli: process.versions.bun ? false : true
|
|
64
62
|
},
|
|
65
63
|
...server
|
|
66
64
|
},
|
|
@@ -80,9 +78,10 @@ export function defineConfig(baseConfig = {}) {
|
|
|
80
78
|
routes: solidStartServerFsRouter({ dir: `${start.appRoot}/routes`, extensions }),
|
|
81
79
|
extensions,
|
|
82
80
|
target: "server",
|
|
83
|
-
plugins: () => [
|
|
81
|
+
plugins: async () => [
|
|
84
82
|
config("user", userConfig),
|
|
85
|
-
...plugins,
|
|
83
|
+
...(typeof plugins === "function" ? [...(await plugins())] : plugins),
|
|
84
|
+
|
|
86
85
|
serverTransform({
|
|
87
86
|
runtime: normalize(fileURLToPath(new URL("./server-fns-runtime.jsx", import.meta.url)))
|
|
88
87
|
}),
|
|
@@ -121,9 +120,9 @@ export function defineConfig(baseConfig = {}) {
|
|
|
121
120
|
}),
|
|
122
121
|
extensions,
|
|
123
122
|
target: "browser",
|
|
124
|
-
plugins: () => [
|
|
123
|
+
plugins: async () => [
|
|
125
124
|
config("user", userConfig),
|
|
126
|
-
...plugins,
|
|
125
|
+
...(typeof plugins === "function" ? [...(await plugins())] : plugins),
|
|
127
126
|
serverFunctions.client({
|
|
128
127
|
runtime: normalize(fileURLToPath(new URL("./server-runtime.jsx", import.meta.url)))
|
|
129
128
|
}),
|
|
@@ -161,9 +160,10 @@ export function defineConfig(baseConfig = {}) {
|
|
|
161
160
|
handler: normalize(fileURLToPath(new URL("./server-handler.js", import.meta.url))),
|
|
162
161
|
runtime: normalize(fileURLToPath(new URL("./server-fns-runtime.jsx", import.meta.url))),
|
|
163
162
|
// routes: solidStartServerFsRouter({ dir: `${start.appRoot}/routes`, extensions }),
|
|
164
|
-
plugins: () => [
|
|
163
|
+
plugins: async () => [
|
|
165
164
|
config("user", userConfig),
|
|
166
|
-
...plugins,
|
|
165
|
+
...(typeof plugins === "function" ? [...(await plugins())] : plugins),
|
|
166
|
+
|
|
167
167
|
solid({ ...start.solid, ssr: true, extensions: extensions.map(ext => `.${ext}`) }),
|
|
168
168
|
config("app-server", {
|
|
169
169
|
resolve: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getRequestEvent } from "solid-js/web";
|
|
2
2
|
import { provideRequestEvent } from "solid-js/web/storage";
|
|
3
|
-
import { cloneEvent } from "../server";
|
|
3
|
+
import { cloneEvent } from "../server/middleware";
|
|
4
4
|
|
|
5
5
|
export function createServerReference(fn, id, name) {
|
|
6
6
|
return new Proxy(fn, {
|
package/config/server-handler.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="vinxi/types/server" />
|
|
2
|
-
import { crossSerializeStream, fromJSON } from "seroval";
|
|
2
|
+
import { crossSerializeStream, fromJSON, getCrossReferenceHeader } from "seroval";
|
|
3
3
|
import {
|
|
4
4
|
CustomEventPlugin,
|
|
5
5
|
DOMExceptionPlugin,
|
|
@@ -10,8 +10,10 @@ import {
|
|
|
10
10
|
RequestPlugin,
|
|
11
11
|
ResponsePlugin,
|
|
12
12
|
URLPlugin,
|
|
13
|
-
URLSearchParamsPlugin
|
|
14
|
-
} from
|
|
13
|
+
URLSearchParamsPlugin
|
|
14
|
+
} from "seroval-plugins/web";
|
|
15
|
+
import { sharedConfig } from "solid-js";
|
|
16
|
+
/* @ts-ignore */
|
|
15
17
|
import { provideRequestEvent } from "solid-js/web/storage";
|
|
16
18
|
import invariant from "vinxi/lib/invariant";
|
|
17
19
|
import {
|
|
@@ -19,7 +21,7 @@ import {
|
|
|
19
21
|
getHeader,
|
|
20
22
|
getRequestURL,
|
|
21
23
|
readBody,
|
|
22
|
-
|
|
24
|
+
readRawBody,
|
|
23
25
|
setHeader
|
|
24
26
|
} from "vinxi/server";
|
|
25
27
|
import { getFetchEvent } from "../server/middleware";
|
|
@@ -39,10 +41,10 @@ function serializeToStream(id, value) {
|
|
|
39
41
|
RequestPlugin,
|
|
40
42
|
ResponsePlugin,
|
|
41
43
|
URLSearchParamsPlugin,
|
|
42
|
-
URLPlugin
|
|
44
|
+
URLPlugin
|
|
43
45
|
],
|
|
44
46
|
onSerialize(data, initial) {
|
|
45
|
-
const result = initial ? `($
|
|
47
|
+
const result = initial ? `(${getCrossReferenceHeader(id)},${data})` : data;
|
|
46
48
|
controller.enqueue(new TextEncoder().encode(`${result};\n`));
|
|
47
49
|
},
|
|
48
50
|
onDone() {
|
|
@@ -89,7 +91,15 @@ async function handleServerFunction(event) {
|
|
|
89
91
|
contentType.startsWith("multipart/form-data") ||
|
|
90
92
|
contentType.startsWith("application/x-www-form-urlencoded")
|
|
91
93
|
) {
|
|
92
|
-
|
|
94
|
+
// Temporary workaround until https://github.com/unjs/nitro/issues/1721 is resolved
|
|
95
|
+
// parsed.push(await readFormData(event));
|
|
96
|
+
|
|
97
|
+
const request = new Request(getRequestURL(event), {
|
|
98
|
+
method: event.method,
|
|
99
|
+
headers: event.headers,
|
|
100
|
+
body: await readRawBody(event)
|
|
101
|
+
});
|
|
102
|
+
parsed.push(await request.formData());
|
|
93
103
|
} else {
|
|
94
104
|
parsed = fromJSON(await readBody(event), {
|
|
95
105
|
plugins: [
|
|
@@ -102,12 +112,17 @@ async function handleServerFunction(event) {
|
|
|
102
112
|
RequestPlugin,
|
|
103
113
|
ResponsePlugin,
|
|
104
114
|
URLSearchParamsPlugin,
|
|
105
|
-
URLPlugin
|
|
106
|
-
]
|
|
115
|
+
URLPlugin
|
|
116
|
+
]
|
|
107
117
|
});
|
|
108
118
|
}
|
|
109
119
|
try {
|
|
110
|
-
const
|
|
120
|
+
const evt = getFetchEvent(event);
|
|
121
|
+
const result = await provideRequestEvent(evt, () => {
|
|
122
|
+
/* @ts-ignore */
|
|
123
|
+
sharedConfig.context = { event: evt };
|
|
124
|
+
return action(...parsed);
|
|
125
|
+
});
|
|
111
126
|
|
|
112
127
|
// handle no JS success case
|
|
113
128
|
if (!instance) {
|
|
@@ -117,16 +132,20 @@ async function handleServerFunction(event) {
|
|
|
117
132
|
status: 302,
|
|
118
133
|
headers: {
|
|
119
134
|
Location: refererUrl.toString(),
|
|
120
|
-
...(result
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
135
|
+
...(result
|
|
136
|
+
? {
|
|
137
|
+
"Set-Cookie": `flash=${JSON.stringify({
|
|
138
|
+
url: url.pathname + encodeURIComponent(url.search),
|
|
139
|
+
result: isError ? result.message : result,
|
|
140
|
+
error: isError,
|
|
141
|
+
input: [...parsed.slice(0, -1), [...parsed[parsed.length - 1].entries()]]
|
|
142
|
+
})}; Secure; HttpOnly;`
|
|
143
|
+
}
|
|
144
|
+
: {})
|
|
126
145
|
}
|
|
127
146
|
});
|
|
128
147
|
}
|
|
129
|
-
|
|
148
|
+
if (typeof result === "string") return new Response(result);
|
|
130
149
|
setHeader(event, "content-type", "text/javascript");
|
|
131
150
|
return serializeToStream(instance, result);
|
|
132
151
|
} catch (x) {
|
|
@@ -138,12 +157,7 @@ async function handleServerFunction(event) {
|
|
|
138
157
|
}
|
|
139
158
|
});
|
|
140
159
|
}
|
|
141
|
-
return
|
|
142
|
-
status: 500,
|
|
143
|
-
headers: {
|
|
144
|
-
"Content-Type": "text/javascript"
|
|
145
|
-
}
|
|
146
|
-
});
|
|
160
|
+
return x;
|
|
147
161
|
}
|
|
148
162
|
}
|
|
149
163
|
|
|
@@ -104,7 +104,15 @@ async function fetchServerFunction(base, id, args) {
|
|
|
104
104
|
}
|
|
105
105
|
throw response;
|
|
106
106
|
}
|
|
107
|
-
const
|
|
107
|
+
const contentType = response.headers.get("Content-Type");
|
|
108
|
+
let result;
|
|
109
|
+
if (contentType && contentType.startsWith("text/plain")) {
|
|
110
|
+
result = await response.text();
|
|
111
|
+
} else if(contentType && contentType.startsWith("application/json")) {
|
|
112
|
+
result = await response.json();
|
|
113
|
+
} else {
|
|
114
|
+
result = deserializeStream(instance, response);
|
|
115
|
+
}
|
|
108
116
|
if (response.ok) {
|
|
109
117
|
return result;
|
|
110
118
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidjs/start",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Ryan Carniato",
|
|
6
6
|
"publishConfig": {
|
|
@@ -38,16 +38,21 @@
|
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"solid-js": "^1.8.
|
|
42
|
-
"vinxi": "0.
|
|
41
|
+
"solid-js": "^1.8.8",
|
|
42
|
+
"vinxi": "0.1.1"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@vinxi/plugin-directives": "0.0
|
|
46
|
-
"@vinxi/server-components": "0.0
|
|
47
|
-
"@vinxi/server-functions": "0.0
|
|
45
|
+
"@vinxi/plugin-directives": "^0.1.0",
|
|
46
|
+
"@vinxi/server-components": "^0.1.0",
|
|
47
|
+
"@vinxi/server-functions": "^0.1.0",
|
|
48
48
|
"defu": "^6.1.2",
|
|
49
|
-
"
|
|
50
|
-
"
|
|
49
|
+
"error-stack-parser": "^2.1.4",
|
|
50
|
+
"html-to-image": "^1.11.11",
|
|
51
|
+
"seroval": "^1.0.2",
|
|
52
|
+
"seroval-plugins": "^1.0.2",
|
|
53
|
+
"shikiji": "^0.9.12",
|
|
54
|
+
"source-map-js": "^1.0.2",
|
|
55
|
+
"terracotta": "^1.0.4",
|
|
51
56
|
"vite-plugin-inspect": "^0.7.33",
|
|
52
57
|
"vite-plugin-solid": "^2.8.0"
|
|
53
58
|
},
|
package/server/handler.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sharedConfig } from "solid-js";
|
|
1
2
|
import { renderToStream } from "solid-js/web";
|
|
2
3
|
/* @ts-ignore */
|
|
3
4
|
import { provideRequestEvent } from "solid-js/web/storage";
|
|
@@ -42,6 +43,7 @@ export function createHandler(
|
|
|
42
43
|
const mod = await match.handler.import();
|
|
43
44
|
const fn = mod[event.request.method];
|
|
44
45
|
(event as APIEvent).params = match.params;
|
|
46
|
+
sharedConfig.context = { event } as any;
|
|
45
47
|
return await fn(event);
|
|
46
48
|
}
|
|
47
49
|
|
|
@@ -63,7 +65,10 @@ export function createHandler(
|
|
|
63
65
|
og(options);
|
|
64
66
|
};
|
|
65
67
|
} else cloned.onCompleteShell = handleShellCompleteRedirect(context, e);
|
|
66
|
-
const stream = renderToStream(() =>
|
|
68
|
+
const stream = renderToStream(() => {
|
|
69
|
+
(sharedConfig.context as any).event = context;
|
|
70
|
+
return fn(context)
|
|
71
|
+
}, cloned);
|
|
67
72
|
if (context.response && context.response.headers.get("Location")) {
|
|
68
73
|
return sendRedirect(event, context.response.headers.get("Location"));
|
|
69
74
|
}
|
package/shared/ErrorBoundary.tsx
CHANGED
|
@@ -1,48 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
ErrorBoundary as ErrorBoundaryBase,
|
|
2
|
+
ErrorBoundary as DefaultErrorBoundary,
|
|
4
3
|
ParentProps,
|
|
5
|
-
resetErrorBoundaries
|
|
6
4
|
} from "solid-js";
|
|
5
|
+
import { HttpStatusCode } from "./HttpStatusCode";
|
|
6
|
+
import { DevOverlay } from "./dev-overlay";
|
|
7
7
|
|
|
8
8
|
export function ErrorBoundary(props: ParentProps) {
|
|
9
|
+
if (import.meta.env.DEV) {
|
|
10
|
+
return (
|
|
11
|
+
<DevOverlay>
|
|
12
|
+
{props.children}
|
|
13
|
+
</DevOverlay>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
9
16
|
return (
|
|
10
|
-
<
|
|
17
|
+
<DefaultErrorBoundary
|
|
18
|
+
fallback={(
|
|
19
|
+
<HttpStatusCode code={500} />
|
|
20
|
+
)}
|
|
21
|
+
>
|
|
11
22
|
{props.children}
|
|
12
|
-
</
|
|
13
|
-
);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function ErrorMessage(props: { error: any }) {
|
|
17
|
-
createEffect(() => console.error(props.error));
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<div style="padding: 16px">
|
|
21
|
-
<div
|
|
22
|
-
style={`
|
|
23
|
-
background-color: rgba(252, 165, 165);
|
|
24
|
-
color: rgb(153, 27, 27);
|
|
25
|
-
border-radius": 5px;
|
|
26
|
-
overflow: scroll;
|
|
27
|
-
padding: 16px;
|
|
28
|
-
margin-bottom: 8px;
|
|
29
|
-
`}
|
|
30
|
-
>
|
|
31
|
-
<p style="font-weight: bold" id="error-message">
|
|
32
|
-
{props.error.message}
|
|
33
|
-
</p>
|
|
34
|
-
<button
|
|
35
|
-
id="reset-errors"
|
|
36
|
-
onClick={resetErrorBoundaries}
|
|
37
|
-
style={`color: rgba(252, 165, 165);
|
|
38
|
-
background-color: rgb(153, 27, 27);
|
|
39
|
-
border-radius: 5px;
|
|
40
|
-
padding: 4px 8px`}
|
|
41
|
-
>
|
|
42
|
-
Clear errors and retry
|
|
43
|
-
</button>
|
|
44
|
-
<pre style={"margin-top: 8px;width:100%"}>{props.error.stack}</pre>
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
23
|
+
</DefaultErrorBoundary>
|
|
47
24
|
);
|
|
48
25
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as shikiji from 'shikiji';
|
|
2
|
+
import { createEffect, createResource, type JSX } from 'solid-js';
|
|
3
|
+
|
|
4
|
+
let HIGHLIGHTER: shikiji.Highlighter;
|
|
5
|
+
|
|
6
|
+
async function loadHighlighter() {
|
|
7
|
+
if (!HIGHLIGHTER) {
|
|
8
|
+
HIGHLIGHTER = await shikiji.getHighlighter({
|
|
9
|
+
themes: ['dark-plus'],
|
|
10
|
+
langs: ['js', 'ts', 'jsx', 'tsx'],
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
return HIGHLIGHTER;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface CodeViewProps {
|
|
17
|
+
fileName: string;
|
|
18
|
+
content: string;
|
|
19
|
+
line: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const RANGE = 8;
|
|
23
|
+
|
|
24
|
+
export function CodeView(props: CodeViewProps): JSX.Element | null {
|
|
25
|
+
const lines = () =>
|
|
26
|
+
props.content.split('\n').map((item, index) => ({
|
|
27
|
+
index: index + 1,
|
|
28
|
+
line: item,
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
const minLine = () => Math.max(props.line - (1 + RANGE), 0);
|
|
32
|
+
const maxLine = () => Math.min(props.line + RANGE, lines().length - 1);
|
|
33
|
+
|
|
34
|
+
let ref: HTMLDivElement | undefined;
|
|
35
|
+
|
|
36
|
+
const [data] = createResource(() => (
|
|
37
|
+
lines()
|
|
38
|
+
.slice(minLine(), maxLine())
|
|
39
|
+
.map(item => item.line)
|
|
40
|
+
.join('\n')
|
|
41
|
+
) ,async (value) => {
|
|
42
|
+
const highlighter = await loadHighlighter();
|
|
43
|
+
const lang = props.fileName
|
|
44
|
+
.split(/[#?]/)[0]
|
|
45
|
+
.split('.')
|
|
46
|
+
.pop()
|
|
47
|
+
?.trim() as shikiji.BuiltinLanguage;
|
|
48
|
+
await highlighter.loadLanguage(lang);
|
|
49
|
+
return highlighter.codeToHtml(value, {
|
|
50
|
+
theme: 'dark-plus',
|
|
51
|
+
lang,
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
createEffect(() => {
|
|
56
|
+
const result = data();
|
|
57
|
+
if (ref && result) {
|
|
58
|
+
ref.innerHTML = result;
|
|
59
|
+
|
|
60
|
+
const lines = ref.querySelectorAll('span[class="line"]');
|
|
61
|
+
|
|
62
|
+
for (let i = 0, len = lines.length; i < len; i++) {
|
|
63
|
+
const el = lines[i];
|
|
64
|
+
if ((props.line - minLine() - 1) === i) {
|
|
65
|
+
el.innerHTML = `<mark style="background-color:#aaaaaa80">${el.innerHTML}</mark>`;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return <div ref={ref} class="dev-overlay-code-view" style={{
|
|
72
|
+
'--dev-overlay-code-view-start': minLine() + 1,
|
|
73
|
+
}} />;
|
|
74
|
+
}
|