@rshono/create 1.0.0-rc.0 → 1.0.0-rc.10
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 +83 -53
- package/bin/create-rshono.mjs +5 -3
- package/dist/api.mjs +181 -105
- package/dist/cli.mjs +250 -197
- package/package.json +11 -12
- package/templates/base/AGENTS.md +5 -0
- package/templates/base/CLAUDE.md +1 -0
- package/templates/base/README.md +6 -10
- package/templates/base/_env +2 -5
- package/templates/base/public/favicon.svg +2 -1
- package/templates/base/rshono.config.ts +1 -31
- package/templates/base/src/components/404.tsx +0 -1
- package/templates/base/src/components/500.tsx +0 -6
- package/templates/base/src/components/home.tsx +6 -23
- package/templates/base/src/components/layout.tsx +4 -11
- package/templates/base/src/routes.ts +1 -26
- package/templates/base/src/server.ts +20 -35
- package/templates/base/src/styles.css +1 -64
- package/templates/biome/biome.json +2 -1
- package/templates/biome-tailwind/biome.json +1 -1
- package/templates/eslint/eslint.config.mjs +16 -0
- package/templates/oxfmt/_oxfmtrc.json +1 -1
- package/templates/oxlint/_oxlintrc.json +1 -1
- package/templates/prettier/_prettierignore +6 -1
- package/templates/tailwind/postcss.config.mjs +0 -4
- package/templates/tailwind/rshono.config.ts +2 -38
- package/templates/tailwind/src/components/home.tsx +6 -23
- package/templates/tailwind/src/components/layout.tsx +4 -11
- package/templates/tailwind/src/styles.css +0 -25
- package/templates/base/src/actions.ts +0 -19
- package/templates/base/src/components/greet-form.tsx +0 -27
- package/templates/base/src/lib/env.ts +0 -26
package/README.md
CHANGED
|
@@ -1,65 +1,98 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7
|
-
|
|
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`,
|
|
13
|
-
for the install, written into `packageManager` for Corepack,
|
|
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` |
|
|
24
|
-
| Styling | plain CSS | `--tailwind` / `--no-tailwind`
|
|
25
|
-
| Formatting & linting | Prettier + oxlint | `--quality prettier-oxlint\|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
|
|
30
|
-
|
|
31
|
-
to
|
|
32
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
54
|
+
package.json scripts, and the exact dependency versions 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
|
|
49
|
-
src/server.ts
|
|
50
|
-
src/
|
|
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
|
|
67
|
+
pnpm-workspace.yaml pnpm only: which dependency install scripts this app runs (none of them)
|
|
54
68
|
```
|
|
55
69
|
|
|
56
|
-
|
|
57
|
-
project passes its own `format:check`
|
|
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.
|
|
58
73
|
|
|
59
74
|
`react` and `react-dom` are pinned **exactly**, at the versions the framework is tested against, and those
|
|
60
75
|
pins are generated from rshono's own manifest. That is not tidiness: the RSC runtime reaches into React's
|
|
61
76
|
internals, and an app installed with npm or bun has no workspace overrides to keep a single copy of it.
|
|
62
77
|
|
|
78
|
+
## Two things worth knowing
|
|
79
|
+
|
|
80
|
+
**The ESLint preset pins TypeScript 6.** Linting TypeScript with ESLint means `typescript-eslint`, which reads
|
|
81
|
+
the compiler API directly rather than through a stable interface, so its peer range is
|
|
82
|
+
`typescript >=4.8.4 <6.1.0` — below the TypeScript rshono is built and tested against. An app that chooses
|
|
83
|
+
ESLint therefore gets `typescript ~6.0.3`, the newest that range allows: `npm install` would otherwise fail
|
|
84
|
+
outright on the conflict, and forcing past it hands you a linter running against a compiler API it was never
|
|
85
|
+
built for. The framework's declarations compile identically under either version, which is what makes this the
|
|
86
|
+
app's pin and not the framework's — every other preset leaves TypeScript alone. What you trade for type-aware
|
|
87
|
+
rules is a compiler one major behind, and the JavaScript implementation rather than the native one, so
|
|
88
|
+
`typecheck` on a large app is several times slower. When upstream widens the range, the pin in
|
|
89
|
+
`features/quality.ts` is the only thing to delete.
|
|
90
|
+
|
|
91
|
+
**Tailwind is four packages, a `postcss.config.mjs` and one rule in `rshono.config.ts`.** rshono compiles CSS
|
|
92
|
+
natively and has no PostCSS in it — that is deliberate, and it means an app that wants a plugin chain brings
|
|
93
|
+
its own, through the `rspack` hook. The overlay writes all of it, with a comment saying what to delete to go
|
|
94
|
+
back to plain CSS.
|
|
95
|
+
|
|
63
96
|
## Adding an option
|
|
64
97
|
|
|
65
98
|
Every difference between two scaffolds is a `Feature` — files to overlay, dependencies, scripts,
|
|
@@ -68,38 +101,35 @@ edits and no new machinery:
|
|
|
68
101
|
|
|
69
102
|
1. A `Feature` in `src/features/` — `templates/<id>` for the files it brings, plus whatever it adds to the
|
|
70
103
|
manifest.
|
|
71
|
-
2. The template directory itself, as **real files**. They are copied over the base, so an overlay replaces
|
|
72
|
-
|
|
73
|
-
|
|
104
|
+
2. The template directory itself, as **real files**. They are copied over the base, so an overlay replaces a
|
|
105
|
+
file rather than patching it, and template files stay valid TypeScript that an editor can check. `_name`
|
|
106
|
+
becomes `.name` on write, because npm strips a literal `.gitignore` out of a published tarball.
|
|
74
107
|
3. A prompt in `src/cli.ts`, if it deserves a question of its own — and a flag, which it always does.
|
|
75
108
|
|
|
76
|
-
`plan(answers)` is pure: answers in, a `Map` of path → contents out, no directory touched. That is what
|
|
77
|
-
makes the whole matrix of options testable in milliseconds (`test/plan.test.mjs`) and `--dry-run` free. It
|
|
78
|
-
|
|
109
|
+
`plan(answers, pm)` is pure: answers in, a `Map` of path → contents out, no directory touched. That is what
|
|
110
|
+
makes the whole matrix of options testable in milliseconds (`test/plan.test.mjs`) and `--dry-run` free. It is
|
|
111
|
+
also exported, for a tool that wants to scaffold without the prompts:
|
|
79
112
|
|
|
80
113
|
```ts
|
|
81
114
|
import { plan, writePlan } from '@rshono/create';
|
|
82
115
|
```
|
|
83
116
|
|
|
84
|
-
## Two things worth knowing
|
|
85
|
-
|
|
86
|
-
**There is no ESLint option.** Linting TypeScript with ESLint means `typescript-eslint`, whose peer range is
|
|
87
|
-
`typescript >=4.8.4 <6.1.0`; rshono is built and tested against TypeScript 7. `npm install` fails outright
|
|
88
|
-
on the conflict, and forcing past it would hand you a linter running against a compiler API it was never
|
|
89
|
-
built for. When upstream widens the range, ESLint becomes one more entry in `features/quality.ts`.
|
|
90
|
-
|
|
91
|
-
**Tailwind is four packages, a `postcss.config.mjs` and one rule in `rshono.config.ts`.** rshono compiles
|
|
92
|
-
CSS natively and has no PostCSS in it — that is deliberate, and it means an app that wants a plugin chain
|
|
93
|
-
brings its own, through the `rspack` hook. The overlay writes all of it, with a comment saying what to
|
|
94
|
-
delete to go back to plain CSS.
|
|
95
|
-
|
|
96
117
|
## Development
|
|
97
118
|
|
|
98
119
|
```bash
|
|
99
120
|
pnpm --filter @rshono/create build # codegen, then one bundled dist/cli.mjs with no runtime deps
|
|
100
|
-
pnpm --filter @rshono/create test # the plan matrix —
|
|
121
|
+
pnpm --filter @rshono/create test # builds, then the plan matrix and the CLI — seconds, no installs
|
|
101
122
|
CREATE_RSHONO_E2E=1 pnpm --filter @rshono/create test # also: pack, install and build real apps
|
|
102
123
|
```
|
|
103
124
|
|
|
104
|
-
|
|
105
|
-
|
|
125
|
+
`plan.test.mjs` is the fast one — the whole matrix of answers in memory, no directory touched.
|
|
126
|
+
`cli.test.mjs` spawns the real bin against temp directories, which is where argument parsing and the refusal
|
|
127
|
+
to overwrite somebody's files are checked. `e2e.test.mjs` is the opt-in one, and the only one that installs
|
|
128
|
+
anything.
|
|
129
|
+
|
|
130
|
+
`src/generated/framework.ts` — the rshono version, the Node range, the dependency pins and the deploy target
|
|
131
|
+
list — is written by `scripts/codegen.mjs` from `packages/core`, so `pnpm --filter @rshono/create codegen` is
|
|
132
|
+
what picks up a change there.
|
|
133
|
+
|
|
134
|
+
`@clack/prompts` (MIT) is bundled rather than depended on, so `npx @rshono/create` downloads one tarball
|
|
135
|
+
before it can ask its first question.
|
package/bin/create-rshono.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
|
24
|
-
'so scaffolding on this version
|
|
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
|
}
|