Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: workerd environment prototype #14

Merged
merged 47 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
eb6f71c
chore: init
hi-ogawa Apr 8, 2024
007baa6
Merge branch 'main' into chore-workerd
hi-ogawa Apr 8, 2024
3ddd96d
chore: lockfile
hi-ogawa Apr 8, 2024
be62ebe
chore: setup script
hi-ogawa Apr 8, 2024
28bf1ce
wip
hi-ogawa Apr 8, 2024
3183a9f
chore: durable objects websocket example
hi-ogawa Apr 8, 2024
e099974
chore: setup tsup
hi-ogawa Apr 8, 2024
2e503f5
chore: statefull example
hi-ogawa Apr 8, 2024
82da05c
feat: vite ModuleRunner in durable objects
hi-ogawa Apr 8, 2024
ad824de
chore: cleanup
hi-ogawa Apr 8, 2024
d1357f7
feat: prototype vitePluginWorkerd
hi-ogawa Apr 8, 2024
41bc4aa
wip: plugin
hi-ogawa Apr 8, 2024
6430137
wip
hi-ogawa Apr 8, 2024
959e1f3
refactor: simplify runner options
hi-ogawa Apr 8, 2024
6ab9ee6
fix: setup __viteFetchModule service binding
hi-ogawa Apr 8, 2024
c50affd
fix: add vitePluginVirtualIndexHtml
hi-ogawa Apr 8, 2024
f5437a2
ci: fix build
hi-ogawa Apr 8, 2024
eed68d8
fix: fix vitePluginVirtualIndexHtml on build
hi-ogawa Apr 8, 2024
e705d0b
chore: readme
hi-ogawa Apr 8, 2024
79c9da7
fix: fix vitePluginVirtualIndexHtml extension
hi-ogawa Apr 8, 2024
9ced3ee
test: test-e2e-workerd
hi-ogawa Apr 8, 2024
8381eff
chore: remove old
hi-ogawa Apr 8, 2024
db4993a
chore: comment
hi-ogawa Apr 8, 2024
0aa2703
wip: hmr
hi-ogawa Apr 8, 2024
0d843ff
wip: implement hot
hi-ogawa Apr 8, 2024
f6fc3a7
chore: vite v6.0.0-alpha.1
hi-ogawa Apr 8, 2024
07fae6c
refactor: async createEnvironment
hi-ogawa Apr 8, 2024
a78fd3c
refactor: createWorkerdDevEnvironment
hi-ogawa Apr 9, 2024
20dfa8a
refactor: minor
hi-ogawa Apr 9, 2024
371285a
refactor: move code
hi-ogawa Apr 9, 2024
99f545c
feat: vitest-pool-workers like options
hi-ogawa Apr 9, 2024
860a227
refactor: move off entry selection
hi-ogawa Apr 9, 2024
66843cf
feat: catch error
hi-ogawa Apr 9, 2024
2a4ffb7
refactor: get/setRunnerFetchOptions
hi-ogawa Apr 9, 2024
409a694
feat: export createWorkerdDevEnvironment
hi-ogawa Apr 9, 2024
1dd4865
feat: createSimpleHMRChannel
hi-ogawa Apr 9, 2024
4e5b09f
Merge branch 'main' into feat-vite-workerd
hi-ogawa Apr 9, 2024
cd7aafc
wip: kv demo
hi-ogawa Apr 9, 2024
4ef7e23
chore: setup example
hi-ogawa Apr 9, 2024
8743860
chore: kv demo
hi-ogawa Apr 9, 2024
391cc68
ci: add e2e
hi-ogawa Apr 9, 2024
5096571
chore: use wrangler.toml
hi-ogawa Apr 9, 2024
6bce43a
chore: readme
hi-ogawa Apr 9, 2024
ced97d9
chore: readme
hi-ogawa Apr 9, 2024
dba45bc
refactor: minor
hi-ogawa Apr 9, 2024
4d8c8f3
chore: readme
hi-ogawa Apr 9, 2024
f836916
Merge branch 'main' into feat-vite-workerd
hi-ogawa Apr 9, 2024
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
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ jobs:
- run: corepack enable
- run: pnpm i
- run: pnpm lint-check
- run: pnpm -C examples/workerd build
- run: pnpm tsc
- run: npx playwright install chromium
- run: pnpm -C examples/react-ssr test-e2e
- run: pnpm -C examples/react-ssr build
- run: pnpm -C examples/react-ssr test-e2e-preview
- run: pnpm -C examples/react-ssr test-e2e-workerd
- run: pnpm -C examples/react-ssr-workerd test-e2e
- run: pnpm -C examples/react-server test-e2e
- run: pnpm -C examples/react-server build
- run: pnpm -C examples/react-server test-e2e-preview
5 changes: 5 additions & 0 deletions examples/react-ssr-workerd/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# react-ssr-workerd

