create-pracht 0.6.0 → 0.6.1

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-pracht",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Interactive and scriptable starter CLI for creating full-stack Preact apps with Pracht.",
5
5
  "keywords": [
6
6
  "pracht",
@@ -137,6 +137,14 @@ overrides the route-level strategy for a single anchor (and accepts the extra
137
137
  option), so a route can stay on `"intent"` while its primary-nav link opts
138
138
  into `"viewport"` or `"render"`.
139
139
 
140
+ If every route ends up on `"none"`, do not stop there — the prefetch listeners
141
+ still ship, in a chunk the router lazily imports on every page. Recommend
142
+ `pracht({ client: { prefetch: false } })` instead, which compiles the whole
143
+ mechanism out (~2.6 KB gzip and one fewer request). Confirm nothing relies on
144
+ prefetching first: the router silently stops honouring `route({ prefetch })` and
145
+ `<Link prefetch>`, and the imperative `prefetch()` export becomes a no-op. See
146
+ `docs/PERFORMANCE.md#switching-off-js-prefetching`.
147
+
140
148
  ## Step 7: Report
141
149
 
142
150
  Three sections:
@@ -424,6 +424,15 @@ the `@pracht/image/client` types once in a `.d.ts`, and keep
424
424
  `width`/`height`/`blurDataURL` exactly like Next's static imports. Pracht's
425
425
  blur is CSS-only (no fade animation, no inline event handlers).
426
426
 
427
+ For apps that relied on `next/image` producing files during a static export,
428
+ use `?pracht&pracht-static` instead. It emits cached responsive WebP variants
429
+ and bypasses the runtime loader while retaining plain, hydration-free `<img>`
430
+ markup. When Markdown content contains relative images, prefer
431
+ `defineMarkdownCollection()` from `@pracht/markdown`; it applies the same
432
+ static pipeline to normal `![alt](./photo.jpg)` syntax. Keep root-relative
433
+ `public/` and remote image URLs unchanged, and use an absolute Vite `base` for
434
+ static variants.
435
+
427
436
  #### `useRouter` → navigation
428
437
 
429
438
  ```tsx
@@ -72,6 +72,14 @@ Work through these in order, stopping when you find the root cause:
72
72
  - Date/time rendering differences
73
73
  - Browser-only APIs used during SSR (`window`, `document`, `localStorage`)
74
74
  - Conditional rendering based on client state
75
+ - Two copies of `@pracht/core` in the SSR module graph. The tell is that
76
+ `useLocation()` returns `/`, `useParams()` returns `{}`, and
77
+ `useRouteData()` returns `undefined` in the server-rendered HTML for
78
+ *every* page, while the hydrated client is correct — the provider and the
79
+ hooks hold different `createContext()` objects. The plugin prevents this by
80
+ keeping `@pracht/*` in `ssr.noExternal` (dev and build alike); listing a
81
+ `@pracht/*` package in `ssr.external` overrides that and brings the split
82
+ back.
75
83
  - **Missing shell**: Referencing an unregistered shell name throws at manifest resolution — `Unknown shell "..." for route "...". Did you mean "..."? Registered shells: ...` — and shows up in the dev error overlay as soon as the server loads the manifest. Verify the shell is registered in `defineApp({ shells: { ... } })` and assigned to the route/group.
76
84
  - **404 page**: Route not matched — check manifest wiring (step 1). In `pracht dev`, unmatched navigations render a dev-only 404 page listing every registered route with its render mode; compare the requested path against that table. The route table is also printed on dev-server startup and available via `pracht inspect routes`. Apps that declare `defineApp({ notFound })` render their own 404 page instead (in dev and production alike), so the route table is not shown — check `pracht inspect routes` directly. A 404 on a URL you *do* expect to work usually means the loader threw `notFound()`, not that matching failed.
77
85
 
@@ -133,7 +133,7 @@ pracht build
133
133
  npx wrangler deploy
134
134
  ```
135
135
 
136
- To smoke-test the built worker locally first, run `pracht preview` — it builds and then delegates to `wrangler dev`, which serves the wrangler config's `main` entry, `dist/server/worker.js`.
136
+ To smoke-test the built worker locally first, run `pracht preview` — it builds and then delegates to `wrangler dev`, which serves the wrangler config's `main` entry, `dist/server/worker.js`. Keep `no_bundle: true` and the JavaScript `ESModule` rule: Pracht's Vite output is already bundled and can contain lazy server chunks that Wrangler must upload separately.
137
137
 
138
138
  Wrangler owns the Worker's binding environment. Put local-only secrets such as
139
139
  `PRACHT_CONFIRMATION_SECRET` and `PRACHT_REVALIDATE_TOKEN` in a gitignored
@@ -151,8 +151,10 @@ pracht build
151
151
  npx wrangler dev --config wrangler.local.jsonc --port 3000
152
152
  ```
153
153
 
154
- The local config must keep `main: "dist/server/worker.js"` and omit the
155
- production route. `pracht preview` does not forward Wrangler's `--config` flag.
154
+ The local config must keep `main: "dist/server/worker.js"`, keep
155
+ `no_bundle: true`, include the JavaScript `ESModule` rule, and omit the
156
+ production route. `pracht preview` does not forward Wrangler's `--config`
157
+ flag.
156
158
 
157
159
  ### Wrangler Configuration
158
160
 
@@ -161,6 +163,8 @@ production route. `pracht preview` does not forward Wrangler's `--config` flag.
161
163
  {
162
164
  "name": "my-pracht-app",
163
165
  "main": "dist/server/worker.js",
166
+ "no_bundle": true,
167
+ "rules": [{ "type": "ESModule", "globs": ["**/*.js", "**/*.mjs"] }],
164
168
  "compatibility_date": "2026-04-06",
165
169
  "assets": {
166
170
  "binding": "ASSETS",
@@ -170,7 +174,7 @@ production route. `pracht preview` does not forward Wrangler's `--config` flag.
170
174
  }
171
175
  ```
172
176
 
173
- `"binding": "ASSETS"` and `"run_worker_first": true` are required. Without the binding, the worker's `env.ASSETS` resolves to nothing and the runtime silently falls back to `null` — headers and ISG manifests load empty, so SSG serving, ISG revalidation, and per-route headers all silently no-op. The canonical config lives at `examples/cloudflare/wrangler.jsonc`. If you rename the binding with `assetsBinding` (below), the wrangler `binding` value must match.
177
+ `"no_bundle": true`, the JavaScript `ESModule` rule, `"binding": "ASSETS"`, and `"run_worker_first": true` are required. Without the first two settings, Wrangler either re-bundles Pracht's Vite output and folds lazy server chunks into the entry or omits those chunks from the upload. Without the binding, the worker's `env.ASSETS` resolves to nothing and the runtime silently falls back to `null` — headers and ISG manifests load empty, so SSG serving, ISG revalidation, and per-route headers all silently no-op. The canonical config lives at `examples/cloudflare/wrangler.jsonc`. If you rename the binding with `assetsBinding` (below), the wrangler `binding` value must match.
174
178
 
175
179
  ### Bindings (KV, D1, R2)
176
180
 
@@ -98,6 +98,10 @@ a markdown summary (graph diff + verify + budgets) worth attaching to it.
98
98
  validates every named export of the deploy entry and rejects the build
99
99
  metadata (`buildTarget`, manifests, `resolvedApp`, ...) that `server.js`
100
100
  exports for the prerender pass.
101
+ - `no_bundle` is `true`, with an `ESModule` rule whose globs include
102
+ `"**/*.js"`. Pracht's Vite output is already bundled and may contain lazy
103
+ server chunks; these settings make Wrangler upload the chunks as separate
104
+ modules instead of folding them into the entry file.
101
105
  - `assets.directory` points to `dist/client`.
102
106
  - `compatibility_date` is set, and is a date the installed workerd supports.
103
107
  It must not be *newer* than the runtime: workerd refuses to start with
@@ -128,8 +132,10 @@ a markdown summary (graph diff + verify + budgets) worth attaching to it.
128
132
  gateway with a normalized `cf.cacheKey`; also check that markdown-capable
129
133
  routes normalize `Accept` at the gateway when variant fan-out matters.
130
134
  - Bundle size: measure what actually deploys — `dist/server/worker.js` plus
131
- its `dist/server/server.js` import (wrangler bundles the import graph of
132
- `main`; `worker.js` alone is a few lines). Workers limit is ~1 MB
135
+ its `dist/server/server.js` import and lazy chunks (`no_bundle: true` plus
136
+ the JavaScript `ESModule` rule uploads the pre-built module graph;
137
+ `worker.js` alone is a few lines).
138
+ Workers limit is ~1 MB
133
139
  compressed for free tier, ~10 MB on paid. Warn at 80% of the active limit.
134
140
 
135
141
  ### Vercel (`@pracht/adapter-vercel`)
@@ -107,8 +107,12 @@ same-origin anchor. It also accepts navigation-behavior props:
107
107
  `prefetch="none" | "hover" | "intent" | "viewport" | "render"` (per-link
108
108
  prefetch strategy, default `"intent"`), `preserveScroll` (keep the scroll
109
109
  position), and `viewTransition` (animate the navigation with the View Transitions API
110
- where supported). There is also an imperative `prefetch()` export and a
111
- `useNavigation()` hook for pending navigation/submission state.
110
+ where supported). Set `speculate={false}` on links that browser speculation
111
+ rules must not prefetch or prerender. Because it is independent of the JS
112
+ `prefetch` strategy, use both `speculate={false}` and `prefetch="none"` for GET
113
+ links with side effects. There is also an imperative
114
+ `prefetch()` export and a `useNavigation()` hook for pending
115
+ navigation/submission state.
112
116
 
