@webjsdev/cli 0.10.24 → 0.10.26
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 +1 -1
- package/bin/webjs.js +10 -5
- package/lib/create.js +104 -8
- package/package.json +1 -1
- package/templates/AGENTS.md +12 -3
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ npx @webjsdev/cli create my-app
|
|
|
33
33
|
cd my-app && npm run dev
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
`webjs create` installs dependencies in the new directory by default on **Node** (it needs `node_modules` to run). On **Bun** it **skips** the install (zero-install: `bun run dev` resolves deps on the fly). Pass `--install` to force the install, or `--no-install` to skip it, on either runtime.
|
|
37
37
|
|
|
38
38
|
## Commands
|
|
39
39
|
|
package/bin/webjs.js
CHANGED
|
@@ -50,12 +50,12 @@ const USAGE = `webjs commands:
|
|
|
50
50
|
webjs doctor Verify project health (Node, tsconfig, env, vendor pins, importmap coherence, @webjsdev versions, git hook, page/layout elision)
|
|
51
51
|
webjs types Generate .webjs/routes.d.ts (typed Route union + per-route params)
|
|
52
52
|
webjs typecheck [tsc args...] Type-check the app with the project's tsc --noEmit (non-zero on errors)
|
|
53
|
-
webjs create <name> [--template full-stack|api|saas] [--db sqlite|postgres] [--runtime node|bun] [--no-install] Scaffold a new webjs app
|
|
53
|
+
webjs create <name> [--template full-stack|api|saas] [--db sqlite|postgres] [--runtime node|bun] [--install|--no-install] Scaffold a new webjs app
|
|
54
54
|
(only 3 templates exist. default: full-stack, Drizzle, --db sqlite, --runtime node)
|
|
55
55
|
--runtime bun emits a Bun-flavored app (bun.lock, bun Dockerfile/CI, bun docs);
|
|
56
56
|
also auto-detected when run via "bun create webjs".
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
Install default is per runtime: Node installs; Bun skips (zero-install,
|
|
58
|
+
"bun run dev" resolves deps on the fly). --install / --no-install override.
|
|
59
59
|
webjs db generate Generate a SQL migration from the schema (drizzle-kit generate)
|
|
60
60
|
webjs db migrate Apply pending migrations (drizzle-kit migrate)
|
|
61
61
|
webjs db push Push the schema straight to the dev DB (drizzle-kit push)
|
|
@@ -521,7 +521,11 @@ files.
|
|
|
521
521
|
Full docs: https://docs.webjs.com`);
|
|
522
522
|
process.exit(1);
|
|
523
523
|
}
|
|
524
|
+
// Install policy (#682). Default per runtime: Node installs (needs
|
|
525
|
+
// node_modules to run); Bun skips (zero-install, `bun run dev` resolves
|
|
526
|
+
// on the fly). `--install` / `--no-install` override either way.
|
|
524
527
|
const noInstall = rest.includes('--no-install');
|
|
528
|
+
const explicitInstall = rest.includes('--install');
|
|
525
529
|
// --db picks the database dialect: sqlite (default) or postgres.
|
|
526
530
|
const db = flag(rest, '--db', 'sqlite');
|
|
527
531
|
// --runtime picks the target runtime: node (default) or bun. Orthogonal
|
|
@@ -532,8 +536,9 @@ Full docs: https://docs.webjs.com`);
|
|
|
532
536
|
console.error(`Error: unknown --runtime '${runtime}'. Only node / bun are supported.`);
|
|
533
537
|
process.exit(1);
|
|
534
538
|
}
|
|
535
|
-
const { scaffoldApp } = await import('../lib/create.js');
|
|
536
|
-
|
|
539
|
+
const { scaffoldApp, resolveCreateInstall } = await import('../lib/create.js');
|
|
540
|
+
const install = resolveCreateInstall({ runtime, explicitInstall, noInstall });
|
|
541
|
+
await scaffoldApp(name, process.cwd(), { template, db, runtime, install });
|
|
537
542
|
break;
|
|
538
543
|
}
|
|
539
544
|
case 'vendor': {
|
package/lib/create.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { mkdir, writeFile, readFile, cp } from 'node:fs/promises';
|
|
15
15
|
import { join, resolve, dirname } from 'node:path';
|
|
16
16
|
import { fileURLToPath } from 'node:url';
|
|
17
|
-
import { existsSync } from 'node:fs';
|
|
17
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
18
18
|
import { createRequire } from 'node:module';
|
|
19
19
|
import { spawnSync } from 'node:child_process';
|
|
20
20
|
import { bunifyProse, bunifyDockerfile, bunifyCompose, bunifyCi } from './runtime-rewrite.js';
|
|
@@ -35,6 +35,86 @@ function detectPackageManager() {
|
|
|
35
35
|
return 'npm';
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Decide whether `webjs create` runs the post-scaffold install, per target
|
|
40
|
+
* runtime (#682). Node installs by default (it needs `node_modules` to run);
|
|
41
|
+
* Bun SKIPS by default (zero-install: `bun run dev` resolves deps on the fly,
|
|
42
|
+
* #675). Under Bun zero-install webjs pins a declared dep to its package.json
|
|
43
|
+
* version via the #685/#698 onLoad rewrite (a caret range now resolves the
|
|
44
|
+
* highest match, not absolute latest), so `bun install` is the path to a frozen
|
|
45
|
+
* lockfile, not a correctness fix. Explicit flags win: `--install` forces it
|
|
46
|
+
* on, `--no-install` forces it off. The CLI entry points call this and pass an
|
|
47
|
+
* explicit boolean to `scaffoldApp`, so the library default (no install unless
|
|
48
|
+
* `install: true`) is unchanged for programmatic callers.
|
|
49
|
+
*
|
|
50
|
+
* @param {{ runtime?: string, explicitInstall?: boolean, noInstall?: boolean }} [o]
|
|
51
|
+
* @returns {boolean}
|
|
52
|
+
*/
|
|
53
|
+
export function resolveCreateInstall({ runtime, explicitInstall, noInstall } = {}) {
|
|
54
|
+
if (explicitInstall) return true;
|
|
55
|
+
if (noInstall) return false;
|
|
56
|
+
const isBun = runtime === 'bun' || (!runtime && detectPackageManager() === 'bun');
|
|
57
|
+
return !isBun;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Read the EXACT version of `@webjsdev/<pkg>` the scaffolding CLI ships with.
|
|
62
|
+
* `webjsdevRange` carets over this for the generated `package.json` (#700), so a
|
|
63
|
+
* fresh app tracks the line the CLI shipped. Walks the `require.resolve` node_modules search paths
|
|
64
|
+
* and fs-reads `<pkg>/package.json` directly: `@webjsdev/server` (and `ui`) hide
|
|
65
|
+
* `./package.json` behind `exports`, so a bare `require('<pkg>/package.json')`
|
|
66
|
+
* fails (same constraint #687 hit). Falls back to `'latest'` when the package is
|
|
67
|
+
* not resolvable (defensive; the CLI's own dependency closure is normally
|
|
68
|
+
* present), which keeps the scaffold working rather than emitting a bad pin.
|
|
69
|
+
* @param {string} pkg e.g. 'cli', 'core', 'server'
|
|
70
|
+
* @returns {string} an exact version, or 'latest'
|
|
71
|
+
*/
|
|
72
|
+
function webjsdevVersion(pkg) {
|
|
73
|
+
const req = createRequire(import.meta.url);
|
|
74
|
+
for (const base of (req.resolve.paths(`@webjsdev/${pkg}`) || [])) {
|
|
75
|
+
const pj = join(base, '@webjsdev', pkg, 'package.json');
|
|
76
|
+
if (existsSync(pj)) {
|
|
77
|
+
try {
|
|
78
|
+
const v = JSON.parse(readFileSync(pj, 'utf8')).version;
|
|
79
|
+
if (v) return v;
|
|
80
|
+
} catch { /* unreadable; keep looking, then fall back */ }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return 'latest';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The `@webjsdev/<pkg>` specifier for the generated `package.json` (#700): a
|
|
88
|
+
* caret range over the version the scaffolding CLI ships with, so a fresh app
|
|
89
|
+
* picks up patch updates the way an npm user expects (a `^0.x` caret stays
|
|
90
|
+
* within the minor). Bun zero-install resolves a normal caret range correctly
|
|
91
|
+
* since #698, so this no longer diverges from npm. Falls back to `'latest'` when
|
|
92
|
+
* the version is not resolvable (keeps `^latest` from ever being emitted).
|
|
93
|
+
* @param {string} pkg e.g. 'cli', 'core', 'server'
|
|
94
|
+
* @returns {string}
|
|
95
|
+
*/
|
|
96
|
+
function webjsdevRange(pkg) {
|
|
97
|
+
const v = webjsdevVersion(pkg);
|
|
98
|
+
return v === 'latest' ? 'latest' : '^' + v;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Third-party dep specifiers the scaffold ships (#700). These are template deps
|
|
103
|
+
* the CLI does NOT itself depend on, so they cannot be read from the CLI's
|
|
104
|
+
* closure (unlike `@webjsdev/*`). Since #698, Bun zero-install resolves a normal
|
|
105
|
+
* caret range correctly (highest match, not absolute latest), so `pg` is an
|
|
106
|
+
* idiomatic `^` range. Drizzle is PINNED to an exact RC: its 1.0 line is a
|
|
107
|
+
* PRERELEASE (`1.0.0-rc.3`), and Bun zero-install ENOENTs on a caret-prerelease
|
|
108
|
+
* inline specifier (`drizzle-orm@^1.0.0-rc.3`, verified on Bun 1.3.14) while the
|
|
109
|
+
* exact prerelease resolves, so drizzle must stay exact until the 1.0 stable
|
|
110
|
+
* ships. Refresh on a deliberate bump.
|
|
111
|
+
*/
|
|
112
|
+
const SCAFFOLD_DEP_VERSIONS = {
|
|
113
|
+
'drizzle-orm': '1.0.0-rc.3',
|
|
114
|
+
'drizzle-kit': '1.0.0-rc.3',
|
|
115
|
+
pg: '^8.22.0',
|
|
116
|
+
};
|
|
117
|
+
|
|
38
118
|
/**
|
|
39
119
|
* Run `<pm> install` inside the scaffolded app. Returns true on success.
|
|
40
120
|
* Inherits stdio so the user sees the install progress live. Caller decides
|
|
@@ -356,14 +436,20 @@ export async function scaffoldApp(name, cwd, opts = {}) {
|
|
|
356
436
|
// for relations v2. SQLite needs NO driver dependency: the connection
|
|
357
437
|
// uses the built-in node:sqlite (Node) / bun:sqlite (Bun) via Drizzle's
|
|
358
438
|
// node-sqlite / bun-sqlite adapters. Postgres still needs the pg driver.
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
'
|
|
439
|
+
// Since #698 a normal caret range resolves correctly under bun
|
|
440
|
+
// zero-install, so @webjsdev/* and pg are idiomatic `^` ranges (#700).
|
|
441
|
+
// Drizzle stays EXACT: its 1.0 line is a prerelease RC, and bun ENOENTs
|
|
442
|
+
// on a caret-prerelease inline specifier, so a range would break it.
|
|
443
|
+
'drizzle-orm': SCAFFOLD_DEP_VERSIONS['drizzle-orm'],
|
|
444
|
+
...(dialect === 'postgres' ? { pg: SCAFFOLD_DEP_VERSIONS.pg } : {}),
|
|
445
|
+
'@webjsdev/cli': webjsdevRange('cli'),
|
|
446
|
+
'@webjsdev/core': webjsdevRange('core'),
|
|
447
|
+
'@webjsdev/server': webjsdevRange('server'),
|
|
364
448
|
},
|
|
365
449
|
devDependencies: {
|
|
366
|
-
|
|
450
|
+
// Exact pin: drizzle-kit shares drizzle-orm's prerelease 1.0 RC, which bun
|
|
451
|
+
// cannot resolve as a caret-prerelease range, so it stays exact (#700).
|
|
452
|
+
'drizzle-kit': SCAFFOLD_DEP_VERSIONS['drizzle-kit'],
|
|
367
453
|
...(dialect === 'postgres' ? { '@types/pg': '^8.11.0' } : {}),
|
|
368
454
|
// The TypeScript compiler, for `npm run typecheck` (webjs typecheck runs
|
|
369
455
|
// tsc --noEmit). Not needed at runtime (Node strips types in place), only
|
|
@@ -1404,6 +1490,13 @@ For AI agents, read this before editing scaffolded files:
|
|
|
1404
1490
|
if (!installed) {
|
|
1405
1491
|
console.log(`\n[warn] ${pm} install failed. Run '${pm} install' manually in ${name}/ to finish setup.\n`);
|
|
1406
1492
|
}
|
|
1493
|
+
} else if (isBun) {
|
|
1494
|
+
// Bun zero-install (#675): no install needed; `bun run dev` resolves deps on
|
|
1495
|
+
// the fly. Since #698 they resolve to their package.json versions (a caret
|
|
1496
|
+
// range to its highest match), so point at `bun install` for a frozen
|
|
1497
|
+
// lockfile and editor type intelligence, not a correctness fix.
|
|
1498
|
+
console.log(`Skipped install. Bun resolves dependencies on the fly, so 'bun run dev' and 'bun run start' work as-is (no node_modules).`);
|
|
1499
|
+
console.log(`These resolve to the versions in package.json. Run 'bun install' in ${name}/ to freeze a lockfile and get editor type intelligence.\n`);
|
|
1407
1500
|
}
|
|
1408
1501
|
|
|
1409
1502
|
// Next-steps banner prints LAST so the actionable command is the
|
|
@@ -1415,7 +1508,10 @@ For AI agents, read this before editing scaffolded files:
|
|
|
1415
1508
|
// generate + migrate before the first run (the example User model wants
|
|
1416
1509
|
// its table to exist). Drizzle splits Prisma's `migrate dev` into
|
|
1417
1510
|
// `db:generate` (schema to SQL) then `db:migrate` (apply).
|
|
1418
|
-
|
|
1511
|
+
// Omit the install step from the next-steps line for a deliberate Bun
|
|
1512
|
+
// zero-install (#682): `bun run dev` resolves deps on the fly, so it works
|
|
1513
|
+
// without an install. Otherwise (Node, or an install that did not run) keep it.
|
|
1514
|
+
const installSegment = (installed || (isBun && !shouldInstall)) ? '' : `${pm} install && `;
|
|
1419
1515
|
const dbSegment = isSaas ? `${pm} run db:generate && ${pm} run db:migrate && ` : '';
|
|
1420
1516
|
const runCommand = `cd ${name} && ${installSegment}${dbSegment}${pm} run dev`;
|
|
1421
1517
|
// Use `npx webjsdev ui ...` here, not `npx webjs ui ...`. The bare
|
package/package.json
CHANGED
package/templates/AGENTS.md
CHANGED
|
@@ -414,9 +414,18 @@ demand and **no `bun install` is needed**:
|
|
|
414
414
|
bun run dev # or: bun run start (no install step required)
|
|
415
415
|
```
|
|
416
416
|
|
|
417
|
-
`bun
|
|
418
|
-
|
|
419
|
-
|
|
417
|
+
`bun create` does not run an install on Bun, so a fresh app serves immediately.
|
|
418
|
+
Under zero-install, Bun's runtime auto-install resolves a BARE import to LATEST
|
|
419
|
+
(it ignores `package.json` and `bun.lock`), so webjs rewrites each declared dep's
|
|
420
|
+
specifier to an inline-versioned one via an `onLoad` transform. The version is the
|
|
421
|
+
`bun.lock` exact when present, else the `package.json` value when it is an
|
|
422
|
+
inline-safe semver (an exact pin, or a caret / tilde / comparator range, which
|
|
423
|
+
Bun resolves to the highest match). A protocol range (`workspace:`, `file:`), a
|
|
424
|
+
wildcard (`*`), and a dist-tag (`latest`) stay at latest. Run `bun install` when
|
|
425
|
+
you want versions frozen identically across machines (it materializes
|
|
426
|
+
`node_modules` from the lockfile) or editor type intelligence. (To run a
|
|
427
|
+
Node-flavored app on Bun instead, force `bun --bun run dev`, which still expects
|
|
428
|
+
an install.)
|
|
420
429
|
|
|
421
430
|
On Node the `.ts` type-stripping is the built-in `module.stripTypeScriptTypes`;
|
|
422
431
|
on Bun (which has no built-in) it comes from `amaro` automatically, so the same
|