```sh
pnpm dev
```
9 changes: 9 additions & 0 deletions examples/react-ssr-workerd/e2e/basic.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { test, expect } from "@playwright/test";

test("basic", async ({ page }) => {
await page.goto("/");
await expect(page.locator("#root")).toContainText("hydrated: true");
await expect(page.locator("#root")).toContainText("Count: 0");
await page.getByRole("button", { name: "+" }).click();
await expect(page.locator("#root")).toContainText("Count: 1");
});
14 changes: 14 additions & 0 deletions examples/react-ssr-workerd/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>react-ssr-workerd</title>
<meta
name="viewport"
content="width=device-width, height=device-height, initial-scale=1.0"
/>
</head>
<body>
<script src="/src/entry-client" type="module"></script>
</body>
</html>
22 changes: 22 additions & 0 deletions examples/react-ssr-workerd/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@hiogawa/vite-environment-examples-react-ssr-workerd",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"test-e2e": "playwright test"
},
"dependencies": {
"react": "18.3.0-canary-6c3b8dbfe-20240226",
"react-dom": "18.3.0-canary-6c3b8dbfe-20240226"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20240405.0",
"@hiogawa/vite-plugin-workerd": "workspace:*",
"@types/react": "18.2.72",
"@types/react-dom": "18.2.22"
},
"volta": {
"extends": "../../package.json"
}
}
28 changes: 28 additions & 0 deletions examples/react-ssr-workerd/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { defineConfig, devices } from "@playwright/test";

const port = Number(process.env["E2E_PORT"] || 6174);
const command = process.env["E2E_PREVIEW"]
? `pnpm preview --port ${port} --strict-port`
: process.env["E2E_WORKERD"]
? `pnpm dev-workerd --port ${port} --strict-port`
: `pnpm dev --port ${port} --strict-port`;

export default defineConfig({
testDir: "e2e",
use: {
trace: "on-first-retry",
},
projects: [
{
name: "chromium",
use: devices["Desktop Chrome"],
},
],
webServer: {
command,
port,
},
forbidOnly: !!process.env["CI"],
retries: process.env["CI"] ? 2 : 0,
reporter: "list",
});
4 changes: 4 additions & 0 deletions examples/react-ssr-workerd/src/adapters/node.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { createMiddleware } from "@hattip/adapter-node/native-fetch";
import { handler } from "../entry-server";

export default createMiddleware((ctx) => handler(ctx.request));
8 changes: 8 additions & 0 deletions examples/react-ssr-workerd/src/adapters/workerd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { handler } from "../entry-server";

export default {
fetch(request: Request, env: unknown) {
Object.assign(globalThis, { env });
return handler(request);
},
};
14 changes: 14 additions & 0 deletions examples/react-ssr-workerd/src/entry-client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { tinyassert } from "@hiogawa/utils";
import ReactDomClient from "react-dom/client";
import Page from "./routes/page";
import React from "react";

async function main() {
const el = document.getElementById("root");
tinyassert(el);
React.startTransition(() => {
ReactDomClient.hydrateRoot(el, <Page />);
});
}

main();
28 changes: 28 additions & 0 deletions examples/react-ssr-workerd/src/entry-server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import ReactDomServer from "react-dom/server.edge";
import Page from "./routes/page";

