create-blokd 0.1.0-beta.2

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/README.md ADDED
@@ -0,0 +1,454 @@
1
+ # create-blokd
2
+
3
+ Create a new Blokd project from the command line.
4
+
5
+ Blokd is a tiny Hono-native meta-framework for HTML-first applications, with Solid-familiar signals, Web APIs, SSR, file-based routing, and resumable islands.
6
+
7
+ ## Usage
8
+
9
+ Create a new project with pnpm:
10
+
11
+ ~~~sh
12
+ pnpm create blokd my-app
13
+ ~~~
14
+
15
+ Or use the explicit beta tag:
16
+
17
+ ~~~sh
18
+ pnpm create blokd@beta my-app
19
+ ~~~
20
+
21
+ With npm:
22
+
23
+ ~~~sh
24
+ npm create blokd@beta my-app
25
+ ~~~
26
+
27
+ With yarn:
28
+
29
+ ~~~sh
30
+ yarn create blokd my-app
31
+ ~~~
32
+
33
+ With bun:
34
+
35
+ ~~~sh
36
+ bun create blokd my-app
37
+ ~~~
38
+
39
+ Then start the app:
40
+
41
+ ~~~sh
42
+ cd my-app
43
+ pnpm install
44
+ pnpm dev
45
+ ~~~
46
+
47
+ Open the local URL printed by Vite.
48
+
49
+ ## Options
50
+
51
+ ~~~txt
52
+ Usage:
53
+ npm create blokd@beta my-app
54
+ pnpm create blokd my-app
55
+ yarn create blokd my-app
56
+ bun create blokd my-app
57
+
58
+ Options:
59
+ --template <name> Template to use. Default: minimal
60
+ --install Install dependencies after creating the project
61
+ --no-install Do not install dependencies
62
+ --pm <name> Package manager: pnpm, npm, yarn, bun
63
+ -h, --help Show help
64
+ ~~~
65
+
66
+ ## Examples
67
+
68
+ Create a minimal project:
69
+
70
+ ~~~sh
71
+ pnpm create blokd my-app
72
+ ~~~
73
+
74
+ Create a minimal project and install dependencies:
75
+
76
+ ~~~sh
77
+ pnpm create blokd my-app --install
78
+ ~~~
79
+
80
+ Create a project with an explicit template:
81
+
82
+ ~~~sh
83
+ pnpm create blokd my-app --template minimal
84
+ ~~~
85
+
86
+ Create a project and force npm as the package manager:
87
+
88
+ ~~~sh
89
+ pnpm create blokd my-app --pm npm
90
+ ~~~
91
+
92
+ Create a project without installing dependencies:
93
+
94
+ ~~~sh
95
+ pnpm create blokd my-app --no-install
96
+ ~~~
97
+
98
+ ## Templates
99
+
100
+ ### minimal
101
+
102
+ The default template is `minimal`.
103
+
104
+ It includes:
105
+
106
+ - Hono server entry
107
+ - Blokd Vite plugin
108
+ - file-based routes
109
+ - root layout
110
+ - custom 404 page
111
+ - custom error page
112
+ - client entry for resumable islands
113
+ - one interactive signal example
114
+ - one resumable island example
115
+ - one static route
116
+
117
+ Project structure:
118
+
119
+ ~~~txt
120
+ my-app/
121
+ package.json
122
+ tsconfig.json
123
+ vite.config.ts
124
+ index.html
125
+ src/
126
+ server.ts
127
+ entry-client.ts
128
+ resumables/
129
+ demo.ts
130
+ routes/
131
+ _layout.tsx
132
+ _404.tsx
133
+ _error.tsx
134
+ index.tsx
135
+ about.tsx
136
+ ~~~
137
+
138
+ ## Generated project commands
139
+
140
+ Inside the generated project:
141
+
142
+ ~~~sh
143
+ pnpm dev
144
+ ~~~
145
+
146
+ Starts the development server.
147
+
148
+ ~~~sh
149
+ pnpm build
150
+ ~~~
151
+
152
+ Builds the project.
153
+
154
+ ~~~sh
155
+ pnpm typecheck
156
+ ~~~
157
+
158
+ Runs TypeScript without emitting files.
159
+
160
+ ## Generated project dependencies
161
+
162
+ The generated minimal starter includes:
163
+
164
+ ~~~json
165
+ {
166
+ "dependencies": {
167
+ "blokd": "beta",
168
+ "hono": ">=4.5 <5"
169
+ },
170
+ "devDependencies": {
171
+ "@types/node": ">=20 <23",
172
+ "typescript": ">=5.5 <6",
173
+ "vite": ">=5 <9"
174
+ }
175
+ }
176
+ ~~~
177
+
178
+ `blokd` is installed from the beta dist-tag because Blokd is currently in public beta.
179
+
180
+ `hono` is included as an application dependency because Blokd apps use Hono directly for APIs, middleware, routing, cookies, headers, and deployment-specific server behavior.
181
+
182
+ `vite`, `typescript`, and `@types/node` are development dependencies because the starter uses Vite and TypeScript.
183
+
184
+ ## Beta status
185
+
186
+ Blokd is currently in public beta.
187
+
188
+ The beta is intended for:
189
+
190
+ - experimentation
191
+ - early adopters
192
+ - small websites
193
+ - documentation sites
194
+ - local business websites
195
+ - simple dashboards
196
+ - Hono-backed SSR applications
197
+ - form-driven applications
198
+ - progressively enhanced web apps
199
+
200
+ The beta is not yet intended for:
201
+
202
+ - large production migrations
203
+ - highly regulated applications
204
+ - applications requiring long-term API stability
205
+ - complex full-app client routing
206
+ - deep ecosystem integrations
207
+
208
+ APIs may change before a stable `1.0.0` release.
209
+
210
+ ## What Blokd is optimized for
211
+
212
+ Blokd is optimized for HTML-first applications.
213
+
214
+ That means:
215
+
216
+ - server-rendered pages by default
217
+ - Web APIs instead of framework-specific request abstractions
218
+ - Hono for server composition
219
+ - file-based routing for pages
220
+ - native forms for mutations
221
+ - small client JavaScript payloads
222
+ - resumable islands for focused interactivity
223
+ - no React dependency
224
+ - no virtual DOM dependency
225
+
226
+ ## What Blokd is not
227
+
228
+ Blokd is not a full replacement for every app framework.
229
+
230
+ It is not:
231
+
232
+ - a React framework
233
+ - a full Qwik-compatible resumability system
234
+ - a full client-side app router
235
+ - a batteries-included CMS framework
236
+ - a mature ecosystem equivalent to Next.js, Astro, Remix, or SvelteKit
237
+
238
+ The goal is a small, explicit, Web Platform-oriented framework.
239
+
240
+ ## Minimal starter walkthrough
241
+
242
+ The generated app has two public pages:
243
+
244
+ ~~~txt
245
+ src/routes/index.tsx -> /
246
+ src/routes/about.tsx -> /about
247
+ ~~~
248
+
249
+ It also has three special route files:
250
+
251
+ ~~~txt
252
+ src/routes/_layout.tsx -> root document layout
253
+ src/routes/_404.tsx -> custom not found page
254
+ src/routes/_error.tsx -> custom error page
255
+ ~~~
256
+
257
+ The root page demonstrates:
258
+
259
+ - `signal`
260
+ - an inline event handler
261
+ - `Island`
262
+ - `resumable`
263
+
264
+ The about page demonstrates a static server-rendered page with no client interactivity.
265
+
266
+ ## Hono server entry
267
+
268
+ The generated app uses Hono as the server foundation:
269
+
270
+ ~~~ts
271
+ import { Hono } from "hono";
272
+ import { createPages } from "blokd/hono";
273
+ import routes from "virtual:blokd/routes";
274
+
275
+ const app = new Hono();
276
+
277
+ app.get("/api/health", c => {
278
+ return c.json({ ok: true });
279
+ });
280
+
281
+ app.route(
282
+ "/",
283
+ createPages({
284
+ routes,
285
+ entryClient: "/src/entry-client.ts"
286
+ })
287
+ );
288
+
289
+ export default app;
290
+ ~~~
291
+
292
+ Use Hono directly for:
293
+
294
+ - API routes
295
+ - middleware
296
+ - authentication
297
+ - sessions
298
+ - cookies
299
+ - headers
300
+ - webhooks
301
+ - deployment adapters
302
+
303
+ ## Vite config
304
+
305
+ The generated app uses the Blokd Vite plugin:
306
+
307
+ ~~~ts
308
+ import { defineConfig } from "vite";
309
+ import { blokd } from "blokd/vite";
310
+
311
+ export default defineConfig({
312
+ plugins: [
313
+ blokd({
314
+ routesDir: "src/routes",
315
+ clientEntry: "/src/entry-client.ts"
316
+ })
317
+ ]
318
+ });
319
+ ~~~
320
+
321
+ The Vite plugin is responsible for:
322
+
323
+ - route manifest generation
324
+ - JSX transform
325
+ - static route analysis
326
+ - virtual route module support
327
+
328
+ ## Resumable islands
329
+
330
+ The starter includes a minimal resumable island:
331
+
332
+ ~~~tsx
333
+ <Island name="demo-island" state={{ message: "Hello from Blokd" }}>
334
+ <button
335
+ type="button"
336
+ data-output
337
+ onClick={resumable("/src/resumables/demo.ts#sayHello")}
338
+ >
339
+ Run resumable handler
340
+ </button>
341
+ </Island>
342
+ ~~~
343
+
344
+ The corresponding handler is:
345
+
346
+ ~~~ts
347
+ export function sayHello(event: Event, ctx: any) {
348
+ const button = event.currentTarget as HTMLButtonElement;
349
+ button.textContent = ctx.state.message;
350
+ }
351
+ ~~~
352
+
353
+ Blokd resumability is island-scoped. It is not full application graph serialization.
354
+
355
+ ## Static route behavior
356
+
357
+ Blokd can analyze routes to determine whether they need the client entry.
358
+
359
+ A route with event handlers, signals, effects, `Island`, or `resumable` needs client behavior.
360
+
361
+ A route without client markers can be server-rendered without framework client JavaScript.
362
+
363
+ This keeps simple pages small by default.
364
+
365
+ ## Package manager behavior
366
+
367
+ `create-blokd` detects the package manager from the current npm user agent when possible.
368
+
369
+ Fallback package manager:
370
+
371
+ ~~~txt
372
+ pnpm
373
+ ~~~
374
+
375
+ You can override this with:
376
+
377
+ ~~~sh
378
+ pnpm create blokd my-app --pm npm
379
+ pnpm create blokd my-app --pm pnpm
380
+ pnpm create blokd my-app --pm yarn
381
+ pnpm create blokd my-app --pm bun
382
+ ~~~
383
+
384
+ ## Installing automatically
385
+
386
+ By default, the CLI creates the project and prints next steps.
387
+
388
+ To install dependencies immediately:
389
+
390
+ ~~~sh
391
+ pnpm create blokd my-app --install
392
+ ~~~
393
+
394
+ To explicitly skip installation:
395
+
396
+ ~~~sh
397
+ pnpm create blokd my-app --no-install
398
+ ~~~
399
+
400
+ ## Directory safety
401
+
402
+ `create-blokd` refuses to write into a non-empty target directory.
403
+
404
+ This prevents accidentally overwriting an existing project.
405
+
406
+ Valid project names may contain:
407
+
408
+ - letters
409
+ - numbers
410
+ - dots
411
+ - dashes
412
+ - underscores
413
+
414
+ ## Publishing
415
+
416
+ This package is published as:
417
+
418
+ ~~~txt
419
+ create-blokd
420
+ ~~~
421
+
422
+ The command:
423
+
424
+ ~~~sh
425
+ npm create blokd
426
+ ~~~
427
+
428
+ resolves to the `create-blokd` package.
429
+
430
+ For beta releases, publish with:
431
+
432
+ ~~~sh
433
+ npm publish --tag beta
434
+ ~~~
435
+
436
+ Do not publish beta releases without the beta dist-tag.
437
+
438
+ ## Related packages
439
+
440
+ Main framework package:
441
+
442
+ ~~~sh
443
+ pnpm add blokd@beta hono
444
+ ~~~
445
+
446
+ Create package:
447
+
448
+ ~~~sh
449
+ pnpm create blokd@beta my-app
450
+ ~~~
451
+
452
+ ## License
453
+
454
+ MIT
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { spawnSync } from "node:child_process";
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+
11
+ const packageRoot = resolve(__dirname, "..");
12
+ const templatesRoot = join(packageRoot, "templates");
13
+
14
+ const args = process.argv.slice(2);
15
+
16
+ const help = `
17
+ create-blokd
18
+
19
+ Usage:
20
+ npm create blokd@beta my-app
21
+ pnpm create blokd my-app
22
+ yarn create blokd my-app
23
+
24
+ Options:
25
+ --template <name> Template to use. Default: minimal
26
+ --install Install dependencies after creating the project
27
+ --no-install Do not install dependencies
28
+ --pm <name> Package manager: pnpm, npm, yarn, bun
29
+ -h, --help Show help
30
+
31
+ Examples:
32
+ pnpm create blokd my-app
33
+ pnpm create blokd my-app --template minimal
34
+ pnpm create blokd my-app --install
35
+ `;
36
+
37
+ function main() {
38
+ if (args.includes("-h") || args.includes("--help")) {
39
+ console.log(help.trim());
40
+ process.exit(0);
41
+ }
42
+
43
+ const parsed = parseArgs(args);
44
+
45
+ if (!parsed.name) {
46
+ console.error("Missing project name.");
47
+ console.error("");
48
+ console.error("Usage:");
49
+ console.error(" pnpm create blokd my-app");
50
+ process.exit(1);
51
+ }
52
+
53
+ const templateName = parsed.template ?? "minimal";
54
+ const templateDir = join(templatesRoot, templateName);
55
+
56
+ if (!existsSync(templateDir)) {
57
+ console.error(`Unknown template: ${templateName}`);
58
+ console.error("");
59
+ console.error("Available templates:");
60
+ for (const name of listTemplates()) {
61
+ console.error(` - ${name}`);
62
+ }
63
+ process.exit(1);
64
+ }
65
+
66
+ const targetDir = resolve(process.cwd(), parsed.name);
67
+
68
+ if (existsSync(targetDir) && readdirSync(targetDir).length > 0) {
69
+ console.error(`Target directory is not empty: ${targetDir}`);
70
+ process.exit(1);
71
+ }
72
+
73
+ mkdirSync(targetDir, { recursive: true });
74
+ copyDirectory(templateDir, targetDir);
75
+
76
+ updatePackageName(join(targetDir, "package.json"), parsed.name);
77
+
78
+ console.log("");
79
+ console.log(`Created ${parsed.name} with the ${templateName} template.`);
80
+ console.log("");
81
+
82
+ const packageManager = parsed.pm || detectPackageManager();
83
+
84
+ if (parsed.install) {
85
+ console.log(`Installing dependencies with ${packageManager}...`);
86
+ const result = spawnSync(packageManager, ["install"], {
87
+ cwd: targetDir,
88
+ stdio: "inherit",
89
+ shell: process.platform === "win32"
90
+ });
91
+
92
+ if (result.status !== 0) {
93
+ console.error("");
94
+ console.error("Dependency installation failed.");
95
+ console.error(`Run manually: cd ${parsed.name} && ${packageManager} install`);
96
+ process.exit(result.status ?? 1);
97
+ }
98
+
99
+ console.log("");
100
+ console.log("Done.");
101
+ console.log("");
102
+ console.log(`Next steps:`);
103
+ console.log(` cd ${parsed.name}`);
104
+ console.log(` ${packageManager} dev`);
105
+ return;
106
+ }
107
+
108
+ console.log("Next steps:");
109
+ console.log(` cd ${parsed.name}`);
110
+ console.log(` ${packageManager} install`);
111
+ console.log(` ${packageManager} dev`);
112
+ }
113
+
114
+ function parseArgs(argv) {
115
+ const parsed = {
116
+ name: "",
117
+ template: "minimal",
118
+ install: false,
119
+ pm: undefined
120
+ };
121
+
122
+ for (let i = 0; i < argv.length; i++) {
123
+ const arg = argv[i];
124
+
125
+ if (arg === "--template") {
126
+ parsed.template = argv[++i];
127
+ continue;
128
+ }
129
+
130
+ if (arg.startsWith("--template=")) {
131
+ parsed.template = arg.slice("--template=".length);
132
+ continue;
133
+ }
134
+
135
+ if (arg === "--install") {
136
+ parsed.install = true;
137
+ continue;
138
+ }
139
+
140
+ if (arg === "--no-install") {
141
+ parsed.install = false;
142
+ continue;
143
+ }
144
+
145
+ if (arg === "--pm") {
146
+ parsed.pm = argv[++i];
147
+ continue;
148
+ }
149
+
150
+ if (arg.startsWith("--pm=")) {
151
+ parsed.pm = arg.slice("--pm=".length);
152
+ continue;
153
+ }
154
+
155
+ if (!arg.startsWith("-") && !parsed.name) {
156
+ parsed.name = arg;
157
+ continue;
158
+ }
159
+ }
160
+
161
+ if (!parsed.name) parsed.name = "my-blokd-app";
162
+
163
+ validateProjectName(parsed.name);
164
+
165
+ if (parsed.pm && !["pnpm", "npm", "yarn", "bun"].includes(parsed.pm)) {
166
+ console.error(`Unsupported package manager: ${parsed.pm}`);
167
+ process.exit(1);
168
+ }
169
+
170
+ return parsed;
171
+ }
172
+
173
+ function validateProjectName(name) {
174
+ if (name === "." || name === "./") return;
175
+
176
+ const base = name.split(/[\\/]/).filter(Boolean).pop() ?? name;
177
+
178
+ if (!/^[a-zA-Z0-9._-]+$/.test(base)) {
179
+ console.error(`Invalid project name: ${name}`);
180
+ console.error("Use letters, numbers, dots, dashes, or underscores.");
181
+ process.exit(1);
182
+ }
183
+ }
184
+
185
+ function detectPackageManager() {
186
+ const ua = process.env.npm_config_user_agent ?? "";
187
+
188
+ if (ua.startsWith("pnpm")) return "pnpm";
189
+ if (ua.startsWith("yarn")) return "yarn";
190
+ if (ua.startsWith("bun")) return "bun";
191
+ if (ua.startsWith("npm")) return "npm";
192
+
193
+ return "pnpm";
194
+ }
195
+
196
+ function listTemplates() {
197
+ if (!existsSync(templatesRoot)) return [];
198
+ return readdirSync(templatesRoot).filter(name => {
199
+ const full = join(templatesRoot, name);
200
+ return statSync(full).isDirectory();
201
+ });
202
+ }
203
+
204
+ function copyDirectory(from, to) {
205
+ mkdirSync(to, { recursive: true });
206
+
207
+ for (const entry of readdirSync(from)) {
208
+ const source = join(from, entry);
209
+ const target = join(to, entry);
210
+
211
+ const stat = statSync(source);
212
+
213
+ if (stat.isDirectory()) {
214
+ copyDirectory(source, target);
215
+ continue;
216
+ }
217
+
218
+ const content = readFileSync(source);
219
+ writeFileSync(target, content);
220
+ }
221
+ }
222
+
223
+ function updatePackageName(packageJsonPath, projectName) {
224
+ if (!existsSync(packageJsonPath)) return;
225
+
226
+ const json = JSON.parse(readFileSync(packageJsonPath, "utf8"));
227
+ const baseName = projectName.split(/[\\/]/).filter(Boolean).pop() ?? projectName;
228
+
229
+ json.name = sanitizePackageName(baseName);
230
+
231
+ writeFileSync(packageJsonPath, `${JSON.stringify(json, null, 2)}\n`);
232
+ }
233
+
234
+ function sanitizePackageName(name) {
235
+ return name
236
+ .trim()
237
+ .toLowerCase()
238
+ .replace(/[^a-z0-9._-]/g, "-")
239
+ .replace(/^[._-]+/, "")
240
+ .replace(/[._-]+$/, "") || "my-blokd-app";
241
+ }
242
+
243
+ main();
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "create-blokd",
3
+ "version": "0.1.0-beta.2",
4
+ "description": "Create a new Blokd project.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "bin": {
8
+ "create-blokd": "./bin/create-blokd.js"
9
+ },
10
+ "files": [
11
+ "bin",
12
+ "templates",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "keywords": [
17
+ "blokd",
18
+ "create-blokd",
19
+ "starter",
20
+ "template",
21
+ "hono",
22
+ "vite",
23
+ "ssr"
24
+ ],
25
+ "engines": {
26
+ "node": ">=20.19"
27
+ }
28
+ }
@@ -0,0 +1,11 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Blokd App</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ </head>
8
+ <body>
9
+ <p>This file is used by Vite during development.</p>
10
+ </body>
11
+ </html>
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "blokd-minimal-app",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "packageManager": "pnpm@11.0.0",
7
+ "scripts": {
8
+ "dev": "vite --host 0.0.0.0",
9
+ "build": "vite build",
10
+ "typecheck": "tsc --noEmit"
11
+ },
12
+ "dependencies": {
13
+ "blokd": "0.1.0-beta.2",
14
+ "hono": ">=4.5 <5"
15
+ },
16
+ "devDependencies": {
17
+ "@types/node": ">=20 <23",
18
+ "typescript": ">=5.5 <6",
19
+ "vite": ">=6 <9"
20
+ }
21
+ }
@@ -0,0 +1,4 @@
1
+ declare module "virtual:blokd/routes" {
2
+ const routes: import("blokd/hono").RouteEntry[];
3
+ export default routes;
4
+ }
@@ -0,0 +1,3 @@
1
+ import { startResumability } from "blokd/client";
2
+
3
+ startResumability();
@@ -0,0 +1,4 @@
1
+ export function sayHello(event: Event, ctx: any) {
2
+ const button = event.currentTarget as HTMLButtonElement;
3
+ button.textContent = ctx.state.message;
4
+ }
@@ -0,0 +1,11 @@
1
+ export default function NotFound() {
2
+ return (
3
+ <section>
4
+ <h1>Page not found</h1>
5
+ <p>The page you requested does not exist.</p>
6
+ <p>
7
+ <a href="/">Return home</a>
8
+ </p>
9
+ </section>
10
+ );
11
+ }
@@ -0,0 +1,17 @@
1
+ type ErrorPageProps = {
2
+ error?: {
3
+ message?: string;
4
+ };
5
+ };
6
+
7
+ export default function ErrorPage(props: ErrorPageProps) {
8
+ return (
9
+ <section>
10
+ <h1>Something went wrong</h1>
11
+ <p>
12
+ {props.error?.message ??
13
+ "The application encountered an unexpected error."}
14
+ </p>
15
+ </section>
16
+ );
17
+ }
@@ -0,0 +1,34 @@
1
+ type LayoutProps = {
2
+ children?: unknown;
3
+ meta?: {
4
+ title?: string;
5
+ description?: string;
6
+ };
7
+ };
8
+
9
+ export default function Layout(props: LayoutProps) {
10
+ return (
11
+ <html lang="en">
12
+ <head>
13
+ <title>{props.meta?.title ?? "Blokd App"}</title>
14
+ <meta
15
+ name="description"
16
+ content={props.meta?.description ?? "A minimal Blokd application."}
17
+ />
18
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
19
+ </head>
20
+
21
+ <body>
22
+ <header>
23
+ <nav>
24
+ <a href="/">Home</a>
25
+ {" · "}
26
+ <a href="/about">About</a>
27
+ </nav>
28
+ </header>
29
+
30
+ <main>{props.children}</main>
31
+ </body>
32
+ </html>
33
+ );
34
+ }
@@ -0,0 +1,17 @@
1
+ export const meta = () => ({
2
+ title: "About | Blokd App",
3
+ description: "About this minimal Blokd application."
4
+ });
5
+
6
+ export default function About() {
7
+ return (
8
+ <section>
9
+ <h1>About</h1>
10
+
11
+ <p>
12
+ This route has no event handlers or islands, so Blokd can treat it as a
13
+ static/server-rendered route.
14
+ </p>
15
+ </section>
16
+ );
17
+ }
@@ -0,0 +1,34 @@
1
+ import { signal, Island, resumable } from "blokd";
2
+
3
+ export const meta = () => ({
4
+ title: "Blokd App",
5
+ description: "A minimal Blokd application."
6
+ });
7
+
8
+ export default function Home() {
9
+ const [count, setCount] = signal(0);
10
+
11
+ return (
12
+ <section>
13
+ <h1>Blokd App</h1>
14
+
15
+ <p>
16
+ This page demonstrates Solid-familiar signals and a resumable island.
17
+ </p>
18
+
19
+ <button onClick={() => setCount(c => c + 1)}>
20
+ Count: {count()}
21
+ </button>
22
+
23
+ <Island name="demo-island" state={{ message: "Hello from Blokd" }}>
24
+ <button
25
+ type="button"
26
+ data-output
27
+ onClick={resumable("/src/resumables/demo.ts#sayHello")}
28
+ >
29
+ Run resumable handler
30
+ </button>
31
+ </Island>
32
+ </section>
33
+ );
34
+ }
@@ -0,0 +1,19 @@
1
+ import { Hono } from "hono";
2
+ import { createPages } from "blokd/hono";
3
+ import routes from "virtual:blokd/routes";
4
+
5
+ const app = new Hono();
6
+
7
+ app.get("/api/health", c => {
8
+ return c.json({ ok: true });
9
+ });
10
+
11
+ app.route(
12
+ "/",
13
+ createPages({
14
+ routes,
15
+ entryClient: "/src/entry-client.ts"
16
+ })
17
+ );
18
+
19
+ export default app;
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "jsx": "react-jsx",
7
+ "jsxImportSource": "blokd",
8
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
9
+ "types": ["node"],
10
+ "strict": true,
11
+ "skipLibCheck": true,
12
+ "allowSyntheticDefaultImports": true,
13
+ "isolatedModules": true,
14
+ "noEmit": true
15
+ },
16
+ "include": ["src", "vite.config.ts"]
17
+ }
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from "vite";
2
+ import { blokd } from "blokd/vite";
3
+
4
+ export default defineConfig({
5
+ plugins: [
6
+ blokd({
7
+ routesDir: "src/routes",
8
+ clientEntry: "/src/entry-client.ts"
9
+ })
10
+ ]
11
+ });