@rshono/create 1.0.0-rc.2 → 1.0.0-rc.21
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/LICENSE +21 -0
- package/README.md +94 -61
- package/bin/create-rshono.mjs +9 -7
- package/dist/api.mjs +297 -254
- package/dist/cli.mjs +588 -518
- package/package.json +12 -13
- package/templates/base/AGENTS.md +5 -0
- package/templates/base/CLAUDE.md +1 -0
- package/templates/base/README.md +11 -9
- package/templates/base/_env +1 -4
- package/templates/base/_gitignore +1 -0
- package/templates/base/public/favicon.svg +2 -1
- package/templates/base/rshono.config.ts +0 -30
- 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 -16
- package/templates/oxfmt/_oxfmtrc.json +1 -1
- package/templates/tailwind/postcss.config.mjs +0 -4
- package/templates/tailwind/rshono.config.ts +1 -37
- 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 -22
- package/templates/base/src/components/greet-form.tsx +0 -27
- package/templates/base/src/lib/env.ts +0 -26
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lasse Tange
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,66 +1,113 @@
|
|
|
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\|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
|
|
30
|
-
the
|
|
31
|
-
`--
|
|
32
|
-
given. **A non-interactive terminal implies `-y`**,
|
|
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, 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
|
|
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
|
|
54
67
|
pnpm-workspace.yaml pnpm only: which dependency install scripts this app runs (none of them)
|
|
55
68
|
```
|
|
56
69
|
|
|
57
|
-
|
|
58
|
-
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.
|
|
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,37 +116,19 @@ 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
|
-
|
|
74
|
-
|
|
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
|
-
|
|
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
|
|
@@ -109,9 +138,13 @@ CREATE_RSHONO_E2E=1 pnpm --filter @rshono/create test # also: pack, install an
|
|
|
109
138
|
```
|
|
110
139
|
|
|
111
140
|
`plan.test.mjs` is the fast one — the whole matrix of answers in memory, no directory touched.
|
|
112
|
-
`cli.test.mjs` spawns the real bin against temp directories, which is where argument parsing and the
|
|
113
|
-
|
|
114
|
-
|
|
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.
|
|
115
148
|
|
|
116
|
-
`@clack/prompts` (MIT) is bundled rather than depended on, so `
|
|
117
|
-
can ask its first question.
|
|
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.
|
package/bin/create-rshono.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Thin launcher,
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
2
|
+
// Thin launcher, deliberately old-syntax and dependency-free: it is the one file that has to parse and run on
|
|
3
|
+
// whatever Node the user happens to have. A version check inside the CLI bundle would be too late — its imports
|
|
4
|
+
// evaluate before any statement in it.
|
|
5
|
+
//
|
|
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
|
}
|