@rshono/create 1.0.0-rc.1 → 1.0.0-rc.11

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 CHANGED
@@ -1,66 +1,113 @@
1
- # @rshono/create
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/rshono/rshono/main/logo.svg" alt="" width="72" height="72" />
3
+ </p>
2
4
 
3
- Scaffolds a new [rshono](https://github.com/rshono/rshono) app — Hono + Rspack + React Server Components.
5
+ <h1 align="center">@rshono/create</h1>
6
+
7
+ <p align="center">
8
+ Scaffolds a new <a href="https://github.com/rshono/rshono">rshono</a> app — Hono + Rspack + React Server Components.
9
+ </p>
4
10
 
5
11
  ```bash
6
- npm create @rshono@latest my-app
7
- pnpm create @rshono my-app
12
+ npx @rshono/create@latest my-app
13
+ pnx @rshono/create my-app
14
+ bunx @rshono/create my-app
8
15
  yarn create @rshono my-app
9
- bun create @rshono my-app
10
16
  ```
11
17
 
12
- The package manager that ran it is the one the project gets: it is read from `npm_config_user_agent`, used
13
- for the install, written into `packageManager` for Corepack, and used in every command the closing summary
14
- prints. Nothing asks you which one you meant.
18
+ The package manager that ran it is the one the project gets: it is read from `npm_config_user_agent`, which
19
+ every one of these runners sets, and it is used for the install, written into `packageManager` for Corepack,
20
+ and used in every command the closing summary prints. Nothing asks you which one you meant.
21
+
22
+ Yarn is the odd row out because `yarn dlx` is Berry-only, while `yarn create` works in either — and `pnx`
23
+ arrived in pnpm 10.16, before which it is `pnpm dlx`.
15
24
 
16
25
  ## The questions
17
26
 
18
27
  Six, each with a default, and each answerable by a flag instead:
19
28
 
20
- | Question | Default | Flag |
21
- | --------------------- | ------------------ | ------------------------------------------------------------------- |
22
- | Where should it go? | `my-rshono-app` | first positional argument, or `.` |
23
- | Where is it deployed? | `node` | `--deploy node\|bun\|deno\|cloudflare\|vercel\|netlify\|aws-lambda` |
24
- | Styling | plain CSS | `--tailwind` / `--no-tailwind` |
25
- | Formatting & linting | Prettier + oxlint | `--quality prettier-oxlint\|prettier-eslint\|biome\|oxc\|none` |
26
- | Install dependencies? | yes | `--no-install` |
27
- | Initialize git? | yes, unless nested | `--no-git` |
28
-
29
- Plus `--formatter` and `--linter` to set either half of the quality preset on its own, `--force` to
30
- scaffold into a directory that is not empty, `--dry-run` to see the file list and write nothing, and `-y`
31
- to take the defaults for everything not given. **A non-interactive terminal implies `-y`**, so this is one
32
- command in CI or from an agent:
29
+ | Question | Default | Flag |
30
+ | --------------------- | ------------------ | -------------------------------------------------------------- |
31
+ | Where should it go? | `my-rshono-app` | first positional argument, or `.` |
32
+ | Where is it deployed? | `node` | `-d, --deploy node\|cloudflare\|vercel\|aws-lambda` |
33
+ | Styling | plain CSS | `--tailwind` / `--no-tailwind` |
34
+ | Formatting & linting | Prettier + oxlint | `--quality prettier-oxlint\|prettier-eslint\|biome\|oxc\|none` |
35
+ | Install dependencies? | yes | `--no-install` |
36
+ | Initialize git? | yes, unless nested | `--no-git` |
37
+
38
+ Plus `--formatter prettier\|biome\|oxfmt\|none` and `--linter oxlint\|eslint\|biome\|none` to set either half
39
+ of the quality preset on its own, `--pm npm\|pnpm\|yarn\|bun` to override the package manager that was
40
+ detected, `--force` to scaffold into a directory that is not empty, `--dry-run` to see the file list and write
41
+ nothing, and `-y` to take the defaults for everything not given. **A non-interactive terminal implies `-y`**,
42
+ so this is one command in CI or from an agent:
33
43
 
34
44
  ```bash
35
- npm create @rshono@latest my-app -y --deploy cloudflare --tailwind --quality biome
45
+ npx @rshono/create@latest my-app -y --deploy cloudflare --tailwind --quality biome
36
46
  ```
37
47
 
38
- The deploy targets, and the deploy command each one prints, are generated from the framework's own
39
- presets — a target added to rshono appears here with no edit.
48
+ The deploy targets, and the deploy command each one prints, are generated from the framework's own presets —
49
+ a target added to rshono appears here with no edit.
40
50
 
41
51
  ## What you get
42
52
 
43
53
  ```
44
- rshono.config.ts the chosen deploy target; everything else commented with its default
54
+ package.json scripts, including the target's own, and the exact pins rshono is tested against
55
+ rshono.config.ts the chosen deploy target; every other setting takes its default
45
56
  tsconfig.json strict, with @/* → ./src/*
46
57
  .env committed defaults; secrets go in .env.local
58
+ .gitignore plus whatever each chosen feature adds, under a heading naming it
59
+ README.md the app's own commands, layout and deploy step
60
+ AGENTS.md where an agent finds the framework docs; CLAUDE.md imports it
47
61
  public/ favicon.svg, robots.txt
48
- src/routes.ts one page, a 404 and a 500, with the other route kinds commented
49
- src/server.ts AppEnv, request-id middleware, error reporting, /api/health, redirects, AppType
50
- src/actions.ts a 'use server' action, called from a form that works without JavaScript
51
- src/components/ layout, home, greet-form ('use client'), 404, 500
52
- src/lib/env.ts both sides of the PUBLIC_ boundary in one place
62
+ src/routes.ts one page, a 404 and a 500
63
+ src/server.ts error reporting, trailing-slash and old-path redirects, AppType
64
+ src/components/ layout, home, 404, 500
53
65
  src/styles.css element-level CSS, or the Tailwind entry
66
+ src/env.d.ts the CSS-import declaration the compiler needs
54
67
  pnpm-workspace.yaml pnpm only: which dependency install scripts this app runs (none of them)
55
68
  ```
56
69
 
57
- Then, if the dependencies were installed, the scaffold is run through its own formatter so a fresh
58
- project passes its own `format:check` rather than reporting a diff nobody made.
70
+ Scaffolding runs the install and nothing else no formatter, no linter. The templates are written to satisfy
71
+ every formatter option at its configured width, so a fresh project passes its own `format:check` without a
72
+ write pass first.
73
+
74
+ Beside `dev`, `build` and `typecheck`, the deploy target contributes the scripts only it can define, under three
75
+ names that mean the same thing in every app. **`deploy`** builds and ships it, where the platform has one
76
+ command that does the shipping (`cloudflare`, `vercel`). **`preview`** builds and runs the result here — in
77
+ workerd for `cloudflare`, and as a Node build for `vercel` and `aws-lambda`, since neither can run its own
78
+ output locally. **`start`** runs a build that already exists and never makes one, which is what a host's start
79
+ command needs — so only `node` has one, and needs no `preview`: `build` then `start` already is that.
80
+
81
+ Every command is spelled for the package manager the project got. That includes the runner for the one CLI a
82
+ scaffold does not install, Vercel's: `npx`, `pnpm dlx`, `yarn dlx` or `bunx`. Wrangler is a devDependency
83
+ instead, since `wrangler dev` is how a Cloudflare app previews.
84
+
85
+ Those scripts are for a laptop, and a platform building from git asks a different question — what to type into
86
+ two fields on a settings page, where a `deploy` script would build twice. So each target also spells out the
87
+ commands its own platform asks for, in the scaffolded README's Deploying section.
59
88
 
60
89
  `react` and `react-dom` are pinned **exactly**, at the versions the framework is tested against, and those
61
90
  pins are generated from rshono's own manifest. That is not tidiness: the RSC runtime reaches into React's
62
91
  internals, and an app installed with npm or bun has no workspace overrides to keep a single copy of it.
63
92
 
93
+ ## Two things worth knowing
94
+
95
+ **The ESLint preset pins TypeScript 6.** Linting TypeScript with ESLint means `typescript-eslint`, which reads
96
+ the compiler API directly rather than through a stable interface, so its peer range is
97
+ `typescript >=4.8.4 <6.1.0` — below the TypeScript rshono is built and tested against. An app that chooses
98
+ ESLint therefore gets `typescript ~6.0.3`, the newest that range allows: `npm install` would otherwise fail
99
+ outright on the conflict, and forcing past it hands you a linter running against a compiler API it was never
100
+ built for. The framework's declarations compile identically under either version, which is what makes this the
101
+ app's pin and not the framework's — every other preset leaves TypeScript alone. What you trade for type-aware
102
+ rules is a compiler one major behind, and the JavaScript implementation rather than the native one, so
103
+ `typecheck` on a large app is several times slower. When upstream widens the range, the pin in
104
+ `features/quality.ts` is the only thing to delete.
105
+
106
+ **Tailwind is four packages, a `postcss.config.mjs` and one rule in `rshono.config.ts`.** rshono compiles CSS
107
+ natively and has no PostCSS in it — that is deliberate, and it means an app that wants a plugin chain brings
108
+ its own, through the `rspack` hook. The overlay writes all of it, with a comment saying what to delete to go
109
+ back to plain CSS.
110
+
64
111
  ## Adding an option
65
112
 
66
113
  Every difference between two scaffolds is a `Feature` — files to overlay, dependencies, scripts,
@@ -69,44 +116,35 @@ edits and no new machinery:
69
116
 
70
117
  1. A `Feature` in `src/features/` — `templates/<id>` for the files it brings, plus whatever it adds to the
71
118
  manifest.
72
- 2. The template directory itself, as **real files**. They are copied over the base, so an overlay replaces
73
- a file rather than patching it, and template files stay valid TypeScript that an editor can check.
74
- `_name` becomes `.name` on write, because npm strips a literal `.gitignore` out of a published tarball.
119
+ 2. The template directory itself, as **real files**. They are copied over the base, so an overlay replaces a
120
+ file rather than patching it, and template files stay valid TypeScript that an editor can check. `_name`
121
+ becomes `.name` on write, because npm strips a literal `.gitignore` out of a published tarball.
75
122
  3. A prompt in `src/cli.ts`, if it deserves a question of its own — and a flag, which it always does.
76
123
 
77
- `plan(answers)` is pure: answers in, a `Map` of path → contents out, no directory touched. That is what
78
- makes the whole matrix of options testable in milliseconds (`test/plan.test.mjs`) and `--dry-run` free. It
79
- is also exported, for a tool that wants to scaffold without the prompts:
124
+ `plan(answers, pm)` is pure: answers in, a `Map` of path → contents out, no directory touched. That is what
125
+ makes the whole matrix of options testable in milliseconds (`test/plan.test.mjs`) and `--dry-run` free. It is
126
+ also exported, for a tool that wants to scaffold without the prompts:
80
127
 
81
128
  ```ts
82
129
  import { plan, writePlan } from '@rshono/create';
83
130
  ```
84
131
 
85
- ## Two things worth knowing
86
-
87
- **The ESLint preset pins TypeScript 6.** Linting TypeScript with ESLint means `typescript-eslint`, which
88
- reads the compiler API directly rather than through a stable interface, so its peer range is
89
- `typescript >=4.8.4 <6.1.0` — below the TypeScript rshono is built and tested against. An app that chooses
90
- ESLint therefore gets `typescript ~6.0.3`, the newest that range allows: `npm install` would otherwise fail
91
- outright on the conflict, and forcing past it hands you a linter running against a compiler API it was never
92
- built for. The framework's declarations compile identically under either version, which is what makes this
93
- the app's pin and not the framework's — every other preset leaves TypeScript alone. What you trade for
94
- type-aware rules is a compiler one major behind, and the JavaScript implementation rather than the native
95
- one, so `typecheck` on a large app is several times slower. When upstream widens the range, the pin in
96
- `features/quality.ts` is the only thing to delete.
97
-
98
- **Tailwind is four packages, a `postcss.config.mjs` and one rule in `rshono.config.ts`.** rshono compiles
99
- CSS natively and has no PostCSS in it — that is deliberate, and it means an app that wants a plugin chain
100
- brings its own, through the `rspack` hook. The overlay writes all of it, with a comment saying what to
101
- delete to go back to plain CSS.
102
-
103
132
  ## Development
104
133
 
105
134
  ```bash
106
135
  pnpm --filter @rshono/create build # codegen, then one bundled dist/cli.mjs with no runtime deps
107
- pnpm --filter @rshono/create test # the plan matrix — fast, no I/O
136
+ pnpm --filter @rshono/create test # builds, then the plan matrix and the CLI seconds, no installs
108
137
  CREATE_RSHONO_E2E=1 pnpm --filter @rshono/create test # also: pack, install and build real apps
109
138
  ```
110
139
 
111
- `@clack/prompts` (MIT) is bundled rather than depended on, so `npm create` downloads one tarball before it
112
- can ask its first question.
140
+ `plan.test.mjs` is the fast one the whole matrix of answers in memory, no directory touched.
141
+ `cli.test.mjs` spawns the real bin against temp directories, which is where argument parsing and the refusal
142
+ to overwrite somebody's files are checked. `e2e.test.mjs` is the opt-in one, and the only one that installs
143
+ anything.
144
+
145
+ `src/generated/framework.ts` — the rshono version, the Node range, the dependency pins and the deploy target
146
+ list — is written by `scripts/codegen.mjs` from `packages/core`, so `pnpm --filter @rshono/create codegen` is
147
+ what picks up a change there.
148
+
149
+ `@clack/prompts` (MIT) is bundled rather than depended on, so `npx @rshono/create` downloads one tarball
150
+ before it can ask its first question.
@@ -3,7 +3,8 @@
3
3
  // parse and run on whatever Node the user happens to have. The CLI itself is a bundle — its imports
4
4
  // are evaluated before any statement in it, so a version check *inside* it would be too late to
5
5
  // produce anything friendlier than a stack trace.
6
- var MINIMUM = [22, 1, 0];
6
+ // Kept in step with `engines.node` in @rshono/core's manifest, which is what a scaffolded app pins.
7
+ var MINIMUM = [22, 18, 0];
7
8
 
8
9
  var current = process.versions.node.split('.').map(Number);
9
10
  var older = false;
@@ -20,8 +21,9 @@ if (older) {
20
21
  ' or newer — you are on ' +
21
22
  process.versions.node +
22
23
  '.\n' +
23
- 'rshono itself requires it too (worker threads, process.loadEnvFile, Promise.withResolvers),\n' +
24
- 'so scaffolding on this version would produce an app that cannot start.\n',
24
+ 'rshono itself requires it (native TypeScript stripping loads rshono.config.ts, and the dev\n' +
25
+ 'server needs process.loadEnvFile and Promise.withResolvers), so scaffolding on this version\n' +
26
+ 'would produce an app that cannot start.\n',
25
27
  );
26
28
  process.exit(1);
27
29
  }