113
117
  ### Outside components
114
118
 
@@ -33,8 +33,9 @@ pnpm list --depth 1 --json | grep -A2 '@pracht/' # or read package.json + lock
33
33
 
34
34
  The family: `@pracht/core`, `@pracht/cli`, `@pracht/vite-plugin`,
35
35
  `@pracht/adapter-node`, `@pracht/adapter-cloudflare`, `@pracht/adapter-vercel`,
36
- `@pracht/preact-ssr-precompile`, `@pracht/image`. Get the latest published
37
- versions with `npm view <pkg> version`.
36
+ `@pracht/preact-ssr-precompile`, `@pracht/content`, `@pracht/markdown`,
37
+ `@pracht/image`. Get the latest published versions with
38
+ `npm view <pkg> version`.
38
39
 
39
40
  ## Step 2: Understand the versioning model
40
41
 
@@ -75,6 +76,8 @@ https://raw.githubusercontent.com/JoviDeCroock/pracht/main/packages/<dir>/CHANGE
75
76
  | `@pracht/vite-plugin` | `packages/vite-plugin` |
76
77
  | `@pracht/adapter-node` / `-cloudflare` / `-vercel` | `packages/adapter-*` |
77
78
  | `@pracht/preact-ssr-precompile` | `packages/preact-ssr-precompile` |
79
+ | `@pracht/content` | `packages/content` |
80
+ | `@pracht/markdown` | `packages/markdown` |
78
81
  | `@pracht/image` | `packages/image` |
79
82
 
80
83
  Changelogs are changesets-generated: `## X.Y.Z` sections containing
package/src/index.js CHANGED
@@ -1298,6 +1298,11 @@ function createWranglerConfig(projectName) {
1298
1298
  // validates every named export of the deployed entry module and rejects the
1299
1299
  // build metadata (buildTarget, manifests, ...) server.js also exports.
1300
1300
  ' "main": "dist/server/worker.js",',
1301
+ // Pracht's Vite build is the authoritative bundle and may contain lazy
1302
+ // server chunks. A second Wrangler bundle would inline them again; the
1303
+ // module rule makes Wrangler upload those chunks next to the entry.
1304
+ ' "no_bundle": true,',
1305
+ ' "rules": [{ "type": "ESModule", "globs": ["**/*.js", "**/*.mjs"] }],',
1301
1306
  ` "compatibility_date": ${JSON.stringify(compatibilityDate)},`,
1302
1307
  ' "assets": {',
1303
1308
  ' "binding": "ASSETS",',