@solidjs/start 0.4.10 → 0.4.11
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.js +15 -12
- package/config/server-fns-runtime.jsx +2 -0
- package/config/server-handler.js +77 -36
- package/config/server-runtime.jsx +44 -25
- package/package.json +7 -7
- package/server/page-event.tsx +8 -13
- package/shared/GET.ts +5 -0
- package/shared/dev-overlay/DevOverlayDialog.tsx +51 -49
- package/shared/dev-overlay/createStackFrame.ts +9 -1
- package/shared/dev-overlay/styles.css +5 -1
- package/shared/index.tsx +2 -1
package/config/index.js
CHANGED
|
@@ -73,6 +73,9 @@ export function defineConfig(baseConfig = {}) {
|
|
|
73
73
|
{
|
|
74
74
|
name: "ssr",
|
|
75
75
|
mode: "handler",
|
|
76
|
+
link: {
|
|
77
|
+
client: "client"
|
|
78
|
+
},
|
|
76
79
|
handler: `${start.appRoot}/entry-server${entryExtension}`,
|
|
77
80
|
middleware: start.middleware,
|
|
78
81
|
routes: solidStartServerFsRouter({ dir: `${start.appRoot}/routes`, extensions }),
|
|
@@ -85,10 +88,10 @@ export function defineConfig(baseConfig = {}) {
|
|
|
85
88
|
...(userConfig.optimizeDeps || {}),
|
|
86
89
|
include: [
|
|
87
90
|
...(userConfig.optimizeDeps?.include || []),
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
]
|
|
91
|
-
}
|
|
91
|
+
"@solidjs/start > source-map-js",
|
|
92
|
+
"@solidjs/start > error-stack-parser"
|
|
93
|
+
]
|
|
94
|
+
}
|
|
92
95
|
}),
|
|
93
96
|
...(typeof plugins === "function" ? [...(await plugins())] : plugins),
|
|
94
97
|
|
|
@@ -138,10 +141,10 @@ export function defineConfig(baseConfig = {}) {
|
|
|
138
141
|
...(userConfig.optimizeDeps || {}),
|
|
139
142
|
include: [
|
|
140
143
|
...(userConfig.optimizeDeps?.include || []),
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
]
|
|
144
|
-
}
|
|
144
|
+
"@solidjs/start > source-map-js",
|
|
145
|
+
"@solidjs/start > error-stack-parser"
|
|
146
|
+
]
|
|
147
|
+
}
|
|
145
148
|
}),
|
|
146
149
|
...(typeof plugins === "function" ? [...(await plugins())] : plugins),
|
|
147
150
|
serverFunctions.client({
|
|
@@ -189,10 +192,10 @@ export function defineConfig(baseConfig = {}) {
|
|
|
189
192
|
...(userConfig.optimizeDeps || {}),
|
|
190
193
|
include: [
|
|
191
194
|
...(userConfig.optimizeDeps?.include || []),
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
]
|
|
195
|
-
}
|
|
195
|
+
"@solidjs/start > source-map-js",
|
|
196
|
+
"@solidjs/start > error-stack-parser"
|
|
197
|
+
]
|
|
198
|
+
}
|
|
196
199
|
}),
|
|
197
200
|
...(typeof plugins === "function" ? [...(await plugins())] : plugins),
|
|
198
201
|
|
|
@@ -3,12 +3,14 @@ import { provideRequestEvent } from "solid-js/web/storage";
|
|
|
3
3
|
import { cloneEvent } from "../server/middleware";
|
|
4
4
|
|
|
5
5
|
export function createServerReference(fn, id, name) {
|
|
6
|
+
if (typeof fn !== "function") throw new Error("Export from a 'use server' module must be a function");
|
|
6
7
|
const baseURL = import.meta.env.SERVER_BASE_URL;
|
|
7
8
|
return new Proxy(fn, {
|
|
8
9
|
get(target, prop, receiver) {
|
|
9
10
|
if (prop === "url") {
|
|
10
11
|
return `${baseURL}/_server?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}`;
|
|
11
12
|
}
|
|
13
|
+
if (prop === "GET") return receiver;
|
|
12
14
|
},
|
|
13
15
|
apply(target, thisArg, args) {
|
|
14
16
|
const ogEvt = getRequestEvent();
|
package/config/server-handler.js
CHANGED
|
@@ -16,16 +16,13 @@ import { sharedConfig } from "solid-js";
|
|
|
16
16
|
/* @ts-ignore */
|
|
17
17
|
import { provideRequestEvent } from "solid-js/web/storage";
|
|
18
18
|
import invariant from "vinxi/lib/invariant";
|
|
19
|
-
import {
|
|
20
|
-
eventHandler,
|
|
21
|
-
setHeader
|
|
22
|
-
} from "vinxi/server";
|
|
19
|
+
import { eventHandler, setHeader } from "vinxi/server";
|
|
23
20
|
import { getFetchEvent } from "../server/middleware";
|
|
24
21
|
|
|
25
22
|
function createChunk(data) {
|
|
26
23
|
const bytes = data.length;
|
|
27
24
|
const baseHex = bytes.toString(16);
|
|
28
|
-
const totalHex =
|
|
25
|
+
const totalHex = "00000000".substring(0, 8 - baseHex.length) + baseHex; // 32-bit
|
|
29
26
|
return new TextEncoder().encode(`;0x${totalHex};${data}`);
|
|
30
27
|
}
|
|
31
28
|
|
|
@@ -47,7 +44,9 @@ function serializeToStream(id, value) {
|
|
|
47
44
|
URLPlugin
|
|
48
45
|
],
|
|
49
46
|
onSerialize(data, initial) {
|
|
50
|
-
controller.enqueue(
|
|
47
|
+
controller.enqueue(
|
|
48
|
+
createChunk(initial ? `(${getCrossReferenceHeader(id)},${data})` : data)
|
|
49
|
+
);
|
|
51
50
|
},
|
|
52
51
|
onDone() {
|
|
53
52
|
controller.close();
|
|
@@ -61,7 +60,6 @@ function serializeToStream(id, value) {
|
|
|
61
60
|
}
|
|
62
61
|
|
|
63
62
|
async function handleServerFunction(h3Event) {
|
|
64
|
-
invariant(h3Event.method === "POST", `Invalid method ${h3Event.method}. Expected POST.`);
|
|
65
63
|
const event = getFetchEvent(h3Event);
|
|
66
64
|
const request = event.request;
|
|
67
65
|
|
|
@@ -84,39 +82,71 @@ async function handleServerFunction(h3Event) {
|
|
|
84
82
|
let parsed = [];
|
|
85
83
|
|
|
86
84
|
// grab bound arguments from url when no JS
|
|
87
|
-
if (!instance) {
|
|
85
|
+
if (!instance || h3Event.method === "GET") {
|
|
88
86
|
const args = url.searchParams.get("args");
|
|
89
87
|
if (args) JSON.parse(args).forEach(arg => parsed.push(arg));
|
|
90
88
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
89
|
+
if (h3Event.method === "POST") {
|
|
90
|
+
const contentType = request.headers.get("content-type");
|
|
91
|
+
if (
|
|
92
|
+
contentType.startsWith("multipart/form-data") ||
|
|
93
|
+
contentType.startsWith("application/x-www-form-urlencoded")
|
|
94
|
+
) {
|
|
95
|
+
// workaround for https://github.com/unjs/nitro/issues/1721
|
|
96
|
+
// (issue only in edge runtimes)
|
|
97
|
+
parsed.push(await new Request(request, { ...request, body: event.node.req.body }).formData());
|
|
98
|
+
// what should work when #1721 is fixed
|
|
99
|
+
// parsed.push(await request.formData);
|
|
100
|
+
} else {
|
|
101
|
+
// workaround for https://github.com/unjs/nitro/issues/1721
|
|
102
|
+
// (issue only in edge runtimes)
|
|
103
|
+
const tmpReq = new Request(request, { ...request, body: event.node.req.body })
|
|
104
|
+
// what should work when #1721 is fixed
|
|
105
|
+
// just use request.json() here
|
|
106
|
+
parsed = fromJSON(await tmpReq.json(), {
|
|
107
|
+
plugins: [
|
|
108
|
+
CustomEventPlugin,
|
|
109
|
+
DOMExceptionPlugin,
|
|
110
|
+
EventPlugin,
|
|
111
|
+
FormDataPlugin,
|
|
112
|
+
HeadersPlugin,
|
|
113
|
+
ReadableStreamPlugin,
|
|
114
|
+
RequestPlugin,
|
|
115
|
+
ResponsePlugin,
|
|
116
|
+
URLSearchParamsPlugin,
|
|
117
|
+
URLPlugin
|
|
118
|
+
]
|
|
119
|
+
});
|
|
120
|
+
}
|
|
112
121
|
}
|
|
113
122
|
try {
|
|
114
|
-
|
|
123
|
+
let result = await provideRequestEvent(event, () => {
|
|
115
124
|
/* @ts-ignore */
|
|
116
125
|
sharedConfig.context = { event };
|
|
117
126
|
return action(...parsed);
|
|
118
127
|
});
|
|
119
128
|
|
|
129
|
+
// handle responses
|
|
130
|
+
if (result instanceof Response) {
|
|
131
|
+
if (result.status === 302) {
|
|
132
|
+
return new Response(null, {
|
|
133
|
+
status: instance ? 204 : 302,
|
|
134
|
+
headers: {
|
|
135
|
+
Location: result.headers.get("Location")
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// forward headers
|
|
140
|
+
if (result.headers) {
|
|
141
|
+
for (const [key, value] of result.headers.entries()) {
|
|
142
|
+
setHeader(h3Event, key, value);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (result.customBody) {
|
|
146
|
+
result = await result.customBody();
|
|
147
|
+
} else if (result.body == undefined) result = undefined;
|
|
148
|
+
}
|
|
149
|
+
|
|
120
150
|
// handle no JS success case
|
|
121
151
|
if (!instance) {
|
|
122
152
|
const isError = result instanceof Error;
|
|
@@ -142,13 +172,24 @@ async function handleServerFunction(h3Event) {
|
|
|
142
172
|
setHeader(h3Event, "content-type", "text/javascript");
|
|
143
173
|
return serializeToStream(instance, result);
|
|
144
174
|
} catch (x) {
|
|
145
|
-
if (x instanceof Response
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
175
|
+
if (x instanceof Response) {
|
|
176
|
+
if (x.status === 302) {
|
|
177
|
+
return new Response(null, {
|
|
178
|
+
status: instance ? 204 : 302,
|
|
179
|
+
headers: {
|
|
180
|
+
Location: x.headers.get("Location")
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
// forward headers
|
|
185
|
+
if (x.headers) {
|
|
186
|
+
for (const [key, value] of x.headers.entries()) {
|
|
187
|
+
setHeader(h3Event, key, value);
|
|
150
188
|
}
|
|
151
|
-
}
|
|
189
|
+
}
|
|
190
|
+
if (x.customBody) {
|
|
191
|
+
x = await x.customBody();
|
|
192
|
+
} else if (x.body == undefined) x = undefined;
|
|
152
193
|
}
|
|
153
194
|
return x;
|
|
154
195
|
}
|
|
@@ -9,14 +9,14 @@ import {
|
|
|
9
9
|
RequestPlugin,
|
|
10
10
|
ResponsePlugin,
|
|
11
11
|
URLPlugin,
|
|
12
|
-
URLSearchParamsPlugin
|
|
13
|
-
} from
|
|
12
|
+
URLSearchParamsPlugin
|
|
13
|
+
} from "seroval-plugins/web";
|
|
14
14
|
import { createIslandReference } from "../server/islands";
|
|
15
15
|
|
|
16
16
|
class SerovalChunkReader {
|
|
17
17
|
constructor(stream) {
|
|
18
18
|
this.reader = stream.getReader();
|
|
19
|
-
this.buffer =
|
|
19
|
+
this.buffer = "";
|
|
20
20
|
this.done = false;
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -33,12 +33,12 @@ class SerovalChunkReader {
|
|
|
33
33
|
|
|
34
34
|
async next() {
|
|
35
35
|
// Check if the buffer is empty
|
|
36
|
-
if (this.buffer ===
|
|
36
|
+
if (this.buffer === "") {
|
|
37
37
|
// if we are already done...
|
|
38
38
|
if (this.done) {
|
|
39
39
|
return {
|
|
40
40
|
done: true,
|
|
41
|
-
value: undefined
|
|
41
|
+
value: undefined
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
// Otherwise, read a new chunk
|
|
@@ -55,7 +55,7 @@ class SerovalChunkReader {
|
|
|
55
55
|
// If it's not enough, and the reader is done
|
|
56
56
|
// then the chunk is invalid.
|
|
57
57
|
if (this.done) {
|
|
58
|
-
throw new Error(
|
|
58
|
+
throw new Error("Malformed server function stream.");
|
|
59
59
|
}
|
|
60
60
|
// Otherwise, we read more chunks
|
|
61
61
|
await this.readChunk();
|
|
@@ -67,7 +67,7 @@ class SerovalChunkReader {
|
|
|
67
67
|
// Deserialize the chunk
|
|
68
68
|
return {
|
|
69
69
|
done: false,
|
|
70
|
-
value: deserialize(partial)
|
|
70
|
+
value: deserialize(partial)
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -117,31 +117,47 @@ function createRequest(base, id, instance, body, contentType) {
|
|
|
117
117
|
});
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
async function fetchServerFunction(base, id, args) {
|
|
120
|
+
async function fetchServerFunction(base, id, method, args) {
|
|
121
121
|
const instance = `server-fn:${INSTANCE++}`;
|
|
122
|
-
const response = await (
|
|
122
|
+
const response = await (method === "GET"
|
|
123
|
+
? fetch(base + (args.length ? `&args=${JSON.stringify(args)}` : ""), {
|
|
124
|
+
headers: {
|
|
125
|
+
"x-server-instance": instance
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
: args.length === 1 && args[0] instanceof FormData
|
|
123
129
|
? createRequest(base, id, instance, args[0])
|
|
124
|
-
: createRequest(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
: createRequest(
|
|
131
|
+
base,
|
|
132
|
+
id,
|
|
133
|
+
instance,
|
|
134
|
+
JSON.stringify(
|
|
135
|
+
await Promise.resolve(
|
|
136
|
+
toJSONAsync(args, {
|
|
137
|
+
plugins: [
|
|
138
|
+
CustomEventPlugin,
|
|
139
|
+
DOMExceptionPlugin,
|
|
140
|
+
EventPlugin,
|
|
141
|
+
FormDataPlugin,
|
|
142
|
+
HeadersPlugin,
|
|
143
|
+
ReadableStreamPlugin,
|
|
144
|
+
RequestPlugin,
|
|
145
|
+
ResponsePlugin,
|
|
146
|
+
URLSearchParamsPlugin,
|
|
147
|
+
URLPlugin
|
|
148
|
+
]
|
|
149
|
+
})
|
|
150
|
+
)
|
|
151
|
+
),
|
|
152
|
+
"application/json"
|
|
153
|
+
));
|
|
138
154
|
|
|
139
155
|
if (response.headers.get("Location")) throw response;
|
|
140
156
|
if (response.headers.get("X-Revalidate")) {
|
|
141
157
|
/* ts-ignore-next-line */
|
|
142
158
|
response.customBody = () => {
|
|
143
159
|
return deserializeStream(instance, response);
|
|
144
|
-
}
|
|
160
|
+
};
|
|
145
161
|
throw response;
|
|
146
162
|
}
|
|
147
163
|
const contentType = response.headers.get("Content-Type");
|
|
@@ -166,9 +182,12 @@ export function createServerReference(fn, id, name) {
|
|
|
166
182
|
if (prop === "url") {
|
|
167
183
|
return `${baseURL}/_server?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}`;
|
|
168
184
|
}
|
|
185
|
+
if (prop === "GET") {
|
|
186
|
+
return (...args) => fetchServerFunction(`${baseURL}/_server/?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}`, `${id}#${name}`, "GET", args);
|
|
187
|
+
}
|
|
169
188
|
},
|
|
170
189
|
apply(target, thisArg, args) {
|
|
171
|
-
return fetchServerFunction(`${baseURL}/_server`, `${id}#${name}`, args);
|
|
190
|
+
return fetchServerFunction(`${baseURL}/_server`, `${id}#${name}`, "POST", args);
|
|
172
191
|
}
|
|
173
192
|
});
|
|
174
193
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidjs/start",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Ryan Carniato",
|
|
6
6
|
"publishConfig": {
|
|
@@ -43,13 +43,13 @@
|
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"solid-js": "^1.8.
|
|
47
|
-
"vinxi": "^0.1.
|
|
46
|
+
"solid-js": "^1.8.12",
|
|
47
|
+
"vinxi": "^0.1.6"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@vinxi/plugin-directives": "^0.1.
|
|
51
|
-
"@vinxi/server-components": "^0.1.
|
|
52
|
-
"@vinxi/server-functions": "^0.1.
|
|
50
|
+
"@vinxi/plugin-directives": "^0.1.3",
|
|
51
|
+
"@vinxi/server-components": "^0.1.3",
|
|
52
|
+
"@vinxi/server-functions": "^0.1.3",
|
|
53
53
|
"defu": "^6.1.2",
|
|
54
54
|
"error-stack-parser": "^2.1.4",
|
|
55
55
|
"html-to-image": "^1.11.11",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"source-map-js": "^1.0.2",
|
|
60
60
|
"terracotta": "^1.0.4",
|
|
61
61
|
"vite-plugin-inspect": "^0.7.33",
|
|
62
|
-
"vite-plugin-solid": "^2.
|
|
62
|
+
"vite-plugin-solid": "^2.9.1"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|
|
65
65
|
"typecheck": "tsc --noEmit --checkJs false --skipLibCheck"
|
package/server/page-event.tsx
CHANGED
|
@@ -45,7 +45,7 @@ export async function createPageEvent(ctx: FetchEvent) {
|
|
|
45
45
|
components: {
|
|
46
46
|
status: props => {
|
|
47
47
|
setResponseStatus(ctx, props.code, props.text);
|
|
48
|
-
return () => setResponseStatus(ctx, 200);
|
|
48
|
+
return () => !ctx.handled && setResponseStatus(ctx, 200);
|
|
49
49
|
},
|
|
50
50
|
header: props => {
|
|
51
51
|
if (props.append) {
|
|
@@ -55,18 +55,13 @@ export async function createPageEvent(ctx: FetchEvent) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
return () => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
const index = values.indexOf(props.value);
|
|
66
|
-
index !== -1 && values.splice(index, 1);
|
|
67
|
-
if (values.length) setResponseHeader(ctx, props.name, values.join(", "));
|
|
68
|
-
else removeResponseHeader(ctx, props.name);
|
|
69
|
-
}
|
|
58
|
+
if (ctx.handled) return;
|
|
59
|
+
let values = getResponseHeader(ctx, props.name);
|
|
60
|
+
if (!Array.isArray(values)) values = [values as string];
|
|
61
|
+
const index = values.indexOf(props.value);
|
|
62
|
+
index !== -1 && values.splice(index, 1);
|
|
63
|
+
if (values.length) setResponseHeader(ctx, props.name, values);
|
|
64
|
+
else removeResponseHeader(ctx, props.name);
|
|
70
65
|
};
|
|
71
66
|
}
|
|
72
67
|
},
|
package/shared/GET.ts
ADDED
|
@@ -190,7 +190,7 @@ export default function DevOverlayDialog(props: DevOverlayDialogProps): JSX.Elem
|
|
|
190
190
|
if (current) {
|
|
191
191
|
htmlToImage.toPng(current, {
|
|
192
192
|
style: {
|
|
193
|
-
transform: 'scale(
|
|
193
|
+
transform: 'scale(0.75)',
|
|
194
194
|
},
|
|
195
195
|
}).then((url) => {
|
|
196
196
|
download(url, 'start-screenshot.png');
|
|
@@ -216,59 +216,61 @@ export default function DevOverlayDialog(props: DevOverlayDialogProps): JSX.Elem
|
|
|
216
216
|
<Dialog class="dev-overlay" isOpen>
|
|
217
217
|
<div>
|
|
218
218
|
<DialogOverlay class="dev-overlay-background"/>
|
|
219
|
-
<DialogPanel ref={setPanel} class="dev-overlay-panel">
|
|
220
|
-
<div class="dev-overlay-
|
|
221
|
-
<div class="dev-overlay-navbar
|
|
222
|
-
<div class="dev-overlay-
|
|
223
|
-
<div>
|
|
224
|
-
<
|
|
225
|
-
|
|
226
|
-
<span>{info.version as string}</span>
|
|
227
|
-
</div>
|
|
228
|
-
<Show when={props.errors.length > 1}>
|
|
229
|
-
<div class="dev-overlay-pagination">
|
|
230
|
-
<button class="dev-overlay-button" onClick={goPrev} type="button">
|
|
231
|
-
<ArrowLeftIcon title="Go Previous" />
|
|
232
|
-
</button>
|
|
233
|
-
<div class="dev-overlay-page-counter">
|
|
234
|
-
{`${truncated()} of ${props.errors.length}`}
|
|
219
|
+
<DialogPanel ref={setPanel} class="dev-overlay-panel-container">
|
|
220
|
+
<div class="dev-overlay-panel">
|
|
221
|
+
<div class="dev-overlay-navbar">
|
|
222
|
+
<div class="dev-overlay-navbar-left">
|
|
223
|
+
<div class="dev-overlay-version">
|
|
224
|
+
<div>
|
|
225
|
+
<SolidStartIcon title="Solid Start Version" />
|
|
235
226
|
</div>
|
|
236
|
-
<
|
|
237
|
-
<ArrowRightIcon title="Go Next" />
|
|
238
|
-
</button>
|
|
227
|
+
<span>{info.version as string}</span>
|
|
239
228
|
</div>
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
<button class="dev-overlay-button" onClick={toggleIsCompiled} type="button">
|
|
253
|
-
<Show when={isCompiled()} fallback={(
|
|
254
|
-
<ViewOriginalIcon title="View Original Source" />
|
|
255
|
-
)}>
|
|
256
|
-
<ViewCompiledIcon title="View Compiled Source" />
|
|
229
|
+
<Show when={props.errors.length > 1}>
|
|
230
|
+
<div class="dev-overlay-pagination">
|
|
231
|
+
<button class="dev-overlay-button" onClick={goPrev} type="button">
|
|
232
|
+
<ArrowLeftIcon title="Go Previous" />
|
|
233
|
+
</button>
|
|
234
|
+
<div class="dev-overlay-page-counter">
|
|
235
|
+
{`${truncated()} of ${props.errors.length}`}
|
|
236
|
+
</div>
|
|
237
|
+
<button class="dev-overlay-button" onClick={goNext} type="button">
|
|
238
|
+
<ArrowRightIcon title="Go Next" />
|
|
239
|
+
</button>
|
|
240
|
+
</div>
|
|
257
241
|
</Show>
|
|
258
|
-
</
|
|
259
|
-
<
|
|
260
|
-
<
|
|
261
|
-
|
|
242
|
+
</div>
|
|
243
|
+
<div class="dev-overlay-controls">
|
|
244
|
+
<button class="dev-overlay-button" onClick={redirectToGithub} type="button">
|
|
245
|
+
<GithubIcon title="Create an issue thread on Github" />
|
|
246
|
+
</button>
|
|
247
|
+
<button class="dev-overlay-button" onClick={redirectToDiscord} type="button">
|
|
248
|
+
<DiscordIcon title="Join our Discord Channel" />
|
|
249
|
+
</button>
|
|
250
|
+
<button class="dev-overlay-button" onClick={downloadScreenshot} type="button">
|
|
251
|
+
<CameraIcon title="Capture Error Overlay" />
|
|
252
|
+
</button>
|
|
253
|
+
<button class="dev-overlay-button" onClick={toggleIsCompiled} type="button">
|
|
254
|
+
<Show when={isCompiled()} fallback={(
|
|
255
|
+
<ViewOriginalIcon title="View Original Source" />
|
|
256
|
+
)}>
|
|
257
|
+
<ViewCompiledIcon title="View Compiled Source" />
|
|
258
|
+
</Show>
|
|
259
|
+
</button>
|
|
260
|
+
<button class="dev-overlay-button" onClick={props.resetError} type="button">
|
|
261
|
+
<RefreshIcon title="Reset Error" />
|
|
262
|
+
</button>
|
|
263
|
+
</div>
|
|
262
264
|
</div>
|
|
265
|
+
<Show when={props.errors[truncated() - 1]} keyed>
|
|
266
|
+
{(current) => (
|
|
267
|
+
<div class="dev-overlay-content">
|
|
268
|
+
<ErrorInfo error={current} />
|
|
269
|
+
<StackFrames error={current} isCompiled={isCompiled()} />
|
|
270
|
+
</div>
|
|
271
|
+
)}
|
|
272
|
+
</Show>
|
|
263
273
|
</div>
|
|
264
|
-
<Show when={props.errors[truncated() - 1]} keyed>
|
|
265
|
-
{(current) => (
|
|
266
|
-
<div class="dev-overlay-content">
|
|
267
|
-
<ErrorInfo error={current} />
|
|
268
|
-
<StackFrames error={current} isCompiled={isCompiled()} />
|
|
269
|
-
</div>
|
|
270
|
-
)}
|
|
271
|
-
</Show>
|
|
272
274
|
</DialogPanel>
|
|
273
275
|
</div>
|
|
274
276
|
</Dialog>
|
|
@@ -9,6 +9,13 @@ export interface StackFrameSource {
|
|
|
9
9
|
column: number;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
function getActualFileSource(path: string): string {
|
|
13
|
+
if (path.startsWith('file://')) {
|
|
14
|
+
return '/_build/@fs' + path.substring('file://'.length);
|
|
15
|
+
}
|
|
16
|
+
return path;
|
|
17
|
+
}
|
|
18
|
+
|
|
12
19
|
export function createStackFrame(
|
|
13
20
|
stackframe: StackFrame,
|
|
14
21
|
isCompiled: () => boolean,
|
|
@@ -24,7 +31,7 @@ export function createStackFrame(
|
|
|
24
31
|
if (!source.fileName) {
|
|
25
32
|
return null;
|
|
26
33
|
}
|
|
27
|
-
const response = await fetch(source.fileName);
|
|
34
|
+
const response = await fetch(getActualFileSource(source.fileName));
|
|
28
35
|
if (!response.ok) {
|
|
29
36
|
return null;
|
|
30
37
|
}
|
|
@@ -51,6 +58,7 @@ export function createStackFrame(
|
|
|
51
58
|
line: source.line,
|
|
52
59
|
column: source.column,
|
|
53
60
|
});
|
|
61
|
+
console.log('sourcemap', result);
|
|
54
62
|
|
|
55
63
|
return {
|
|
56
64
|
...result,
|
|
@@ -25,12 +25,16 @@
|
|
|
25
25
|
width: 75vw;
|
|
26
26
|
margin-top: 2rem;
|
|
27
27
|
margin-bottom: 2rem;
|
|
28
|
-
z-index: 10;
|
|
29
28
|
gap: 0.5rem;
|
|
30
29
|
color: rgb(17 24 39);
|
|
31
30
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
32
31
|
}
|
|
33
32
|
|
|
33
|
+
.dev-overlay-panel-container {
|
|
34
|
+
margin: 2rem;
|
|
35
|
+
z-index: 10;
|
|
36
|
+
}
|
|
37
|
+
|
|
34
38
|
.dev-overlay-navbar {
|
|
35
39
|
display: flex;
|
|
36
40
|
flex-direction: row;
|
package/shared/index.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { default as clientOnly } from "./clientOnly";
|
|
2
1
|
export { FileRoutes } from "./FileRoutes";
|
|
2
|
+
export { GET } from "./GET";
|
|
3
3
|
export { HttpHeader } from "./HttpHeader";
|
|
4
4
|
export { HttpStatusCode } from "./HttpStatusCode";
|
|
5
|
+
export { default as clientOnly } from "./clientOnly";
|
|
5
6
|
|