Skip to content
Merged
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
4 changes: 4 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"recommendations": ["oxc.oxc-vscode", "TypeScriptTeam.native-preview"],
"unwantedRecommendations": ["vscode.typescript-language-features"]
}
917 changes: 481 additions & 436 deletions bun.lock

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions fixtures/react-router-rsc/e2e.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as Options from "@distilled.cloud/e2e/Options";
import path from "node:path";

export default Options.make({
vite: {
main: path.resolve(import.meta.dirname, "react-router-vite/entry.worker.tsx"),
compatibilityDate: "2026-03-10",
compatibilityFlags: ["nodejs_compat"],
viteEnvironments: { entry: "rsc", children: ["ssr"] },
worker: {
name: "fixtures-react-router-rsc",
bindings: [],
assets: {
htmlHandling: "auto-trailing-slash",
notFoundHandling: "none",
},
},
},
miniflare: {
compatibilityDate: "2026-03-10",
compatibilityFlags: ["nodejs_compat"],
assets: {
routerConfig: {
has_user_worker: true,
invoke_user_worker_ahead_of_assets: false,
debug: true,
},
assetConfig: {
html_handling: "auto-trailing-slash",
not_found_handling: "none",
debug: true,
has_static_routing: false,
},
},
},
});
10 changes: 4 additions & 6 deletions fixtures/react-router-rsc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"license": "MIT",
"type": "module",
"scripts": {
"dev": "vite dev --port 3200",
"build": "vite build",
"preview": "vite preview",
"dev": "e2e dev --port 3200",
"build": "e2e build",
"preview": "e2e preview",
"test": "playwright test",
"test:update-snapshots": "playwright test --update-snapshots",
"pretest": "playwright install chromium"
Expand All @@ -18,9 +18,7 @@
},
"devDependencies": {
"@cloudflare/workers-types": "catalog:workers",
"@distilled.cloud/cloudflare-runtime": "workspace:*",
"@distilled.cloud/cloudflare-vite-plugin": "workspace:*",
"@distilled.cloud/test-utils": "workspace:*",
"@distilled.cloud/e2e": "workspace:*",
"@playwright/test": "catalog:",
"@types/node": "^24.12.0",
"@types/react": "^19.2.17",
Expand Down
106 changes: 30 additions & 76 deletions fixtures/react-router-rsc/test/smoke.test.ts
Original file line number Diff line number Diff line change
@@ -1,79 +1,33 @@
import { createMiniflare, type MiniflareInstance } from "@distilled.cloud/test-utils/miniflare";
import { miniflareModulesFromDirectory } from "@distilled.cloud/test-utils/miniflare-module";
import * as Playwright from "@distilled.cloud/e2e/Playwright";
import { expect, test } from "@playwright/test";
import path from "node:path";
import { fileURLToPath } from "node:url";

const dirname = path.dirname(fileURLToPath(import.meta.url));
const root = path.resolve(dirname, "..");
const client = path.resolve(root, "dist/client");

// The Worker runs in the `rsc` environment and loads the `ssr` environment at
// runtime via a relative `../../ssr/index.js` import, so both output
// directories ship as a single Miniflare module set under matching prefixes.
const WORKER_ENTRY = "rsc/entry.worker.js";

let miniflare: MiniflareInstance;

test.beforeAll(async () => {
const [rsc, ssr] = await Promise.all([
miniflareModulesFromDirectory(path.resolve(root, "dist/rsc"), "rsc"),
miniflareModulesFromDirectory(path.resolve(root, "dist/ssr"), "ssr"),
]);
const modules = [...rsc, ...ssr];
const entryIndex = modules.findIndex((module) => module.path === WORKER_ENTRY);
if (entryIndex === -1) {
throw new Error(`Worker entry "${WORKER_ENTRY}" not found in build output`);
}
// Miniflare treats the first module as the Worker entrypoint.
modules.unshift(modules.splice(entryIndex, 1)[0]);

miniflare = await createMiniflare({
modules,
compatibilityDate: "2026-03-10",
compatibilityFlags: ["nodejs_compat"],
assets: {
directory: client,
routerConfig: {
has_user_worker: true,
invoke_user_worker_ahead_of_assets: false,
debug: true,
},
assetConfig: {
html_handling: "auto-trailing-slash",
not_found_handling: "none",
debug: true,
has_static_routing: false,
},
},
});
});

test.afterAll(async () => {
await miniflare?.[Symbol.asyncDispose]();
});

test("renders the homepage and hydrates client routes", async ({ page }) => {
const response = await page.goto(miniflare.url.toString());
expect(response?.status()).toBe(200);
await page.waitForLoadState("networkidle");
await page.evaluate(() => document.fonts.ready);

await expect(page).toHaveScreenshot("index.png", {
animations: "disabled",
maxDiffPixelRatio: 0.03,
});

await page.click("a[href='/about']");
await page.waitForURL("**/about");
await page.evaluate(() => document.fonts.ready);

await expect(page).toHaveScreenshot("about.png", {
animations: "disabled",
maxDiffPixelRatio: 0.03,
for (const method of Playwright.SERVER_METHODS) {
test.describe(method, () => {
const it = Playwright.make(method);

it("renders the homepage and hydrates client routes", async ({ page, server }) => {
const response = await page.goto(server.url.toString());
expect(response?.status()).toBe(200);
await page.waitForLoadState("networkidle");
await page.evaluate(() => document.fonts.ready);

await expect(page).toHaveScreenshot("index.png", {
animations: "disabled",
maxDiffPixelRatio: 0.03,
});

await page.click("a[href='/about']");
await page.waitForURL("**/about");
await page.evaluate(() => document.fonts.ready);

await expect(page).toHaveScreenshot("about.png", {
animations: "disabled",
maxDiffPixelRatio: 0.03,
});

expect(await page.textContent("button.counter")).toBe("Count is 0");
await page.click("button.counter");
expect(await page.textContent("button.counter")).toBe("Count is 1");
});
});

expect(await page.textContent("button.counter")).toBe("Count is 0");
await page.click("button.counter");
expect(await page.textContent("button.counter")).toBe("Count is 1");
});
}
18 changes: 5 additions & 13 deletions fixtures/react-router-rsc/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import cloudflare from "@distilled.cloud/cloudflare-vite-plugin";
import react from "@vitejs/plugin-react";
import rsc from "@vitejs/plugin-rsc";
import { defineConfig } from "vite";

// Minimal React Router app (hand-rolled on @vitejs/plugin-rsc) wired to the
// distilled Cloudflare vite plugin. The Worker IS the `rsc` environment; its
// fetch handler loads the `ssr` environment at runtime via
// `import.meta.viteRsc.loadModule("ssr", ...)`. The new `viteEnvironments`
// option declares this entry/child topology to the plugin.
// Minimal React Router app (hand-rolled on @vitejs/plugin-rsc). The Worker IS
// the `rsc` environment; its fetch handler loads the `ssr` environment at
// runtime via `import.meta.viteRsc.loadModule("ssr", ...)`. The Cloudflare
// plugin configuration, including the `viteEnvironments` option that declares
// this entry/child topology, lives in `e2e.config.ts`.
export default defineConfig({
plugins: [
react(),
Expand All @@ -19,13 +18,6 @@ export default defineConfig({
rsc: "./react-router-vite/entry.worker.tsx",
},
}),
cloudflare({
main: "./react-router-vite/entry.worker.tsx",
compatibilityDate: "2026-03-10",
compatibilityFlags: ["nodejs_compat"],
viteEnvironments: { entry: "rsc", children: ["ssr"] },
worker: { name: "fixtures-react-router-rsc", bindings: [] },
}),
],
optimizeDeps: {
include: ["react-router", "react-router/internal/react-server-client"],
Expand Down
38 changes: 38 additions & 0 deletions fixtures/solid-ssr/e2e.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as Options from "@distilled.cloud/e2e/Options";

export default Options.make({
vite: {
compatibilityDate: "2026-03-10",
compatibilityFlags: ["nodejs_als"],
worker: {
name: "fixtures-solid-ssr",
bindings: [],
assets: {
htmlHandling: "auto-trailing-slash",
notFoundHandling: "single-page-application",
},
},
},
miniflare: {
modules: [
{
type: "ESModule",
path: "index.js",
contents: `export default { fetch: (request) => new Response("Not Found", { status: 404 }) }`,
},
],
assets: {
routerConfig: {
has_user_worker: false,
invoke_user_worker_ahead_of_assets: false,
debug: true,
},
assetConfig: {
html_handling: "auto-trailing-slash",
not_found_handling: "single-page-application",
debug: true,
has_static_routing: false,
},
},
},
});
13 changes: 8 additions & 5 deletions fixtures/solid-ssr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@
"license": "MIT",
"type": "module",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
"dev": "e2e dev",
"build": "e2e build",
"preview": "e2e preview",
"test": "playwright test",
"test:update-snapshots": "playwright test --update-snapshots",
"pretest": "playwright install chromium"
},
"dependencies": {
"@solidjs/router": "^0.15.1",
"solid-js": "^1.9.5"
},
"devDependencies": {
"@distilled.cloud/cloudflare-vite-plugin": "workspace:*",
"@distilled.cloud/e2e": "workspace:*",
"@playwright/test": "catalog:",
"@tailwindcss/postcss": "^4.1.13",
"postcss": "^8.4.49",
"solid-devtools": "^0.34.3",
Expand Down
21 changes: 21 additions & 0 deletions fixtures/solid-ssr/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { defineConfig } from "@playwright/test";

export default defineConfig({
testDir: "./test",
timeout: 60_000,
expect: {
timeout: 10_000,
},
snapshotPathTemplate: "{testDir}/__snapshots__/{testFileName}/{arg}{ext}",
projects: [
{
name: "chromium",
use: {
browserName: "chromium",
colorScheme: "light",
deviceScaleFactor: 1,
viewport: { width: 1280, height: 720 },
},
},
],
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 33 additions & 0 deletions fixtures/solid-ssr/test/smoke.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as Playwright from "@distilled.cloud/e2e/Playwright";
import { expect, test } from "@playwright/test";

for (const method of Playwright.SERVER_METHODS) {
test.describe(method, () => {
const it = Playwright.make(method);

it("renders the homepage", async ({ page, server }) => {
const response = await page.goto(server.url.toString());
expect(response?.status()).toBe(200);
await page.waitForLoadState("networkidle");
await page.evaluate(() => document.fonts.ready);

await expect(page).toHaveScreenshot("index.png", {
animations: "disabled",
maxDiffPixelRatio: 0.03,
});

expect(await page.textContent("output")).toBe("Count: 0");
await page.click("button:has-text('+')");
expect(await page.textContent("output")).toBe("Count: 1");

await page.click("a[href='/about']");
await page.waitForURL("**/about");
await page.evaluate(() => document.fonts.ready);

await expect(page).toHaveScreenshot("about.png", {
animations: "disabled",
maxDiffPixelRatio: 0.03,
});
});
});
}
8 changes: 1 addition & 7 deletions fixtures/solid-ssr/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import cloudflare from "@distilled.cloud/cloudflare-vite-plugin";
import devtools from "solid-devtools/vite";
import type { PluginOption } from "vite";
import { defineConfig } from "vite";
import solidPlugin from "vite-plugin-solid";

export default defineConfig({
plugins: [
devtools(),
solidPlugin(),
cloudflare({ compatibilityFlags: ["nodejs_als"] }) as PluginOption,
],
plugins: [devtools(), solidPlugin()],
server: {
port: 3000,
},
Expand Down
34 changes: 34 additions & 0 deletions fixtures/solidstart/e2e.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as Options from "@distilled.cloud/e2e/Options";

export default Options.make({
vite: {
compatibilityDate: "2026-03-10",
compatibilityFlags: ["nodejs_compat"],
exports: ["default"],
worker: {
name: "fixtures-solidstart",
bindings: [],
assets: {
htmlHandling: "auto-trailing-slash",
notFoundHandling: "none",
},
},
},
miniflare: {
compatibilityDate: "2026-03-10",
compatibilityFlags: ["nodejs_compat"],
assets: {
routerConfig: {
has_user_worker: true,
invoke_user_worker_ahead_of_assets: false,
debug: true,
},
assetConfig: {
html_handling: "auto-trailing-slash",
not_found_handling: "none",
debug: true,
has_static_routing: false,
},
},
},
});
Loading