Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/chilly-rabbits-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solidjs/start": minor
---

add new dev toolbar
23 changes: 23 additions & 0 deletions apps/tests/src/routes/server-function-file.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createEffect, createSignal } from "solid-js";

async function ping(file: File) {
"use server";
return await file.text();
}

export default function App() {
const [output, setOutput] = createSignal<{ result?: boolean }>({});

createEffect(async () => {
const file = new File(['Hello, World!'], 'hello-world.txt');
const result = await ping(file);
const value = await file.text();
setOutput(prev => ({ ...prev, result: value === result }));
});

return (
<main>
<span id="server-fn-test">{JSON.stringify(output())}</span>
</main>
);
}
35 changes: 35 additions & 0 deletions apps/tests/src/routes/server-function-iterator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { createEffect, createSignal } from "solid-js";

async function ping(value: Date) {
"use server";

const current = [
value,
{
name: 'example',
*[Symbol.iterator]() {
yield 'foo';
yield 'bar';
yield 'baz';
}
}
];

return current;
}

export default function App() {
const [output, setOutput] = createSignal<{ result?: boolean }>({});

createEffect(async () => {
const value = new Date();
const result = await ping(value);
setOutput((prev) => ({ ...prev, result: value.toString() === result[0].toString() }));
});

return (
<main>
<span id="server-fn-test">{JSON.stringify(output())}</span>
</main>
);
}
28 changes: 24 additions & 4 deletions apps/tests/src/routes/server-function-ping.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,38 @@
import { createEffect, createSignal } from "solid-js";