export async function handler(request: Request) {
const url = new URL(request.url);
if (url.pathname === "/api") {
return apiHandler(request);
}
if (url.pathname === "/nodejs-compat") {
const util = await import("node:util");
return new Response(util.format("hello %s", "world"));
}

const ssrHtml = ReactDomServer.renderToString(<Page />);
let html = (await import("virtual:index-html")).default;
html = html.replace(/<body>/, `<body><div id="root">${ssrHtml}</div>`);
return new Response(html, { headers: { "content-type": "text/html" } });
}

async function apiHandler(request: Request) {
let count = Number(await env.kv.get("count"));
if (request.method === "POST") {
const { delta } = await request.json();
count += delta;
await env.kv.put("count", String(count));
}
return new Response(JSON.stringify({ count }));
}
35 changes: 35 additions & 0 deletions examples/react-ssr-workerd/src/routes/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from "react";

export default function Page() {
const [count, setCount] = React.useState<number>();

const [hydrated, setHydrated] = React.useState(false);
React.useEffect(() => {
setHydrated(true);
getCount().then(setCount);
}, []);

return (
<div>
<div>hydrated: {String(hydrated)}</div>
<div>Count: {count ?? "..."}</div>
<button onClick={async () => changeCount(-1).then(setCount)}>-1</button>
<button onClick={async () => changeCount(+1).then(setCount)}>+1</button>
</div>
);
}

async function getCount() {
const res = await fetch("/api");
const { count } = await res.json();
return count as number;
}

async function changeCount(delta: number) {
const res = await fetch("/api", {
method: "POST",
body: JSON.stringify({ delta }),
});
const { count } = await res.json();
return count as number;
}
3 changes: 3 additions & 0 deletions examples/react-ssr-workerd/src/types/react.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare module "react-dom/server.edge" {
export * from "react-dom/server";
}
4 changes: 4 additions & 0 deletions examples/react-ssr-workerd/src/types/virtual.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module "virtual:index-html" {
const src: string;
export default src;
}
3 changes: 3 additions & 0 deletions examples/react-ssr-workerd/src/types/workerd.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare const env: {
kv: import("@cloudflare/workers-types").KVNamespace;
};
15 changes: 15 additions & 0 deletions examples/react-ssr-workerd/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"extends": "@tsconfig/strictest/tsconfig.json",
"include": ["src", "vite.config.ts", "e2e", "playwright.config.ts"],
"compilerOptions": {
"exactOptionalPropertyTypes": false,
"verbatimModuleSyntax": true,
"noEmit": true,
"moduleResolution": "Bundler",
"module": "ESNext",
"target": "ESNext",
"lib": ["ESNext", "DOM"],
"types": ["vite/client"],
"jsx": "react-jsx"
}
}
47 changes: 47 additions & 0 deletions examples/react-ssr-workerd/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { vitePluginWorkerd } from "@hiogawa/vite-plugin-workerd";
import { vitePluginVirtualIndexHtml } from "../react-ssr/vite.config";
import { Log } from "miniflare";

export default defineConfig((_env) => ({
clearScreen: false,
appType: "custom",
plugins: [
react(),
vitePluginWorkerd({
entry: "/src/adapters/workerd.ts",
miniflare: {
log: new Log(),
},
wrangler: {
configPath: "./wrangler.toml",
},
}),
vitePluginVirtualIndexHtml(),
],
environments: {
workerd: {
// [feedback] how to prevent deps optimization to inject this? still `ssr.target: "webworker"` needed?
// import { createRequire } from 'module';const require = createRequire(import.meta.url);
nodeCompatible: false,
webCompatible: true,
resolve: {
noExternal: true,
},
dev: {
optimizeDeps: {
include: [
"react",
"react/jsx-runtime",
"react/jsx-dev-runtime",
"react-dom/server.edge",
],
},
},
},
},
ssr: {
target: "webworker",
},
}));
5 changes: 5 additions & 0 deletions examples/react-ssr-workerd/wrangler.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
compatibility_date = "2024-01-01"
compatibility_flags = ["nodejs_compat"]
kv_namespaces = [
{ binding = "kv", id = "test-namespace" }
]
3 changes: 3 additions & 0 deletions examples/react-ssr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
"type": "module",
"scripts": {
"dev": "vite",
"dev-workerd": "vite --config vite.config.workerd.ts",
"build": "vite build --all",
"preview": "vite preview",
"test-e2e": "playwright test",
"test-e2e-preview": "E2E_PREVIEW=1 playwright test",
"test-e2e-workerd": "E2E_WORKERD=1 playwright test",
"vc-build": "SERVER_ENTRY=/src/adapters/vercel-edge.ts pnpm build && bash misc/vercel-edge/build.sh",
"vc-release": "vercel deploy --prebuilt misc/vercel-edge --prod"
},
Expand All @@ -16,6 +18,7 @@
"react-dom": "18.3.0-canary-6c3b8dbfe-20240226"
},
"devDependencies": {
"@hiogawa/vite-plugin-workerd": "workspace:*",
"@types/react": "18.2.72",
"@types/react-dom": "18.2.22"
},
Expand Down
8 changes: 4 additions & 4 deletions examples/react-ssr/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { defineConfig, devices } from "@playwright/test";

