Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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/pretty-cobras-make.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solidjs/start": patch
---

Fix dev server stream responses when using the nitro v2 plugin.
90 changes: 90 additions & 0 deletions packages/start/src/server/handler.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

import type { PageEvent } from "./types.ts";

const streamMock = vi.hoisted(() => ({
stream: undefined as
| ({
then: PromiseLike<string>["then"];
pipeTo: ReturnType<typeof vi.fn>;
} & Record<string, unknown>)
| undefined,
}));

vi.mock("solid-start:middleware", () => ({
default: [],
}));

vi.mock("solid-js/web", () => ({
getRequestEvent: vi.fn(() => ({
request: new Request("http://localhost/"),
response: new Response(null, {
headers: {
"content-type": "text/html",
},
}),
})),
renderToStream: vi.fn(() => streamMock.stream),
renderToString: vi.fn(() => "<html></html>"),
}));

vi.mock("../fns/handler.ts", () => ({
handleServerFunction: vi.fn(),
}));

vi.mock("../router.tsx", () => ({
createRoutes: vi.fn(() => []),
}));

vi.mock("./fetchEvent.ts", () => ({
decorateHandler: vi.fn(handler => handler),
decorateMiddleware: vi.fn(middleware => middleware),
}));

vi.mock("./manifest/ssr-manifest.ts", () => ({
getSsrManifest: vi.fn(),
}));

vi.mock("./routes.ts", () => ({
matchAPIRoute: vi.fn(),
}));

describe("createBaseHandler", () => {
beforeEach(() => {
vi.stubEnv("START_SSR", "true");
globalThis.USING_SOLID_START_DEV_SERVER = true;
const html = Promise.resolve("<html>dev stream</html>");
streamMock.stream = {
then: html.then.bind(html),
pipeTo: vi.fn(),
};
});

afterEach(() => {
vi.unstubAllEnvs();
delete globalThis.USING_SOLID_START_DEV_SERVER;
streamMock.stream = undefined;
});

it("returns the thenable Solid stream in the dev server branch", async () => {
const { createBaseHandler } = await import("./handler.ts");
const app = createBaseHandler(
async event =>
({
...event,
assets: [],
router: {},
routes: [],
complete: false,
$islands: new Set(),
}) as PageEvent,
() => null,
);

const response = await app.request(new Request("http://localhost/"));

expect(await response.text()).toBe("<html>dev stream</html>");
expect(streamMock.stream?.then).toEqual(expect.any(Function));
expect(streamMock.stream?.pipeTo).not.toHaveBeenCalled();
});
});
4 changes: 2 additions & 2 deletions packages/start/src/server/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,12 @@ export function createBaseHandler(

if (mode === "async") return await stream;

delete (stream as any).then;

// using TransformStream in dev can cause solid-start-dev-server to crash
// when stream is cancelled
if (globalThis.USING_SOLID_START_DEV_SERVER) return stream;

delete (stream as any).then;

// returning stream directly breaks cloudflare workers
const { writable, readable } = new TransformStream();
stream.pipeTo(writable);
Expand Down
Loading