create-nowaki 0.11.0 → 0.12.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-nowaki",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Scaffold a new Nowaki app",
5
5
  "license": "MIT",
6
6
  "author": "VorEdge <dev@voredge.com>",
@@ -12,6 +12,7 @@ npm run dev # nowaki dev — dev server with hot reload (http://localho
12
12
  npm run build # nowaki build — production build (dist/client + dist/server)
13
13
  npm run start # nowaki start — serve the production build
14
14
  npm run prerender # nowaki prerender — static export
15
+ npx nowaki upgrade # update nowaki (CLI) + @nowaki-dev/runtime to latest
15
16
  ```
16
17
 
17
18
  ## Project layout
@@ -38,16 +39,23 @@ nowaki.config.mjs plugins (optional)
38
39
  `onClick`/hooks in route or `components/` files.
39
40
  3. **Use explicit file extensions in relative imports**:
40
41
  `import Counter from "../islands/Counter.tsx"` (not `"../islands/Counter"`).
41
- 4. **Routes** are components with an optional server-only `loader` and `action`:
42
+ 4. **Routes** are components with an optional server-only `loader` and `action`.
43
+ Optional types come from `@nowaki-dev/runtime` — `PageProps<typeof loader>`
44
+ infers the page's `data`, `LoaderContext` types `params`/cookies/headers:
42
45
  ```tsx
43
46
  // routes/blog/[slug].tsx
44
- export const loader = async ({ params }) => ({ post: await db.post(params.slug) }); // server-only
45
- export async function action(ctx) { // runs on non-GET requests
47
+ import type { LoaderContext, PageProps } from "@nowaki-dev/runtime";
48
+ export const loader = async ({ params }: LoaderContext) => ({ post: await db.post(params.slug) }); // server-only
49
+ export async function action(ctx: LoaderContext) { // runs on non-GET requests
46
50
  const form = await ctx.formData();
47
51
  return ctx.redirect("/blog"); // Post/Redirect/Get
48
52
  }
49
- export default function Post({ data }) { return <article><h1>{data.post.title}</h1></article>; }
53
+ export default function Post({ data }: PageProps<typeof loader>) { return <article><h1>{data.post.title}</h1></article>; }
50
54
  ```
55
+ A catch-all segment `routes/files/[...path].tsx` matches `/files/a/b/c`;
56
+ `params.path` is the array `["a","b","c"]`. Add `export const revalidate = 60`
57
+ (seconds) to a route for ISR: the HTML is cached and regenerated in the
58
+ background when stale (don't put per-user data on an ISR page).
51
59
  5. **API routes** are `routes/api/*.ts` with per-method exports; return a value
52
60
  (JSON-encoded) or a `Response`:
53
61
  ```ts
@@ -69,7 +77,7 @@ nowaki.config.mjs plugins (optional)
69
77
  ```ts
70
78
  // actions/todos.ts
71
79
  "use server";
72
- import { getContext } from "@nowaki-dev/runtime/server/functions.mjs";
80
+ import { getContext } from "@nowaki-dev/runtime";
73
81
  export async function addTodo(text: string) { /* runs on the server */ }
74
82
  ```
75
83
  Call it from an island like a normal async function:
@@ -77,6 +85,12 @@ nowaki.config.mjs plugins (optional)
77
85
  8. **Jetstream islands** (server-reactive, zero client JS) — give an island
78
86
  `export const live = { state, on }`; buttons use `data-live="handler"` instead
79
87
  of `onClick`. State lives on the server; the server pushes HTML patches.
88
+ 9. **Loading / error UI** (client navigation) — `routes/loading.tsx` renders
89
+ while a navigation is in flight; `routes/error.tsx` (props `{ error, reset }`,
90
+ type `ErrorPageProps`) renders if it fails. Both nest by directory. In
91
+ `error.tsx`, mark the message element `data-nowaki-error` and the retry button
92
+ `data-nowaki-reset`. Visited pages are kept in a ~30s Router Cache, so
93
+ back/forward is instant. These are server components, not islands.
80
94
 
81
95
  ## Don't
82
96
 
@@ -15,6 +15,18 @@ Other scripts: `npm run build`, `npm run start`, `npm run prerender`.
15
15
  Pass `--host` to expose dev on your LAN, `--open` to open the browser:
16
16
  `npm run dev -- --host --open`.
17
17
 
18
+ ## Update
19
+
20
+ ```bash
21
+ npx nowaki upgrade # bumps nowaki (CLI) and @nowaki-dev/runtime to latest
22
+ ```
23
+
24
+ `nowaki upgrade` detects your package manager and updates both packages,
25
+ rewriting the `package.json` ranges. (A plain `npm update` won't cross a
26
+ `0.x` minor, so prefer `nowaki upgrade` — or install `@latest` by hand.)
27
+ Pin a version with `--to`, e.g. `npx nowaki upgrade --to 0.11.0`. Pre-1.0,
28
+ check the release notes before upgrading; minors can include breaking changes.
29
+
18
30
  ## Structure
19
31
 
20
32
  ```
@@ -9,11 +9,11 @@
9
9
  "prerender": "nowaki prerender"
10
10
  },
11
11
  "dependencies": {
12
- "@nowaki-dev/runtime": "^0.9.0",
12
+ "@nowaki-dev/runtime": "^0.10.0",
13
13
  "preact": "^10.25.4",
14
14
  "preact-render-to-string": "^6.5.13"
15
15
  },
16
16
  "devDependencies": {
17
- "nowaki": "^0.10.0"
17
+ "nowaki": "^0.11.0"
18
18
  }
19
19
  }
@@ -1,3 +1,4 @@
1
+ import type { PageProps } from "@nowaki-dev/runtime";
1
2
  import Counter from "../islands/Counter.tsx";
2
3
 
3
4
  const CSS = `
@@ -32,9 +33,7 @@ export const head = `<style>${CSS}</style>`;
32
33
 
33
34
  export const loader = async () => ({ greeting: "Welcome to Nowaki" });
34
35
 
35
- type Data = Awaited<ReturnType<typeof loader>>;
36
-
37
- export default function Home({ data }: { data: Data }) {
36
+ export default function Home({ data }: PageProps<typeof loader>) {
38
37
  return (
39
38
  <main class="wrap">
40
39
  <div class="brand">