async function ping(value: string) {
async function sleep(value: unknown, ms: number) {
return new Promise((res) => {
setTimeout(res, ms, value);
})
}

async function ping(value: Date) {
"use server";

return await Promise.resolve(value);
const current = [
value,
{
name: 'example',
async *[Symbol.asyncIterator]() {
yield sleep('foo', 5000);
yield sleep('bar', 5000);
yield sleep('baz', 5000);
}
}
];

return current;
}

export default function App() {
const [output, setOutput] = createSignal<{ result?: boolean }>({});

createEffect(async () => {
const value = `${Math.random() * 1000}`;
const value = new Date();
const result = await ping(value);
setOutput(prev => ({ ...prev, result: value === result }));
await ping(value);
console.log(result);
setOutput((prev) => ({ ...prev, result: value.toString() === result[0].toString() }));
});

return (
Comment thread
birkskyum marked this conversation as resolved.
Expand Down
38 changes: 38 additions & 0 deletions apps/tests/src/routes/server-function-plugin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { createEffect, createSignal } from "solid-js";

async function sleep(value: unknown, ms: number) {
return new Promise((res) => {
setTimeout(res, ms, value);
})
}

async function ping(value: URLSearchParams, clone: URLSearchParams) {
"use server";

const current = [
value.toString() === clone.toString(),
value,
clone,
] as const;

return current;
}

export default function App() {
const [output, setOutput] = createSignal<{ result?: boolean }>({});

createEffect(async () => {
const value = new URLSearchParams([
['foo', 'bar'],
['hello', 'world'],
]);
const result = await ping(value, value);
setOutput((prev) => ({ ...prev, result: result[0] }));
});

return (
<main>
<span id="server-fn-test">{JSON.stringify(output())}</span>
</main>
);
}
39 changes: 39 additions & 0 deletions apps/tests/src/routes/server-function-readable-stream.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { createEffect, createSignal } from "solid-js";

async function sleep<T>(value: T, ms: number) {
return new Promise<T>((res) => {
setTimeout(res, ms, value);
})
}

async function ping(value: ReadableStream<string>) {
"use server";
return value;
}

export default function App() {
const [output, setOutput] = createSignal<{ result?: boolean }>({});

createEffect(async () => {
const result = await ping(
new ReadableStream({
async start(controller) {
controller.enqueue(await sleep('foo', 100));
controller.enqueue(await sleep('bar', 100));
controller.enqueue(await sleep('baz', 100));
controller.close();
},
})
);

const reader = result.getReader();
const first = await reader.read();
setOutput((prev) => ({ ...prev, result: first.value === 'foo' }));
});

return (
<main>
<span id="server-fn-test">{JSON.stringify(output())}</span>
</main>
);
}
1 change: 1 addition & 0 deletions apps/tests/src/routes/treeshaking/(no-side-effects).tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createAsync } from "@solidjs/router";
import { createEffect } from "solid-js";

const a = "myTreeshakingTestUniqueString1";

Expand Down
2 changes: 1 addition & 1 deletion packages/start/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
"solid-js": "^1.9.11",
"source-map-js": "^1.2.1",
"srvx": "^0.12.0",
"terracotta": "^1.1.0",
"terracotta": "^1.1.1",
"vite-plugin-solid": "^2.11.11"
},
"engines": {
Expand Down
21 changes: 13 additions & 8 deletions packages/start/src/fns/client.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import { type Component } from "solid-js";
import { pushRequest, pushResponse } from "../shared/dev-toolbar/functions/tracker.ts";
import {
// serializeToJSONStream,
serializeToJSONString,
} from "./serialization.ts";
import {
BODY_FORMAT_KEY,
BodyFormat,
extractBody,
getHeadersAndBody,
} from "./shared.ts";
import { BODY_FORMAT_KEY, BodyFormat, extractBody, getHeadersAndBody } from "./shared.ts";

let INSTANCE = 0;

function createRequest(base: string, id: string, instance: string, options: RequestInit) {
return fetch(base, {
async function createRequest(base: string, id: string, instance: string, options: RequestInit) {
const request = new Request(base, {
method: "POST",
...options,
headers: {
Expand All @@ -22,6 +18,15 @@ function createRequest(base: string, id: string, instance: string, options: Requ
"X-Server-Instance": instance,
},
});
if (import.meta.env.DEV) {
console.log(pushRequest);
pushRequest(id, instance, request.clone());
}
const response = await fetch(request);
if (import.meta.env.DEV) {
pushResponse(id, instance, response.clone());
}
return response;
}

async function initializeResponse(
Expand Down
27 changes: 19 additions & 8 deletions packages/start/src/fns/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ export async function handleServerFunction(h3Event: H3Event) {
h3Event.res.headers.set("content-type", "text/javascript");
return serializeToJSStream(instance, result);
}
h3Event.res.headers.set("content-type", "text/plain");
return serializeToJSONStream(result);
} catch (x) {
if (x instanceof Response) {
Expand All @@ -134,14 +133,18 @@ export async function handleServerFunction(h3Event: H3Event) {
// forward headers
if ((x as any).headers) mergeResponseHeaders(h3Event, (x as any).headers);
// forward non-redirect statuses
if ((x as any).status && (!instance || (x as any).status < 300 || (x as any).status >= 400))
if (
(x as any).status &&
(!instance || (x as any).status < 300 || (x as any).status >= 400)
)
h3Event.res.status = (x as any).status;
if ((x as any).customBody) {
x = await (x as any).customBody();
} else if ((x as any).body == null) x = null;
h3Event.res.headers.set("X-Error", "true");
} else if (instance) {
const error = x instanceof Error ? x.message : typeof x === "string" ? x : "true";
const error =
x instanceof Error ? x.message : typeof x === "string" ? x : "true";

h3Event.res.headers.set("X-Error", toHeaderValue(error));
} else {
Expand All @@ -164,7 +167,6 @@ export async function handleServerFunction(h3Event: H3Event) {
h3Event.res.headers.set("content-type", "text/javascript");
return serializeToJSStream(instance, x);
}
h3Event.res.headers.set("content-type", "text/plain");
return serializeToJSONStream(x);
}
return x;
Expand Down Expand Up @@ -192,7 +194,10 @@ function handleNoJS(result: any, request: Request, parsed: any[], thrown?: boole
if (result.headers.has("Location")) {
headers.set(
`Location`,
new URL(result.headers.get("Location")!, url.origin + import.meta.env.BASE_URL).toString(),
new URL(
result.headers.get("Location")!,
url.origin + import.meta.env.BASE_URL,
).toString(),
);
statusCode = getExpectedRedirectStatus(result);
}
Expand All @@ -209,7 +214,10 @@ function handleNoJS(result: any, request: Request, parsed: any[], thrown?: boole
result: isError ? result.message : result,
thrown: thrown,
error: isError,
input: [...parsed.slice(0, -1), [...parsed[parsed.length - 1].entries()]],
input: [
...parsed.slice(0, -1),
[...parsed[parsed.length - 1].entries()],
],
}),
)}; Secure; HttpOnly;`,
);
Expand All @@ -235,7 +243,7 @@ export function createSingleFlightHeaders(sourceEvent: FetchEvent) {
// useH3Internals = true;
// sourceEvent.nativeEvent.node.req.headers.cookie = "";
// }
SetCookies.forEach(cookie => {
SetCookies.forEach((cookie) => {
if (!cookie) return;
const { maxAge, expires, name, value } = parseSetCookie(cookie);
if (maxAge != null && maxAge <= 0) {
Expand All @@ -256,7 +264,10 @@ export function createSingleFlightHeaders(sourceEvent: FetchEvent) {

return headers;
}
async function handleSingleFlight(sourceEvent: FetchEvent, result: any): Promise<Response> {
async function handleSingleFlight(
sourceEvent: FetchEvent,
result: any,
): Promise<Response> {
let revalidate: string[];
let url = new URL(sourceEvent.request.headers.get("referer")!).toString();
if (result instanceof Response) {
Expand Down
2 changes: 1 addition & 1 deletion packages/start/src/fns/serialization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export function serializeToJSONStream(value: any) {
});
}

class SerovalChunkReader {
export class SerovalChunkReader {
reader: ReadableStreamDefaultReader<Uint8Array>;
buffer: Uint8Array;
done: boolean;
Expand Down
6 changes: 3 additions & 3 deletions packages/start/src/shared/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// @refresh skip
import { ErrorBoundary as DefaultErrorBoundary, catchError, type ParentProps } from "solid-js";
import { catchError, ErrorBoundary as DefaultErrorBoundary, type ParentProps } from "solid-js";
import { isServer } from "solid-js/web";
import { DevToolbar } from "./dev-toolbar/index.tsx";
import { HttpStatusCode } from "./HttpStatusCode.ts";
import { DevOverlay } from "./dev-overlay/index.tsx";

export const ErrorBoundary =
import.meta.env.DEV && import.meta.env.START_DEV_OVERLAY
? (props: ParentProps) => <DevOverlay>{props.children}</DevOverlay>
? (props: ParentProps) => <DevToolbar>{props.children}</DevToolbar>
: (props: ParentProps) => {
const message = isServer
? "500 | Internal Server Error"
Expand Down
Loading
Loading