@webjsdev/cli 0.10.5 → 0.10.6
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/bin/webjs.js +22 -0
- package/lib/create.js +20 -0
- package/package.json +1 -1
- package/templates/.vscode/settings.json +15 -0
- package/templates/AGENTS.md +38 -2
package/bin/webjs.js
CHANGED
|
@@ -42,6 +42,7 @@ const USAGE = `webjs commands:
|
|
|
42
42
|
webjs start [--port 8080] Start production server (serves source directly, no build step)
|
|
43
43
|
webjs test [--server|--browser] Run server + browser tests
|
|
44
44
|
webjs check Run correctness checks on the app
|
|
45
|
+
webjs types Generate .webjs/routes.d.ts (typed Route union + per-route params)
|
|
45
46
|
webjs create <name> [--template full-stack|api|saas] [--no-install] Scaffold a new webjs app
|
|
46
47
|
(only 3 templates exist. default: full-stack with Prisma+SQLite)
|
|
47
48
|
Auto-runs the detected package manager's install in the new dir
|
|
@@ -277,6 +278,27 @@ async function main() {
|
|
|
277
278
|
}
|
|
278
279
|
break;
|
|
279
280
|
}
|
|
281
|
+
case 'types': {
|
|
282
|
+
// Generate `.webjs/routes.d.ts` from the app's `app/` routes (#258),
|
|
283
|
+
// narrowing the @webjsdev/core `Route` href union + per-route `params`.
|
|
284
|
+
// Opt-in codegen: the static types in @webjsdev/core work without it
|
|
285
|
+
// (un-generated apps see `Route = string`).
|
|
286
|
+
const { generateRouteTypes } = await import('@webjsdev/server');
|
|
287
|
+
const { mkdir, writeFile } = await import('node:fs/promises');
|
|
288
|
+
const appDir = process.cwd();
|
|
289
|
+
const text = await generateRouteTypes(appDir);
|
|
290
|
+
const outDir = join(appDir, '.webjs');
|
|
291
|
+
await mkdir(outDir, { recursive: true });
|
|
292
|
+
const outFile = join(outDir, 'routes.d.ts');
|
|
293
|
+
await writeFile(outFile, text);
|
|
294
|
+
// Count the typed routes (each `WebjsRoutes` key is one route literal).
|
|
295
|
+
const count = (text.match(/^\s+".*": true;$/gm) || []).length;
|
|
296
|
+
console.log(
|
|
297
|
+
`webjs types: wrote .webjs/routes.d.ts (${count} route${count === 1 ? '' : 's'} typed). ` +
|
|
298
|
+
`Ensure tsconfig "include" lists ".webjs/routes.d.ts" so tsserver picks it up.`,
|
|
299
|
+
);
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
280
302
|
case 'create': {
|
|
281
303
|
const name = rest[0];
|
|
282
304
|
if (!name || name.startsWith('-')) {
|
package/lib/create.js
CHANGED
|
@@ -346,6 +346,22 @@ export async function scaffoldApp(name, cwd, opts = {}) {
|
|
|
346
346
|
{ name: '@webjsdev/ts-plugin' },
|
|
347
347
|
],
|
|
348
348
|
},
|
|
349
|
+
// `.webjs/routes.d.ts` is the OPT-IN generated route-types overlay (#258):
|
|
350
|
+
// run `webjs types` (or `webjs dev`, which emits it) to narrow the
|
|
351
|
+
// @webjsdev/core `Route` href union + per-route `params`. Listed in
|
|
352
|
+
// `include` so tsserver picks it up; it is gitignored (regenerated per
|
|
353
|
+
// machine), so a fresh clone runs `webjs dev` / `webjs types` to recreate
|
|
354
|
+
// it, and the static @webjsdev/core types work even when it is absent.
|
|
355
|
+
include: [
|
|
356
|
+
'app/**/*',
|
|
357
|
+
'components/**/*',
|
|
358
|
+
'modules/**/*',
|
|
359
|
+
'lib/**/*',
|
|
360
|
+
'middleware.js',
|
|
361
|
+
'middleware.ts',
|
|
362
|
+
'.webjs/routes.d.ts',
|
|
363
|
+
],
|
|
364
|
+
exclude: ['node_modules', '.webjs/vendor', 'prisma/migrations'],
|
|
349
365
|
}, null, 2) + '\n');
|
|
350
366
|
|
|
351
367
|
// --- Templates (AGENTS.md, CONVENTIONS.md, CLAUDE.md, test files, Claude hooks) ---
|
|
@@ -397,6 +413,10 @@ export async function scaffoldApp(name, cwd, opts = {}) {
|
|
|
397
413
|
// to main, mirroring the webjs framework's own CI.
|
|
398
414
|
'.github/workflows/ci.yml',
|
|
399
415
|
'.editorconfig',
|
|
416
|
+
// VS Code: associate the published webjs-config JSON Schema with the
|
|
417
|
+
// package.json `webjs` block, so an unknown / typo'd key (#259) is
|
|
418
|
+
// flagged natively in the editor instead of silently dropped.
|
|
419
|
+
'.vscode/settings.json',
|
|
400
420
|
// Production / deploy scaffolding. `docker compose up --build` runs
|
|
401
421
|
// the app locally with the same Dockerfile production builds from.
|
|
402
422
|
'Dockerfile',
|
package/package.json
CHANGED
package/templates/AGENTS.md
CHANGED
|
@@ -112,6 +112,15 @@ layered on top:
|
|
|
112
112
|
See [docs.webjs.com → Editor setup](https://docs.webjs.com/docs/editor-setup)
|
|
113
113
|
for the full walkthrough.
|
|
114
114
|
|
|
115
|
+
**Config validation in `package.json`.** The scaffold ships
|
|
116
|
+
`.vscode/settings.json`, which associates the published webjs-config JSON
|
|
117
|
+
Schema (`@webjsdev/server/webjs-config.schema.json`) with the `webjs` block
|
|
118
|
+
of `package.json`. In VS Code an unknown / typo'd `webjs.*` key (`redirect`
|
|
119
|
+
for `redirects`, say) is then flagged inline instead of silently dropped to
|
|
120
|
+
the default. The same shape is typed by the `WebjsConfig` type from
|
|
121
|
+
`@webjsdev/core` (`import type { WebjsConfig } from '@webjsdev/core'`) for a
|
|
122
|
+
typed reference.
|
|
123
|
+
|
|
115
124
|
## UI components: Webjs UI (preinstalled)
|
|
116
125
|
|
|
117
126
|
This scaffold ships with the standard Webjs UI component kit
|
|
@@ -267,6 +276,28 @@ test/<feature>/ feature-scoped tests, one folder per concern
|
|
|
267
276
|
middleware.ts root middleware (optional, outermost)
|
|
268
277
|
```
|
|
269
278
|
|
|
279
|
+
### Typed page / layout / route-handler props
|
|
280
|
+
|
|
281
|
+
Type page / layout / route-handler arguments with the exported helpers so a
|
|
282
|
+
param typo is a compile-time error:
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
import type { PageProps, LayoutProps, RouteHandlerContext } from '@webjsdev/core';
|
|
286
|
+
|
|
287
|
+
export default function Post({ params }: PageProps<'/blog/[slug]'>) {
|
|
288
|
+
return html`<h1>${params.slug}</h1>`; // params typed { slug: string }
|
|
289
|
+
}
|
|
290
|
+
export default function RootLayout({ children }: LayoutProps) { /* ... */ }
|
|
291
|
+
export async function GET(req: Request, ctx: RouteHandlerContext) { /* ctx.params */ }
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Run `webjs types` once (and ensure `tsconfig.json` `include` lists
|
|
295
|
+
`.webjs/routes.d.ts`, the scaffold already does) to generate the route union:
|
|
296
|
+
`PageProps<'/blog/[slug]'>['params']` then narrows to `{ slug: string }` and
|
|
297
|
+
`navigate()` only accepts real app routes. `webjs dev` regenerates the file on
|
|
298
|
+
startup, so it stays current. Without it, `params` is `Record<string, string>`
|
|
299
|
+
and `navigate()` accepts any string (non-breaking).
|
|
300
|
+
|
|
270
301
|
## Database (Prisma + SQLite by default)
|
|
271
302
|
|
|
272
303
|
Every scaffold includes a Prisma setup pointed at a local SQLite file.
|
|
@@ -709,8 +740,13 @@ return html`
|
|
|
709
740
|
```
|
|
710
741
|
|
|
711
742
|
The router's `closest('webjs-frame')` detection takes precedence over
|
|
712
|
-
layout markers. Only the frame's content swaps. Use this sparingly
|
|
713
|
-
folder-based layouts handle 99% of cases.
|
|
743
|
+
layout markers. Only the frame's content swaps. Use this sparingly,
|
|
744
|
+
folder-based layouts handle 99% of cases. When a frame nav's response
|
|
745
|
+
lacks the matching `<webjs-frame id>` (e.g. an auth redirect), the router
|
|
746
|
+
fires a cancelable, bubbling `webjs:frame-missing` event (detail
|
|
747
|
+
`{ frameId, url, document }`) and leaves the frame unchanged rather than
|
|
748
|
+
silently swapping the whole page; call `preventDefault()` to take over
|
|
749
|
+
the outcome (e.g. `location.assign(e.detail.url)`).
|
|
714
750
|
|
|
715
751
|
### 5. `loading.ts` for per-segment skeletons
|
|
716
752
|
|