create-oven 0.3.1 → 0.5.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.
- package/index.js +58 -141
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -88,14 +88,14 @@ async function main() {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
if (args.includes('--version') || args.includes('-v')) {
|
|
91
|
-
console.log('create-oven v0.
|
|
91
|
+
console.log('create-oven v0.5.0');
|
|
92
92
|
process.exit(0);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
console.log(`
|
|
96
96
|
${c.bold}${c.cyan} ╔═══════════════════════════════════════╗
|
|
97
97
|
║ ║
|
|
98
|
-
║ 🔥 Create Oven App v0.
|
|
98
|
+
║ 🔥 Create Oven App v0.5.0 ║
|
|
99
99
|
║ ║
|
|
100
100
|
║ Next.js-style framework for Bun ║
|
|
101
101
|
║ ║
|
|
@@ -174,12 +174,14 @@ ${c.bold}${c.cyan} ╔═══════════════════
|
|
|
174
174
|
version: '0.1.0',
|
|
175
175
|
private: true,
|
|
176
176
|
scripts: {
|
|
177
|
-
dev: '
|
|
178
|
-
build: '
|
|
179
|
-
start: '
|
|
177
|
+
dev: 'oven dev',
|
|
178
|
+
build: 'oven build',
|
|
179
|
+
start: 'oven start',
|
|
180
180
|
...(useEslint && { lint: 'eslint .' }),
|
|
181
181
|
},
|
|
182
|
-
dependencies: {
|
|
182
|
+
dependencies: {
|
|
183
|
+
'oven-bun': 'latest',
|
|
184
|
+
},
|
|
183
185
|
devDependencies: {
|
|
184
186
|
...(useTypescript && { '@types/bun': 'latest', 'typescript': '^5' }),
|
|
185
187
|
...(useTailwind && { '@tailwindcss/postcss': '^4', 'tailwindcss': '^4' }),
|
|
@@ -293,7 +295,7 @@ body {
|
|
|
293
295
|
const spin6 = spinner(`Creating app/layout.${ext}...`);
|
|
294
296
|
const layoutContent = useTypescript ? `import "./globals.css";
|
|
295
297
|
|
|
296
|
-
export const metadata
|
|
298
|
+
export const metadata = {
|
|
297
299
|
title: "Create Oven App",
|
|
298
300
|
description: "Generated by create-oven",
|
|
299
301
|
};
|
|
@@ -301,25 +303,24 @@ export const metadata${useTypescript ? ': { title: string; description: string }
|
|
|
301
303
|
export default function RootLayout({
|
|
302
304
|
children,
|
|
303
305
|
}: Readonly<{
|
|
304
|
-
children:
|
|
306
|
+
children: React.ReactNode;
|
|
305
307
|
}>) {
|
|
306
308
|
return (
|
|
307
|
-
\`<!DOCTYPE html>
|
|
308
309
|
<html lang="en">
|
|
309
310
|
<head>
|
|
310
|
-
<meta
|
|
311
|
+
<meta charSet="UTF-8" />
|
|
311
312
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
312
|
-
<title
|
|
313
|
-
<meta name="description" content=
|
|
313
|
+
<title>{metadata.title}</title>
|
|
314
|
+
<meta name="description" content={metadata.description} />
|
|
314
315
|
<link rel="icon" href="/favicon.ico" />
|
|
315
316
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
316
|
-
<link rel="preconnect" href="https://fonts.gstatic.com"
|
|
317
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
|
317
318
|
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono&display=swap" rel="stylesheet" />
|
|
318
319
|
</head>
|
|
319
|
-
<body
|
|
320
|
-
|
|
320
|
+
<body className="antialiased" style={{ fontFamily: "'Geist', sans-serif" }}>
|
|
321
|
+
{children}
|
|
321
322
|
</body>
|
|
322
|
-
</html
|
|
323
|
+
</html>
|
|
323
324
|
);
|
|
324
325
|
}
|
|
325
326
|
` : `import "./globals.css";
|
|
@@ -331,22 +332,21 @@ export const metadata = {
|
|
|
331
332
|
|
|
332
333
|
export default function RootLayout({ children }) {
|
|
333
334
|
return (
|
|
334
|
-
\`<!DOCTYPE html>
|
|
335
335
|
<html lang="en">
|
|
336
336
|
<head>
|
|
337
|
-
<meta
|
|
337
|
+
<meta charSet="UTF-8" />
|
|
338
338
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
339
|
-
<title
|
|
340
|
-
<meta name="description" content=
|
|
339
|
+
<title>{metadata.title}</title>
|
|
340
|
+
<meta name="description" content={metadata.description} />
|
|
341
341
|
<link rel="icon" href="/favicon.ico" />
|
|
342
342
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
343
|
-
<link rel="preconnect" href="https://fonts.gstatic.com"
|
|
343
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
|
344
344
|
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono&display=swap" rel="stylesheet" />
|
|
345
345
|
</head>
|
|
346
|
-
<body
|
|
347
|
-
|
|
346
|
+
<body className="antialiased" style={{ fontFamily: "'Geist', sans-serif" }}>
|
|
347
|
+
{children}
|
|
348
348
|
</body>
|
|
349
|
-
</html
|
|
349
|
+
</html>
|
|
350
350
|
);
|
|
351
351
|
}
|
|
352
352
|
`;
|
|
@@ -357,55 +357,55 @@ export default function RootLayout({ children }) {
|
|
|
357
357
|
const spin7 = spinner(`Creating app/page.${ext}...`);
|
|
358
358
|
const pageContent = useTailwind ? `export default function Home() {
|
|
359
359
|
return (
|
|
360
|
-
|
|
361
|
-
<main
|
|
360
|
+
<div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
|
|
361
|
+
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
|
|
362
362
|
<img
|
|
363
|
-
|
|
363
|
+
className="dark:invert"
|
|
364
364
|
src="/oven.svg"
|
|
365
365
|
alt="Oven logo"
|
|
366
|
-
width=
|
|
367
|
-
height=
|
|
366
|
+
width={100}
|
|
367
|
+
height={24}
|
|
368
368
|
/>
|
|
369
|
-
<div
|
|
370
|
-
<h1
|
|
369
|
+
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
|
|
370
|
+
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
|
|
371
371
|
Get started by editing app/page.${ext}
|
|
372
372
|
</h1>
|
|
373
|
-
<p
|
|
373
|
+
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
|
|
374
374
|
Looking for a starting point? Head over to the{" "}
|
|
375
375
|
<a
|
|
376
376
|
href="https://github.com/oven-ttta/oven-framework"
|
|
377
|
-
|
|
377
|
+
className="font-medium text-zinc-950 dark:text-zinc-50"
|
|
378
378
|
>
|
|
379
379
|
Documentation
|
|
380
380
|
</a>{" "}
|
|
381
381
|
or{" "}
|
|
382
382
|
<a
|
|
383
383
|
href="https://bun.sh/docs"
|
|
384
|
-
|
|
384
|
+
className="font-medium text-zinc-950 dark:text-zinc-50"
|
|
385
385
|
>
|
|
386
386
|
Bun Docs
|
|
387
387
|
</a>.
|
|
388
388
|
</p>
|
|
389
389
|
</div>
|
|
390
|
-
<div
|
|
390
|
+
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
|
|
391
391
|
<a
|
|
392
|
-
|
|
392
|
+
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
|
|
393
393
|
href="https://github.com/oven-ttta/oven-framework"
|
|
394
394
|
target="_blank"
|
|
395
395
|
rel="noopener noreferrer"
|
|
396
|
-
style=
|
|
396
|
+
style={{ background: "#171717", color: "white" }}
|
|
397
397
|
>
|
|
398
398
|
<img
|
|
399
|
-
|
|
399
|
+
className="dark:invert"
|
|
400
400
|
src="/github.svg"
|
|
401
401
|
alt="GitHub"
|
|
402
|
-
width=
|
|
403
|
-
height=
|
|
402
|
+
width={16}
|
|
403
|
+
height={16}
|
|
404
404
|
/>
|
|
405
405
|
GitHub
|
|
406
406
|
</a>
|
|
407
407
|
<a
|
|
408
|
-
|
|
408
|
+
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
|
|
409
409
|
href="https://bun.sh/docs"
|
|
410
410
|
target="_blank"
|
|
411
411
|
rel="noopener noreferrer"
|
|
@@ -414,134 +414,51 @@ export default function RootLayout({ children }) {
|
|
|
414
414
|
</a>
|
|
415
415
|
</div>
|
|
416
416
|
</main>
|
|
417
|
-
</div
|
|
417
|
+
</div>
|
|
418
418
|
);
|
|
419
419
|
}
|
|
420
420
|
` : `export default function Home() {
|
|
421
421
|
return (
|
|
422
|
-
|
|
423
|
-
<main style=
|
|
424
|
-
<div style=
|
|
425
|
-
<div style=
|
|
426
|
-
<h1 style=
|
|
422
|
+
<div style={{ display: "flex", minHeight: "100vh", alignItems: "center", justifyContent: "center", background: "#fafafa" }}>
|
|
423
|
+
<main style={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "space-between", maxWidth: "48rem", padding: "8rem 4rem", background: "white" }}>
|
|
424
|
+
<div style={{ fontSize: "4rem", marginBottom: "2rem" }}>🔥</div>
|
|
425
|
+
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "1.5rem", textAlign: "center" }}>
|
|
426
|
+
<h1 style={{ fontSize: "1.875rem", fontWeight: 600, lineHeight: "2.5rem", color: "black" }}>
|
|
427
427
|
Get started by editing app/page.${ext}
|
|
428
428
|
</h1>
|
|
429
|
-
<p style=
|
|
430
|
-
Looking for a starting point? Head over to the
|
|
431
|
-
<a href="https://github.com/oven-ttta/oven-framework" style=
|
|
432
|
-
or
|
|
433
|
-
<a href="https://bun.sh/docs" style=
|
|
429
|
+
<p style={{ maxWidth: "28rem", fontSize: "1.125rem", lineHeight: "2rem", color: "#666" }}>
|
|
430
|
+
Looking for a starting point? Head over to the{" "}
|
|
431
|
+
<a href="https://github.com/oven-ttta/oven-framework" style={{ fontWeight: 500, color: "black" }}>Documentation</a>
|
|
432
|
+
{" "}or{" "}
|
|
433
|
+
<a href="https://bun.sh/docs" style={{ fontWeight: 500, color: "black" }}>Bun Docs</a>.
|
|
434
434
|
</p>
|
|
435
435
|
</div>
|
|
436
|
-
<div style=
|
|
436
|
+
<div style={{ display: "flex", gap: "1rem", marginTop: "2rem" }}>
|
|
437
437
|
<a
|
|
438
438
|
href="https://github.com/oven-ttta/oven-framework"
|
|
439
439
|
target="_blank"
|
|
440
|
-
|
|
440
|
+
rel="noopener noreferrer"
|
|
441
|
+
style={{ display: "flex", height: "3rem", alignItems: "center", justifyContent: "center", gap: "0.5rem", borderRadius: "9999px", background: "black", color: "white", padding: "0 1.5rem", textDecoration: "none" }}
|
|
441
442
|
>
|
|
442
443
|
GitHub
|
|
443
444
|
</a>
|
|
444
445
|
<a
|
|
445
446
|
href="https://bun.sh/docs"
|
|
446
447
|
target="_blank"
|
|
447
|
-
|
|
448
|
+
rel="noopener noreferrer"
|
|
449
|
+
style={{ display: "flex", height: "3rem", alignItems: "center", justifyContent: "center", borderRadius: "9999px", border: "1px solid #e5e5e5", padding: "0 1.5rem", textDecoration: "none", color: "inherit" }}
|
|
448
450
|
>
|
|
449
451
|
Bun Docs
|
|
450
452
|
</a>
|
|
451
453
|
</div>
|
|
452
454
|
</main>
|
|
453
|
-
</div
|
|
455
|
+
</div>
|
|
454
456
|
);
|
|
455
457
|
}
|
|
456
458
|
`;
|
|
457
459
|
fs.writeFileSync(path.join(projectDir, 'app', `page.${ext}`), pageContent);
|
|
458
460
|
spin7.stop(`Created app/page.${ext}`);
|
|
459
461
|
|
|
460
|
-
// ============ server.tsx ============
|
|
461
|
-
const spin8 = spinner(`Creating server.${ext}...`);
|
|
462
|
-
const serverContent = `/**
|
|
463
|
-
* Oven Server
|
|
464
|
-
* Powered by Bun
|
|
465
|
-
*/
|
|
466
|
-
|
|
467
|
-
const PORT = parseInt(process.env.PORT || "3000");
|
|
468
|
-
|
|
469
|
-
// Simple router
|
|
470
|
-
const routes = new Map${useTypescript ? '<string, (req: Request) => Promise<Response>>' : ''}();
|
|
471
|
-
|
|
472
|
-
async function scanRoutes() {
|
|
473
|
-
const appDir = "./app";
|
|
474
|
-
|
|
475
|
-
// Scan for page files
|
|
476
|
-
const glob = new Bun.Glob("**/page.{tsx,jsx,ts,js}");
|
|
477
|
-
|
|
478
|
-
for await (const file of glob.scan({ cwd: appDir })) {
|
|
479
|
-
const routePath = "/" + file
|
|
480
|
-
.replace(/\\/page\\.(tsx|jsx|ts|js)$/, "")
|
|
481
|
-
.replace(/^page\\.(tsx|jsx|ts|js)$/, "")
|
|
482
|
-
.replace(/\\/$/, "") || "/";
|
|
483
|
-
|
|
484
|
-
routes.set(routePath === "" ? "/" : routePath, async (req${useTypescript ? ': Request' : ''}) => {
|
|
485
|
-
const module = await import(\`\${appDir}/\${file}\`);
|
|
486
|
-
const content = await module.default();
|
|
487
|
-
|
|
488
|
-
// Wrap with layout
|
|
489
|
-
let html = content;
|
|
490
|
-
try {
|
|
491
|
-
const layout = await import(\`\${appDir}/layout.tsx\`);
|
|
492
|
-
html = await layout.default({ children: content });
|
|
493
|
-
} catch {}
|
|
494
|
-
|
|
495
|
-
return new Response(html, {
|
|
496
|
-
headers: { "Content-Type": "text/html; charset=utf-8" },
|
|
497
|
-
});
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
async function main() {
|
|
503
|
-
await scanRoutes();
|
|
504
|
-
|
|
505
|
-
Bun.serve({
|
|
506
|
-
port: PORT,
|
|
507
|
-
async fetch(req${useTypescript ? ': Request' : ''}) {
|
|
508
|
-
const url = new URL(req.url);
|
|
509
|
-
let pathname = url.pathname;
|
|
510
|
-
|
|
511
|
-
if (pathname !== "/" && pathname.endsWith("/")) {
|
|
512
|
-
pathname = pathname.slice(0, -1);
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
// Check routes
|
|
516
|
-
const handler = routes.get(pathname);
|
|
517
|
-
if (handler) {
|
|
518
|
-
return handler(req);
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// Static files
|
|
522
|
-
const publicPath = "./public" + pathname;
|
|
523
|
-
const file = Bun.file(publicPath);
|
|
524
|
-
if (await file.exists()) {
|
|
525
|
-
return new Response(file);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
return new Response("Not Found", { status: 404 });
|
|
529
|
-
},
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
console.log(\`
|
|
533
|
-
${c.green}▲${c.reset} Ready in \${Date.now() - start}ms
|
|
534
|
-
|
|
535
|
-
${c.dim}➜${c.reset} Local: ${c.cyan}http://localhost:\${PORT}${c.reset}
|
|
536
|
-
\`);
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
const start = Date.now();
|
|
540
|
-
main();
|
|
541
|
-
`;
|
|
542
|
-
fs.writeFileSync(path.join(projectDir, `server.${ext}`), serverContent);
|
|
543
|
-
spin8.stop(`Created server.${ext}`);
|
|
544
|
-
|
|
545
462
|
// ============ .gitignore ============
|
|
546
463
|
const spin9 = spinner('Creating .gitignore...');
|
|
547
464
|
fs.writeFileSync(path.join(projectDir, '.gitignore'), `# Dependencies
|