create-oven 0.3.0 → 0.4.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 +125 -130
- 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.4.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.4.0 ║
|
|
99
99
|
║ ║
|
|
100
100
|
║ Next.js-style framework for Bun ║
|
|
101
101
|
║ ║
|
|
@@ -157,6 +157,16 @@ ${c.bold}${c.cyan} ╔═══════════════════
|
|
|
157
157
|
fs.mkdirSync(path.join(projectDir, 'app'), { recursive: true });
|
|
158
158
|
fs.mkdirSync(path.join(projectDir, 'public'), { recursive: true });
|
|
159
159
|
|
|
160
|
+
// ============ public/oven.svg ============
|
|
161
|
+
fs.writeFileSync(path.join(projectDir, 'public', 'oven.svg'), `<svg width="100" height="24" viewBox="0 0 100 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
162
|
+
<text x="0" y="20" font-family="system-ui, sans-serif" font-size="20" font-weight="bold" fill="currentColor">🔥 Oven</text>
|
|
163
|
+
</svg>`);
|
|
164
|
+
|
|
165
|
+
// ============ public/github.svg ============
|
|
166
|
+
fs.writeFileSync(path.join(projectDir, 'public', 'github.svg'), `<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
|
167
|
+
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
|
|
168
|
+
</svg>`);
|
|
169
|
+
|
|
160
170
|
// ============ package.json ============
|
|
161
171
|
const spin1 = spinner('Creating package.json...');
|
|
162
172
|
const pkg = {
|
|
@@ -164,12 +174,14 @@ ${c.bold}${c.cyan} ╔═══════════════════
|
|
|
164
174
|
version: '0.1.0',
|
|
165
175
|
private: true,
|
|
166
176
|
scripts: {
|
|
167
|
-
dev: '
|
|
168
|
-
build: '
|
|
169
|
-
start: '
|
|
177
|
+
dev: 'oven dev',
|
|
178
|
+
build: 'oven build',
|
|
179
|
+
start: 'oven start',
|
|
170
180
|
...(useEslint && { lint: 'eslint .' }),
|
|
171
181
|
},
|
|
172
|
-
dependencies: {
|
|
182
|
+
dependencies: {
|
|
183
|
+
'oven-bun': 'latest',
|
|
184
|
+
},
|
|
173
185
|
devDependencies: {
|
|
174
186
|
...(useTypescript && { '@types/bun': 'latest', 'typescript': '^5' }),
|
|
175
187
|
...(useTailwind && { '@tailwindcss/postcss': '^4', 'tailwindcss': '^4' }),
|
|
@@ -283,31 +295,34 @@ body {
|
|
|
283
295
|
const spin6 = spinner(`Creating app/layout.${ext}...`);
|
|
284
296
|
const layoutContent = useTypescript ? `import "./globals.css";
|
|
285
297
|
|
|
286
|
-
export const metadata = {
|
|
298
|
+
export const metadata${useTypescript ? ': { title: string; description: string }' : ''} = {
|
|
287
299
|
title: "Create Oven App",
|
|
288
300
|
description: "Generated by create-oven",
|
|
289
301
|
};
|
|
290
302
|
|
|
291
303
|
export default function RootLayout({
|
|
292
304
|
children,
|
|
293
|
-
}: {
|
|
305
|
+
}: Readonly<{
|
|
294
306
|
children: string;
|
|
295
|
-
}) {
|
|
296
|
-
return
|
|
297
|
-
|
|
307
|
+
}>) {
|
|
308
|
+
return (
|
|
309
|
+
\`<!DOCTYPE html>
|
|
298
310
|
<html lang="en">
|
|
299
311
|
<head>
|
|
300
|
-
<meta charset="UTF-8"
|
|
301
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0"
|
|
312
|
+
<meta charset="UTF-8" />
|
|
313
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
302
314
|
<title>\${metadata.title}</title>
|
|
303
|
-
<meta name="description" content="\${metadata.description}"
|
|
304
|
-
<link rel="icon" href="/favicon.ico"
|
|
315
|
+
<meta name="description" content="\${metadata.description}" />
|
|
316
|
+
<link rel="icon" href="/favicon.ico" />
|
|
317
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
318
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
319
|
+
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono&display=swap" rel="stylesheet" />
|
|
305
320
|
</head>
|
|
306
|
-
<body>
|
|
321
|
+
<body class="antialiased" style="font-family: 'Geist', sans-serif;">
|
|
307
322
|
\${children}
|
|
308
323
|
</body>
|
|
309
|
-
</html
|
|
310
|
-
|
|
324
|
+
</html>\`
|
|
325
|
+
);
|
|
311
326
|
}
|
|
312
327
|
` : `import "./globals.css";
|
|
313
328
|
|
|
@@ -317,21 +332,24 @@ export const metadata = {
|
|
|
317
332
|
};
|
|
318
333
|
|
|
319
334
|
export default function RootLayout({ children }) {
|
|
320
|
-
return
|
|
321
|
-
|
|
335
|
+
return (
|
|
336
|
+
\`<!DOCTYPE html>
|
|
322
337
|
<html lang="en">
|
|
323
338
|
<head>
|
|
324
|
-
<meta charset="UTF-8"
|
|
325
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0"
|
|
339
|
+
<meta charset="UTF-8" />
|
|
340
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
326
341
|
<title>\${metadata.title}</title>
|
|
327
|
-
<meta name="description" content="\${metadata.description}"
|
|
328
|
-
<link rel="icon" href="/favicon.ico"
|
|
342
|
+
<meta name="description" content="\${metadata.description}" />
|
|
343
|
+
<link rel="icon" href="/favicon.ico" />
|
|
344
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
345
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
346
|
+
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono&display=swap" rel="stylesheet" />
|
|
329
347
|
</head>
|
|
330
|
-
<body>
|
|
348
|
+
<body class="antialiased" style="font-family: 'Geist', sans-serif;">
|
|
331
349
|
\${children}
|
|
332
350
|
</body>
|
|
333
|
-
</html
|
|
334
|
-
|
|
351
|
+
</html>\`
|
|
352
|
+
);
|
|
335
353
|
}
|
|
336
354
|
`;
|
|
337
355
|
fs.writeFileSync(path.join(projectDir, 'app', `layout.${ext}`), layoutContent);
|
|
@@ -339,131 +357,108 @@ export default function RootLayout({ children }) {
|
|
|
339
357
|
|
|
340
358
|
// ============ app/page.tsx ============
|
|
341
359
|
const spin7 = spinner(`Creating app/page.${ext}...`);
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
360
|
+
const pageContent = useTailwind ? `export default function Home() {
|
|
361
|
+
return (
|
|
362
|
+
\`<div class="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
|
|
363
|
+
<main class="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">
|
|
364
|
+
<img
|
|
365
|
+
class="dark:invert"
|
|
366
|
+
src="/oven.svg"
|
|
367
|
+
alt="Oven logo"
|
|
368
|
+
width="100"
|
|
369
|
+
height="24"
|
|
370
|
+
/>
|
|
371
|
+
<div class="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
|
|
372
|
+
<h1 class="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
|
|
373
|
+
Get started by editing app/page.${ext}
|
|
352
374
|
</h1>
|
|
353
|
-
<p
|
|
354
|
-
|
|
375
|
+
<p class="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
|
|
376
|
+
Looking for a starting point? Head over to the{" "}
|
|
377
|
+
<a
|
|
378
|
+
href="https://github.com/oven-ttta/oven-framework"
|
|
379
|
+
class="font-medium text-zinc-950 dark:text-zinc-50"
|
|
380
|
+
>
|
|
381
|
+
Documentation
|
|
382
|
+
</a>{" "}
|
|
383
|
+
or{" "}
|
|
384
|
+
<a
|
|
385
|
+
href="https://bun.sh/docs"
|
|
386
|
+
class="font-medium text-zinc-950 dark:text-zinc-50"
|
|
387
|
+
>
|
|
388
|
+
Bun Docs
|
|
389
|
+
</a>.
|
|
355
390
|
</p>
|
|
356
391
|
</div>
|
|
357
|
-
|
|
358
|
-
|
|
392
|
+
<div class="flex flex-col gap-4 text-base font-medium sm:flex-row">
|
|
393
|
+
<a
|
|
394
|
+
class="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]"
|
|
395
|
+
href="https://github.com/oven-ttta/oven-framework"
|
|
396
|
+
target="_blank"
|
|
397
|
+
rel="noopener noreferrer"
|
|
398
|
+
style="background: #171717; color: white;"
|
|
399
|
+
>
|
|
400
|
+
<img
|
|
401
|
+
class="dark:invert"
|
|
402
|
+
src="/github.svg"
|
|
403
|
+
alt="GitHub"
|
|
404
|
+
width="16"
|
|
405
|
+
height="16"
|
|
406
|
+
/>
|
|
407
|
+
GitHub
|
|
408
|
+
</a>
|
|
409
|
+
<a
|
|
410
|
+
class="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]"
|
|
411
|
+
href="https://bun.sh/docs"
|
|
412
|
+
target="_blank"
|
|
413
|
+
rel="noopener noreferrer"
|
|
414
|
+
>
|
|
415
|
+
Bun Docs
|
|
416
|
+
</a>
|
|
417
|
+
</div>
|
|
418
|
+
</main>
|
|
419
|
+
</div>\`
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
` : `export default function Home() {
|
|
423
|
+
return (
|
|
424
|
+
\`<div style="display: flex; min-height: 100vh; align-items: center; justify-content: center; background: #fafafa;">
|
|
425
|
+
<main style="display: flex; flex-direction: column; align-items: center; justify-content: space-between; max-width: 48rem; padding: 8rem 4rem; background: white;">
|
|
426
|
+
<div style="font-size: 4rem; margin-bottom: 2rem;">🔥</div>
|
|
427
|
+
<div style="display: flex; flex-direction: column; align-items: center; gap: 1.5rem; text-align: center;">
|
|
428
|
+
<h1 style="font-size: 1.875rem; font-weight: 600; line-height: 2.5rem; color: black;">
|
|
429
|
+
Get started by editing app/page.${ext}
|
|
430
|
+
</h1>
|
|
431
|
+
<p style="max-width: 28rem; font-size: 1.125rem; line-height: 2rem; color: #666;">
|
|
432
|
+
Looking for a starting point? Head over to the
|
|
433
|
+
<a href="https://github.com/oven-ttta/oven-framework" style="font-weight: 500; color: black;">Documentation</a>
|
|
434
|
+
or
|
|
435
|
+
<a href="https://bun.sh/docs" style="font-weight: 500; color: black;">Bun Docs</a>.
|
|
436
|
+
</p>
|
|
437
|
+
</div>
|
|
438
|
+
<div style="display: flex; gap: 1rem; margin-top: 2rem;">
|
|
359
439
|
<a
|
|
360
|
-
${tailwindClasses ? 'class="flex h-12 items-center justify-center gap-2 rounded-full bg-black text-white px-6 hover:bg-zinc-800 transition-colors"' : 'style="display: flex; height: 3rem; align-items: center; justify-content: center; gap: 0.5rem; border-radius: 9999px; background: black; color: white; padding: 0 1.5rem; text-decoration: none;"'}
|
|
361
440
|
href="https://github.com/oven-ttta/oven-framework"
|
|
362
441
|
target="_blank"
|
|
442
|
+
style="display: flex; height: 3rem; align-items: center; justify-content: center; gap: 0.5rem; border-radius: 9999px; background: black; color: white; padding: 0 1.5rem; text-decoration: none;"
|
|
363
443
|
>
|
|
364
444
|
GitHub
|
|
365
445
|
</a>
|
|
366
446
|
<a
|
|
367
|
-
${tailwindClasses ? 'class="flex h-12 items-center justify-center rounded-full border border-zinc-200 dark:border-zinc-700 px-6 hover:bg-zinc-50 dark:hover:bg-zinc-900 transition-colors"' : 'style="display: flex; height: 3rem; align-items: center; justify-content: center; border-radius: 9999px; border: 1px solid #e5e5e5; padding: 0 1.5rem; text-decoration: none; color: inherit;"'}
|
|
368
447
|
href="https://bun.sh/docs"
|
|
369
448
|
target="_blank"
|
|
449
|
+
style="display: flex; height: 3rem; align-items: center; justify-content: center; border-radius: 9999px; border: 1px solid #e5e5e5; padding: 0 1.5rem; text-decoration: none; color: inherit;"
|
|
370
450
|
>
|
|
371
451
|
Bun Docs
|
|
372
452
|
</a>
|
|
373
453
|
</div>
|
|
374
454
|
</main>
|
|
375
|
-
</div
|
|
376
|
-
|
|
455
|
+
</div>\`
|
|
456
|
+
);
|
|
377
457
|
}
|
|
378
458
|
`;
|
|
379
459
|
fs.writeFileSync(path.join(projectDir, 'app', `page.${ext}`), pageContent);
|
|
380
460
|
spin7.stop(`Created app/page.${ext}`);
|
|
381
461
|
|
|
382
|
-
// ============ server.tsx ============
|
|
383
|
-
const spin8 = spinner(`Creating server.${ext}...`);
|
|
384
|
-
const serverContent = `/**
|
|
385
|
-
* Oven Server
|
|
386
|
-
* Powered by Bun
|
|
387
|
-
*/
|
|
388
|
-
|
|
389
|
-
const PORT = parseInt(process.env.PORT || "3000");
|
|
390
|
-
|
|
391
|
-
// Simple router
|
|
392
|
-
const routes = new Map${useTypescript ? '<string, (req: Request) => Promise<Response>>' : ''}();
|
|
393
|
-
|
|
394
|
-
async function scanRoutes() {
|
|
395
|
-
const appDir = "./app";
|
|
396
|
-
|
|
397
|
-
// Scan for page files
|
|
398
|
-
const glob = new Bun.Glob("**/page.{tsx,jsx,ts,js}");
|
|
399
|
-
|
|
400
|
-
for await (const file of glob.scan({ cwd: appDir })) {
|
|
401
|
-
const routePath = "/" + file
|
|
402
|
-
.replace(/\\/page\\.(tsx|jsx|ts|js)$/, "")
|
|
403
|
-
.replace(/^page\\.(tsx|jsx|ts|js)$/, "")
|
|
404
|
-
.replace(/\\/$/, "") || "/";
|
|
405
|
-
|
|
406
|
-
routes.set(routePath === "" ? "/" : routePath, async (req${useTypescript ? ': Request' : ''}) => {
|
|
407
|
-
const module = await import(\`\${appDir}/\${file}\`);
|
|
408
|
-
const content = await module.default();
|
|
409
|
-
|
|
410
|
-
// Wrap with layout
|
|
411
|
-
let html = content;
|
|
412
|
-
try {
|
|
413
|
-
const layout = await import(\`\${appDir}/layout.tsx\`);
|
|
414
|
-
html = await layout.default({ children: content });
|
|
415
|
-
} catch {}
|
|
416
|
-
|
|
417
|
-
return new Response(html, {
|
|
418
|
-
headers: { "Content-Type": "text/html; charset=utf-8" },
|
|
419
|
-
});
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
async function main() {
|
|
425
|
-
await scanRoutes();
|
|
426
|
-
|
|
427
|
-
Bun.serve({
|
|
428
|
-
port: PORT,
|
|
429
|
-
async fetch(req${useTypescript ? ': Request' : ''}) {
|
|
430
|
-
const url = new URL(req.url);
|
|
431
|
-
let pathname = url.pathname;
|
|
432
|
-
|
|
433
|
-
if (pathname !== "/" && pathname.endsWith("/")) {
|
|
434
|
-
pathname = pathname.slice(0, -1);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// Check routes
|
|
438
|
-
const handler = routes.get(pathname);
|
|
439
|
-
if (handler) {
|
|
440
|
-
return handler(req);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// Static files
|
|
444
|
-
const publicPath = "./public" + pathname;
|
|
445
|
-
const file = Bun.file(publicPath);
|
|
446
|
-
if (await file.exists()) {
|
|
447
|
-
return new Response(file);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
return new Response("Not Found", { status: 404 });
|
|
451
|
-
},
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
console.log(\`
|
|
455
|
-
${c.green}▲${c.reset} Ready in \${Date.now() - start}ms
|
|
456
|
-
|
|
457
|
-
${c.dim}➜${c.reset} Local: ${c.cyan}http://localhost:\${PORT}${c.reset}
|
|
458
|
-
\`);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
const start = Date.now();
|
|
462
|
-
main();
|
|
463
|
-
`;
|
|
464
|
-
fs.writeFileSync(path.join(projectDir, `server.${ext}`), serverContent);
|
|
465
|
-
spin8.stop(`Created server.${ext}`);
|
|
466
|
-
|
|
467
462
|
// ============ .gitignore ============
|
|
468
463
|
const spin9 = spinner('Creating .gitignore...');
|
|
469
464
|
fs.writeFileSync(path.join(projectDir, '.gitignore'), `# Dependencies
|