const port = Number(process.env["E2E_PORT"] || 6174);
const isPreview = Boolean(process.env["E2E_PREVIEW"]);
const command = isPreview
const command = process.env["E2E_PREVIEW"]
? `pnpm preview --port ${port} --strict-port`
: `pnpm dev --port ${port} --strict-port`;
: process.env["E2E_WORKERD"]
? `pnpm dev-workerd --port ${port} --strict-port`
: `pnpm dev --port ${port} --strict-port`;

export default defineConfig({
testDir: "e2e",
Expand All @@ -21,7 +22,6 @@ export default defineConfig({
command,
port,
},
grepInvert: isPreview ? /@dev/ : /@build/,
forbidOnly: !!process.env["CI"],
retries: process.env["CI"] ? 2 : 0,
reporter: "list",
Expand Down
5 changes: 5 additions & 0 deletions examples/react-ssr/src/adapters/workerd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { handler } from "../entry-server";

export default {
fetch: handler,
};
8 changes: 7 additions & 1 deletion examples/react-ssr/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{
"extends": "@tsconfig/strictest/tsconfig.json",
"include": ["src", "vite.config.ts", "e2e", "playwright.config.ts"],
"include": [
"src",
"vite.config.ts",
"vite.config.workerd.ts",
"e2e",
"playwright.config.ts"
],
"compilerOptions": {
"exactOptionalPropertyTypes": false,
"verbatimModuleSyntax": true,
Expand Down
44 changes: 44 additions & 0 deletions examples/react-ssr/vite.config.workerd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { vitePluginWorkerd } from "@hiogawa/vite-plugin-workerd";
import { vitePluginVirtualIndexHtml } from "./vite.config";
import { Log } from "miniflare";

export default defineConfig((_env) => ({
clearScreen: false,
appType: "custom",
plugins: [
react(),
vitePluginWorkerd({
entry: "/src/adapters/workerd.ts",
miniflare: {
log: new Log(),
},
}),
vitePluginVirtualIndexHtml(),
],
environments: {
workerd: {
// [feedback] how to prevent deps optimization to inject this? still `ssr.target: "webworker"` needed?
// import { createRequire } from 'module';const require = createRequire(import.meta.url);
nodeCompatible: false,
webCompatible: true,
resolve: {
noExternal: true,
},
dev: {
optimizeDeps: {
include: [
"react",
"react/jsx-runtime",
"react/jsx-dev-runtime",
"react-dom/server.edge",
],
},
},
},
},
ssr: {
target: "webworker",
},
}));
12 changes: 12 additions & 0 deletions examples/workerd/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# workerd

Vite module runner on Durable Objects.

See [`examples/react-ssr-workerd`](../react-ssr-workerd).

## references

- https://github.com/cloudflare/workers-sdk/blame/2789f26a87c769fc6177b0bdc79a839a15f4ced1/packages/miniflare/test/plugins/do/index.spec.ts
- https://github.com/cloudflare/workers-sdk/blob/d994066f255f6851759a055eac3b52a4aa4b83c3/packages/vitest-pool-workers/src/worker/index.ts#L174
- https://github.com/cloudflare/workers-sdk/blob/2789f26a87c769fc6177b0bdc79a839a15f4ced1/packages/vitest-pool-workers/src/pool/index.ts#L630
- https://github.com/cloudflare/workers-sdk/pull/5530
Loading