create-rsc-kit 0.7.2 → 0.9.0

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.
Files changed (2) hide show
  1. package/dist/templates.js +87 -15
  2. package/package.json +1 -1
package/dist/templates.js CHANGED
@@ -63,16 +63,34 @@ export function scripts(o) {
63
63
  return {
64
64
  dev: 'vite',
65
65
  build: 'vite build',
66
+ // The two that produce something you ship build first, rather than reading
67
+ // whatever .output happens to hold. Run on a project that has never been
68
+ // built, they failed with `ENOENT opening root directory ".output/server"`
69
+ // — a path the app did not write and has no reason to recognise. Run on one
70
+ // built a while ago, which is worse, they silently packaged the old code.
71
+ //
72
+ // start and preview are left alone: they are the inner loop, they follow a
73
+ // build in every set of instructions, and re-running one on each restart
74
+ // costs more than it saves.
66
75
  ...(o.host === 'worker'
67
- ? { preview: 'wrangler dev .output/server/index.mjs', deploy: 'nitro deploy --prebuilt' }
76
+ ? {
77
+ preview: 'wrangler dev .output/server/index.mjs',
78
+ deploy: 'vite build && nitro deploy --prebuilt',
79
+ }
68
80
  : {
69
81
  start: `${o.host === 'node' ? 'node' : 'bun'} .output/server/index.mjs`,
70
82
  // Bun only, and only because serveStatic: 'inline' is set in the vite
71
83
  // config. Without that the binary compiles, serves pages, and 404s
72
84
  // every asset — the static path resolves into Bun's virtual
73
85
  // filesystem, where the files on disk are not.
86
+ //
87
+ // Into dist/, which is already ignored. Named after the project it
88
+ // landed a 63MB binary in the root of, next to the source, with
89
+ // nothing in .gitignore covering it.
74
90
  ...(o.host === 'bun'
75
- ? { compile: `bun build --compile .output/server/index.mjs --outfile ${o.name}` }
91
+ ? {
92
+ compile: 'vite build && bun build --compile .output/server/index.mjs --outfile dist/app',
93
+ }
76
94
  : {}),
77
95
  }),
78
96
  typecheck: 'tsc --noEmit',
@@ -178,7 +196,11 @@ export function viteConfig(o) {
178
196
  //
179
197
  // Not optional, and not a flag on rscKit() either — the plugin builds for
180
198
  // Nitro and nothing else, so a config without this line has no server.
181
- plugins.push(`nitro({ preset: ${JSON.stringify(preset(o.host))}, serveStatic: 'inline' })`);
199
+ // serverDir is what makes server/api and server/routes exist at all: Nitro's
200
+ // scanDirs is empty without it, so a handler written there is never scanned,
201
+ // the request falls through to the rsc entry, and the 404 it answers with
202
+ // reads as a routing bug in this package rather than a missing option.
203
+ plugins.push(`nitro({ preset: ${JSON.stringify(preset(o.host))}, serveStatic: 'inline', serverDir: 'server' })`);
182
204
  plugins.push(`rscKit({
183
205
  ${options.join(',\n ')},
184
206
  })`);
@@ -187,12 +209,22 @@ export function viteConfig(o) {
187
209
  plugins.push('babel({ presets: [reactCompilerPreset()] })');
188
210
  if (o.tailwind)
189
211
  plugins.push('tailwindcss()');
212
+ // `@/` for the source directory. Vite does not read tsconfig `paths`, so the
213
+ // alias has to exist here as well or the import type-checks and then fails to
214
+ // resolve — and the tsconfig half is what tools like shadcn look for when
215
+ // they ask whether this project has an import alias at all.
190
216
  return `${imports.join('\n')}
217
+ import { fileURLToPath } from 'node:url'
191
218
 
192
219
  export default defineConfig({
193
220
  plugins: [
194
221
  ${plugins.join(',\n ')},
195
222
  ],
223
+ resolve: {
224
+ alias: {
225
+ '@': fileURLToPath(new URL('./${o.sourceDir}', import.meta.url)),
226
+ },
227
+ },
196
228
  })
197
229
  `;
198
230
  }
@@ -202,6 +234,16 @@ export const tsconfig = (o) => JSON.stringify({
202
234
  target: 'ESNext',
203
235
  module: 'ESNext',
204
236
  moduleResolution: 'bundler',
237
+ // `@/thing` for `<sourceDir>/thing`. Matched by resolve.alias in the
238
+ // vite config, which is what actually resolves it — this half is for
239
+ // the type system, and for the tools that read a tsconfig to find out
240
+ // whether the project has an import alias. shadcn refuses to init
241
+ // without one.
242
+ //
243
+ // No `baseUrl`: TypeScript removed it, and emitting it now is an
244
+ // outright TS5102 on a freshly scaffolded app. Paths resolve relative
245
+ // to this file without it.
246
+ paths: { '@/*': [`./${o.sourceDir}/*`] },
205
247
  jsx: 'react-jsx',
206
248
  strict: true,
207
249
  noEmit: true,
@@ -231,12 +273,17 @@ export const tsconfig = (o) => JSON.stringify({
231
273
  // .rsc-kit holds the generated ambient declarations. Ambient means
232
274
  // inside the project, and `include` is what decides that — leave it out
233
275
  // and typed routes silently fall back to string.
234
- include: [`${o.sourceDir}/**/*`, '.rsc-kit/**/*'],
276
+ //
277
+ // server/ is the same mistake one directory over: an api handler outside
278
+ // the program is not type-checked at all, so one returning the wrong
279
+ // shape builds, deploys and fails at runtime with nothing having said so.
280
+ include: [`${o.sourceDir}/**/*`, 'server/**/*', '.rsc-kit/**/*'],
235
281
  }, null, 2) + '\n';
236
282
  export function layout(o) {
237
283
  return `${o.tailwind ? "import './styles.css'\n" : ''}import type { ReactNode } from 'react'
284
+ import type { Metadata } from '@rsc-kit/core/metadata'
238
285
 
239
- export const metadata = {
286
+ export const metadata: Metadata = {
240
287
  title: { template: '%s · ${o.name}', default: '${o.name}' },
241
288
  }
242
289
 
@@ -260,23 +307,40 @@ export default function RootLayout({ children }: { children: ReactNode }) {
260
307
  export function page(o) {
261
308
  const h1 = o.tailwind ? ' className="text-3xl font-bold"' : '';
262
309
  const p = o.tailwind ? ' className="mt-4 text-slate-600"' : '';
310
+ const code = o.tailwind ? ' className="rounded bg-slate-100 px-1"' : '';
311
+ // Deliberately nothing that changes between renders.
312
+ //
313
+ // This page said "Rendered on the server at {new Date()}" — and every route
314
+ // it can is frozen at build time, so that timestamp was the build's and
315
+ // never moved again. Reload and the same instant is still there, under a
316
+ // sentence claiming it was rendered just now. The first thing the starter
317
+ // did was look broken, and the fix someone reaches for is to stop
318
+ // prerendering the page that is teaching them about prerendering.
263
319
  return `import { Counter } from '../components/Counter'
320
+ import type { Metadata } from '@rsc-kit/core/metadata'
264
321
 
265
- export const metadata = { title: 'Home' }
266
-
267
- // A server component: async, runs only on the server, ships no JavaScript.
268
- export default async function HomePage() {
269
- const now = new Date().toISOString()
322
+ export const metadata: Metadata = { title: 'Home' }
270
323
 
324
+ // A server component. It runs on the server and ships no JavaScript of its
325
+ // own — this file is not in the browser bundle. It can be \`async\` and await
326
+ // whatever it needs; nothing here does yet.
327
+ export default function HomePage() {
271
328
  return (
272
329
  <>
273
330
  <h1${h1}>${o.name}</h1>
274
331
  <p${p}>
275
- Rendered on the server at {now}. The only JavaScript on this page is the
276
- counter below.
332
+ The only JavaScript on this page is the counter below, because
333
+ <code${code}>Counter.tsx</code> is the only file that opts into the
334
+ client. Everything else rendered on the server and stayed there.
277
335
  </p>
278
336
 
279
337
  <Counter />
338
+
339
+ <p${p}>
340
+ Edit <code${code}>src/app/page.tsx</code> and the change arrives without
341
+ a reload. Add <code${code}>src/app/about/page.tsx</code> and{' '}
342
+ <code${code}>/about</code> exists — there is no route table to update.
343
+ </p>
280
344
  </>
281
345
  )
282
346
  }
@@ -384,9 +448,17 @@ export function readme(o) {
384
448
  ? `${pm} preview # wrangler dev, on workerd\n${pm} deploy # nitro deploy --prebuilt`
385
449
  : `${pm} start # serve on http://localhost:${PORT}`;
386
450
  const compile = o.host === 'bun'
387
- ? `\n\n\`${pm} compile\` puts the whole application in one file — engine, pages and
388
- assets — with Bun's runtime inside it. Frozen pages stay outside: a binary
389
- has no filesystem to read them from, so it renders those live.`
451
+ ? `\n\n\`${pm} compile\` builds and then puts the whole application into
452
+ \`dist/app\` — engine, pages and assets, with Bun's runtime inside it. Run it
453
+ directly:
454
+
455
+ \`\`\`sh
456
+ ./dist/app
457
+ \`\`\`
458
+
459
+ It builds first, so the binary is never a version behind your source. Frozen
460
+ pages stay outside it: a binary has no filesystem to read them from, so it
461
+ renders those live.`
390
462
  : '';
391
463
  return `# ${o.name}
392
464
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-rsc-kit",
3
- "version": "0.7.2",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "description": "Scaffold an RSC app on Bun, Hono, Elysia or Node.",
6
6
  "bin": {