create-frootjs 1.0.13 → 1.0.15

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.
@@ -1,13 +1,12 @@
1
1
  /**
2
- * Fullstack Next.js Alternative Template
3
- * Powered by froot-fullstack, Froot Core, Preact, and Tailwind CSS v4.
4
- * Features Next.js App Router-style file-based routing, nested layouts, Preact SSR, SSG, and Markdown content.
2
+ * Fullstack JSX & Server-Side Rendering (SSR) Template
3
+ * Native JSX components rendered on the server with zero client JavaScript overhead.
5
4
  */
6
- import { COMMON_GITIGNORE } from './types.js';
5
+ import { COMMON_GITIGNORE, COMMON_TSCONFIG } from './types.js';
7
6
  export const fullstackTemplate = {
8
7
  id: 'fullstack',
9
- name: 'Fullstack (Next.js Alternative)',
10
- description: 'Preact SSR & Tailwind v4',
8
+ name: 'Fullstack',
9
+ description: 'Server-rendered JSX views',
11
10
  generate: (projectName) => {
12
11
  return {
13
12
  'package.json': JSON.stringify({
@@ -16,64 +15,29 @@ export const fullstackTemplate = {
16
15
  type: 'module',
17
16
  scripts: {
18
17
  dev: 'tsx watch src/server.tsx',
19
- build: 'tsc && tsx src/build.ts',
20
- 'build:static': 'tsx src/build.ts',
18
+ build: 'tsc',
21
19
  start: 'node dist/server.js',
22
20
  },
23
21
  dependencies: {
24
- 'froot-fullstack': '^1.2.0',
25
- frootjs: '^1.0.6',
26
- preact: '^11.1.0',
27
- 'preact-render-to-string': '^6.8.2',
22
+ frootjs: '^1.0.2',
28
23
  },
29
24
  devDependencies: {
30
- '@tailwindcss/cli': '^4.0.0',
31
- tailwindcss: '^4.0.0',
32
25
  '@types/node': '^22.10.0',
33
26
  tsx: '^4.19.0',
34
27
  typescript: '^5.8.0',
35
28
  },
36
29
  }, null, 2) + '\n',
37
- 'tsconfig.json': `{
38
- "compilerOptions": {
39
- "target": "ES2024",
40
- "module": "NodeNext",
41
- "moduleResolution": "NodeNext",
42
- "lib": ["ES2024", "DOM", "DOM.Iterable"],
43
- "declaration": true,
44
- "declarationMap": true,
45
- "sourceMap": true,
46
- "outDir": "./dist",
47
- "rootDir": "./src",
48
- "strict": true,
49
- "noImplicitAny": true,
50
- "strictNullChecks": true,
51
- "skipLibCheck": true,
52
- "forceConsistentCasingInFileNames": true,
53
- "jsx": "react-jsx",
54
- "jsxImportSource": "preact"
55
- },
56
- "include": ["src/**/*"],
57
- "exclude": ["node_modules", "dist"]
58
- }
59
- `,
30
+ 'tsconfig.json': COMMON_TSCONFIG,
60
31
  '.gitignore': COMMON_GITIGNORE,
61
32
  'README.md': `# ${projectName}
62
33
 
63
- High-performance **Next.js alternative** powered by **Froot Framework**, **Preact**, and **Tailwind CSS v4**.
34
+ Froot application built with the **Fullstack JSX & Server-Side Rendering (SSR)** pattern.
64
35
 
65
36
  ## Features
66
37
 
67
- - ⚡ **Ultra-Fast Throughput**: 120,000+ req/sec powered by Froot's monomorphic V8 engine.
68
- - ⚛️ **Native Preact SSR**: Lightweight 3kB component runtime without React baggage.
69
- - 🎨 **Tailwind CSS v4**: Built-in real CSS-first configuration via \`@theme\` with zero CDN dependencies.
70
- - 📂 **Next.js App Router Architecture**:
71
- - File-based routing automatically discovered from \`src/app\`
72
- - Hierarchical nested layout system (\`app/layout.tsx\` -> \`app/docs/layout.tsx\`)
73
- - Dynamic route dispatch with bracket parameters (\`app/docs/[slug]/page.tsx\`)
74
- - Distinct layouts (e.g. landing page with navbar vs documentation with left sidebar and no top navbar)
75
- - 🚀 **Static Site Generation (SSG)**: Prerender static pages and dynamic routes with \`generateStaticParams()\`.
76
- - 📝 **Built-in Markdown Engine**: Next.js MDX/Contentlayer alternative with zero dependencies.
38
+ - **Native JSX / TSX**: Pure server-rendered JSX without React runtime baggage
39
+ - **Layout Middleware**: Automatic HTML wrapper layout with \`jsxRenderer()\`
40
+ - **Zero Client JS**: Ultra-fast initial page loads and 100% SEO-friendly markup
77
41
 
78
42
  ## Getting Started
79
43
 
@@ -81,351 +45,178 @@ High-performance **Next.js alternative** powered by **Froot Framework**, **Preac
81
45
  # 1. Install dependencies
82
46
  pnpm install
83
47
 
84
- # 2. Run in development mode (builds Tailwind v4 & starts server)
48
+ # 2. Run in development mode
85
49
  pnpm run dev
86
50
 
87
- # 3. Prerender static site (SSG)
88
- pnpm run build:static
89
-
90
- # 4. View in browser
51
+ # 3. View in browser
91
52
  http://localhost:3000
92
53
  \`\`\`
93
54
  `,
94
- 'content/docs/overview.md': `---
95
- title: Overview
96
- category: Getting Started
97
- summary: Introduction to the Froot Fullstack Next.js Alternative architecture.
98
- ---
99
-
100
- Welcome to **Froot Fullstack**, the high-performance Next.js alternative powered by Preact, Tailwind CSS v4, and Froot.
101
-
102
- ## Design Principles
103
-
104
- - **Monomorphic V8 Execution:** Minimal memory overhead and maximum throughput.
105
- - **File-Based Routing:** Next.js App Router conventions with \`src/app\`, nested layouts, and bracket parameters.
106
- - **Preact Server-Side Rendering:** Clean JSX syntax with sub-millisecond render times.
107
- - **Tailwind CSS v4:** Lightning-fast CSS compilation via \`@tailwindcss/cli\` and native \`@theme\` variables.
108
- - **Layout Isolation:** Dedicated layouts for different application sections (e.g. docs vs marketing).
109
- `,
110
- 'content/docs/quickstart.md': `---
111
- title: Quickstart
112
- category: Getting Started
113
- summary: Build your first fullstack application in seconds.
114
- ---
115
-
116
- Create routes, compose Preact components, and serve HTML with extreme performance.
117
-
118
- ## Adding Routes
119
-
120
- Simply add a new folder or file in \`src/app/\`:
55
+ 'src/components/Layout.tsx': `import type { FC, PropsWithChildren } from 'frootjs/jsx';
121
56
 
122
- \`\`\`tsx
123
- // src/app/about/page.tsx
124
- export default function AboutPage() {
125
- return <h1 class="text-3xl font-bold">About Us</h1>;
126
- }
127
- \`\`\`
128
- `,
129
- 'src/styles.css': `@import "tailwindcss";
130
-
131
- @theme {
132
- --color-froot-400: #34d399;
133
- --color-froot-500: #10b981;
134
- --color-froot-600: #059669;
135
- }
136
- `,
137
- 'src/app/layout.tsx': `import type { ComponentChildren } from 'preact';
138
-
139
- export interface RootLayoutProps {
57
+ export interface LayoutProps {
140
58
  title?: string;
141
- description?: string;
142
- children: ComponentChildren;
143
59
  }
144
60
 
145
- export default function RootLayout({
146
- title = 'Froot Fullstack App',
147
- description = 'High-performance Next.js alternative powered by Froot and Preact',
148
- children,
149
- }: RootLayoutProps) {
61
+ export const Layout: FC<PropsWithChildren<LayoutProps>> = ({ title = 'Froot JSX App', children }) => {
150
62
  return (
151
- <html lang="en" class="dark scroll-smooth">
63
+ <html lang="en">
152
64
  <head>
153
65
  <meta charSet="UTF-8" />
154
66
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
155
67
  <title>{title}</title>
156
- <meta name="description" content={description} />
157
- <link rel="stylesheet" href="/styles.css" />
68
+ <style>{\`
69
+ * { box-sizing: border-box; margin: 0; padding: 0; }
70
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0f172a; color: #f8fafc; line-height: 1.6; }
71
+ header { background: #1e293b; border-bottom: 1px solid #334155; padding: 1rem 2rem; display: flex; justify-content: space-between; align-items: center; }
72
+ .logo { font-size: 1.3rem; font-weight: bold; color: #10b981; text-decoration: none; }
73
+ nav a { color: #94a3b8; text-decoration: none; margin-left: 1.5rem; font-weight: 500; }
74
+ nav a:hover { color: #f8fafc; }
75
+ main { max-width: 900px; margin: 2rem auto; padding: 0 1.5rem; }
76
+ footer { text-align: center; padding: 2rem; color: #64748b; font-size: 0.9rem; border-top: 1px solid #1e293b; margin-top: 4rem; }
77
+ \`}</style>
158
78
  </head>
159
- <body class="bg-slate-950 text-slate-100 font-sans min-h-screen antialiased">
160
- {children}
79
+ <body>
80
+ <header>
81
+ <a href="/" className="logo">Froot JSX</a>
82
+ <nav>
83
+ <a href="/">Home</a>
84
+ <a href="/about">About</a>
85
+ <a href="/features">Features</a>
86
+ </nav>
87
+ </header>
88
+ <main>{children}</main>
89
+ <footer>
90
+ <p>Powered by Froot Server-Side Rendering Engine</p>
91
+ </footer>
161
92
  </body>
162
93
  </html>
163
94
  );
164
- }
165
- `,
166
- 'src/app/page.tsx': `export const metadata = {
167
- title: 'Froot Fullstack — Next.js Alternative',
168
- description: 'Extreme performance fullstack web engine with Preact SSR and file-based routing',
169
95
  };
96
+ `,
97
+ 'src/components/Card.tsx': `import type { FC, PropsWithChildren } from 'frootjs/jsx';
170
98
 
171
- export default function HomePage() {
172
- return (
173
- <div>
174
- {/* Top Navbar on Landing Page */}
175
- <header class="border-b border-slate-800 bg-slate-900/60 backdrop-blur-md sticky top-0 z-50">
176
- <div class="max-w-6xl mx-auto px-6 h-16 flex items-center justify-between">
177
- <a href="/" class="flex items-center gap-2 font-bold text-white">
178
- <span class="text-xl">🍏</span>
179
- <span>Froot<span class="text-emerald-400">.ts</span></span>
180
- </a>
181
- <nav class="flex items-center gap-6 text-sm text-slate-300">
182
- <a href="#features" class="hover:text-emerald-400 transition-colors">Features</a>
183
- <a href="/docs" class="text-emerald-400 hover:text-emerald-300 font-semibold">Docs &rarr;</a>
184
- </nav>
185
- </div>
186
- </header>
187
-
188
- {/* Hero Section */}
189
- <main class="max-w-5xl mx-auto px-6 py-20 text-center">
190
- <div class="inline-block px-3 py-1 mb-6 text-xs font-semibold text-emerald-400 bg-emerald-500/10 border border-emerald-500/20 rounded-full">
191
- Next.js Alternative • Preact SSR • Tailwind CSS v4 • File-Based Routing
192
- </div>
193
-
194
- <h1 class="text-5xl font-extrabold tracking-tight text-white mb-6">
195
- High-Performance <span class="text-emerald-400">Fullstack Web Engine</span>
196
- </h1>
197
-
198
- <p class="text-lg text-slate-300 max-w-2xl mx-auto mb-10 leading-relaxed">
199
- Engineered for extreme throughput, Next.js-style file-based routing, nested layouts, and zero-allocation V8 execution.
200
- </p>
201
-
202
- <div class="flex items-center justify-center gap-4">
203
- <a
204
- href="/docs"
205
- class="px-6 py-3 rounded-xl font-semibold bg-emerald-500 text-slate-950 hover:bg-emerald-400 transition-colors shadow-lg shadow-emerald-500/20"
206
- >
207
- Explore Documentation
208
- </a>
209
- <a
210
- href="https://github.com/orbitnorth/froot"
211
- target="_blank"
212
- rel="noopener noreferrer"
213
- class="px-6 py-3 rounded-xl font-semibold bg-slate-800 text-slate-200 hover:bg-slate-700 transition-colors border border-slate-700"
214
- >
215
- GitHub Repository
216
- </a>
217
- </div>
99
+ export interface CardProps {
100
+ title: string;
101
+ badge?: string;
102
+ }
218
103
 
219
- {/* Feature Grid */}
220
- <div id="features" class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-20 text-left">
221
- <div class="p-6 rounded-2xl bg-slate-900/60 border border-slate-800">
222
- <div class="text-emerald-400 text-2xl mb-3">📂</div>
223
- <h3 class="text-lg font-bold text-white mb-2">File-Based Routing</h3>
224
- <p class="text-sm text-slate-400">Next.js App Router conventions with src/app, bracket params [slug], and nested layouts.</p>
225
- </div>
226
- <div class="p-6 rounded-2xl bg-slate-900/60 border border-slate-800">
227
- <div class="text-emerald-400 text-2xl mb-3">🎨</div>
228
- <h3 class="text-lg font-bold text-white mb-2">Tailwind CSS v4</h3>
229
- <p class="text-sm text-slate-400">Built-in real CSS-first configuration via @theme without bloated runtime CDN scripts.</p>
230
- </div>
231
- <div class="p-6 rounded-2xl bg-slate-900/60 border border-slate-800">
232
- <div class="text-emerald-400 text-2xl mb-3">⚡</div>
233
- <h3 class="text-lg font-bold text-white mb-2">120,000+ Req/Sec</h3>
234
- <p class="text-sm text-slate-400">Ultra-fast monomorphic HTTP core outperforming standard Node.js frameworks by 10x.</p>
235
- </div>
236
- </div>
237
- </main>
104
+ export const Card: FC<PropsWithChildren<CardProps>> = ({ title, badge, children }) => {
105
+ return (
106
+ <div style={{
107
+ background: '#1e293b',
108
+ border: '1px solid #334155',
109
+ borderRadius: '8px',
110
+ padding: '1.5rem',
111
+ marginBottom: '1.25rem',
112
+ }}>
113
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.75rem' }}>
114
+ <h3 style={{ color: '#38bdf8', fontSize: '1.2rem' }}>{title}</h3>
115
+ {badge ? (
116
+ <span style={{
117
+ background: '#064e3b',
118
+ color: '#34d399',
119
+ fontSize: '0.75rem',
120
+ padding: '0.2rem 0.6rem',
121
+ borderRadius: '9999px',
122
+ fontWeight: 600,
123
+ }}>
124
+ {badge}
125
+ </span>
126
+ ) : null}
127
+ </div>
128
+ <div>{children}</div>
238
129
  </div>
239
130
  );
240
- }
131
+ };
241
132
  `,
242
- 'src/app/docs/layout.tsx': `import type { ComponentChildren } from 'preact';
243
-
244
- export interface DocsLayoutProps {
245
- currentPath: string;
246
- children: ComponentChildren;
247
- }
248
-
249
- export default function DocsLayout({ currentPath, children }: DocsLayoutProps) {
250
- const links = [
251
- { href: '/docs', title: 'Overview' },
252
- { href: '/docs/quickstart', title: 'Quickstart' },
253
- ];
133
+ 'src/pages/Home.tsx': `import type { FC } from 'frootjs/jsx';
134
+ import { Card } from '../components/Card.js';
254
135
 
136
+ export const HomePage: FC = () => {
255
137
  return (
256
- <div class="flex min-h-screen">
257
- {/* NO NAVBAR ON DOCS! Left sidebar handles all navigation */}
258
- <aside class="w-72 bg-slate-900 border-r border-slate-800 p-6 flex flex-col shrink-0">
259
- <a href="/" class="text-base font-bold text-white mb-6 flex items-center gap-2">
260
- <span>🍏</span>
261
- <span>Froot<span class="text-emerald-400">.ts</span></span>
262
- <span class="text-[10px] bg-emerald-500/10 text-emerald-400 px-1.5 py-0.5 rounded border border-emerald-500/20 font-mono">DOCS</span>
263
- </a>
264
-
265
- <div class="text-xs font-semibold text-slate-400 uppercase tracking-wider mb-3">
266
- Getting Started
267
- </div>
268
-
269
- <nav class="space-y-1">
270
- {links.map((link) => {
271
- const isActive = currentPath === link.href || (link.href === '/docs' && currentPath === '/docs/overview');
272
- const cls = isActive
273
- ? 'bg-emerald-500/10 text-emerald-400 font-semibold border-l-2 border-emerald-400 pl-2.5'
274
- : 'text-slate-400 hover:text-white hover:bg-slate-800/60';
138
+ <div>
139
+ <div style={{ marginBottom: '2rem' }}>
140
+ <h1 style={{ fontSize: '2.25rem', color: '#10b981', marginBottom: '0.5rem' }}>
141
+ Server-Side Rendered JSX
142
+ </h1>
143
+ <p style={{ color: '#94a3b8', fontSize: '1.1rem' }}>
144
+ Blazing fast HTML generated on the server with TypeScript-native JSX components.
145
+ </p>
146
+ </div>
275
147
 
276
- return (
277
- <a
278
- key={link.href}
279
- href={link.href}
280
- class={\`block px-3 py-2 text-xs rounded-lg transition-colors \${cls}\`}
281
- >
282
- {link.title}
283
- </a>
284
- );
285
- })}
286
- </nav>
148
+ <Card title="Zero Client Runtime" badge="Performance">
149
+ <p>No heavy virtual DOM diffing in the browser. Pure, pre-rendered semantic HTML delivered instantly.</p>
150
+ </Card>
287
151
 
288
- <div class="mt-auto pt-6 border-t border-slate-800 text-xs text-slate-400">
289
- <a href="/" class="hover:text-emerald-400 transition-colors flex items-center gap-1.5">
290
- <span>&larr;</span>
291
- <span>Back to Home</span>
292
- </a>
293
- </div>
294
- </aside>
152
+ <Card title="Type-Safe Views" badge="DX">
153
+ <p>Full TypeScript compiler checking for props, children, styles, and HTML attributes.</p>
154
+ </Card>
295
155
 
296
- {/* Main Document Body */}
297
- <main class="flex-1 max-w-4xl px-8 py-10">
298
- {children}
299
- </main>
156
+ <Card title="Streaming & Islands Ready" badge="Architecture">
157
+ <p>Seamlessly compose asynchronous server components and stream output as it becomes available.</p>
158
+ </Card>
300
159
  </div>
301
160
  );
302
- }
303
- `,
304
- 'src/app/docs/page.tsx': `import * as path from 'node:path';
305
- import { fileURLToPath } from 'node:url';
306
- import { renderMarkdownFile } from 'froot-fullstack';
307
-
308
- const __filename = fileURLToPath(import.meta.url);
309
- const __dirname = path.dirname(__filename);
310
-
311
- export const metadata = {
312
- title: 'Documentation Overview — Froot Fullstack',
313
- description: 'Overview of the high-performance Froot Fullstack framework.',
314
161
  };
162
+ `,
163
+ 'src/pages/About.tsx': `import type { FC } from 'frootjs/jsx';
315
164
 
316
- export default async function DocsOverviewPage() {
317
- const docPath = path.resolve(process.cwd(), 'content/docs/overview.md');
318
- const { frontmatter, html } = await renderMarkdownFile(docPath);
319
-
165
+ export const AboutPage: FC = () => {
320
166
  return (
321
- <div>
322
- <div class="text-xs font-mono text-emerald-400 mb-2 uppercase tracking-wider">
323
- {frontmatter['category'] || 'Getting Started'}
324
- </div>
325
- <h1 class="text-3xl font-extrabold text-white mb-6">
326
- {frontmatter['title'] || 'Documentation Overview'}
327
- </h1>
328
- <article
329
- class="prose prose-invert max-w-none text-slate-300 leading-relaxed space-y-4"
330
- dangerouslySetInnerHTML={{ __html: html }}
331
- />
167
+ <div style={{ background: '#1e293b', padding: '2rem', borderRadius: '8px', border: '1px solid #334155' }}>
168
+ <h1 style={{ color: '#10b981', marginBottom: '1rem' }}>About This Application</h1>
169
+ <p style={{ marginBottom: '1rem' }}>
170
+ This project showcases Froot's built-in JSX rendering pipeline. Unlike traditional React or Next.js setups,
171
+ Froot renders JSX straight to HTML strings without requiring React, ReactDOM, or a Node.js bundling step.
172
+ </p>
173
+ <p style={{ color: '#94a3b8' }}>
174
+ It achieves sub-millisecond page render times while maintaining full component composition.
175
+ </p>
332
176
  </div>
333
177
  );
334
- }
178
+ };
335
179
  `,
336
- 'src/app/docs/[slug]/page.tsx': `import * as path from 'node:path';
337
- import { fileURLToPath } from 'node:url';
338
- import { renderMarkdownFile } from 'froot-fullstack';
180
+ 'src/server.tsx': `import { Froot } from 'frootjs';
181
+ import { jsxRenderer } from 'frootjs/jsx';
182
+ import { Layout } from './components/Layout.js';
183
+ import { HomePage } from './pages/Home.js';
184
+ import { AboutPage } from './pages/About.js';
339
185
 
340
- const __filename = fileURLToPath(import.meta.url);
341
- const __dirname = path.dirname(__filename);
186
+ export const app = new Froot();
342
187
 
343
- export async function generateStaticParams() {
344
- return [
345
- { slug: 'overview' },
346
- { slug: 'quickstart' },
347
- ];
348
- }
188
+ // Wrap all HTML responses in the global Layout shell
189
+ app.use('*', jsxRenderer(({ children }) => {
190
+ return <Layout>{children}</Layout>;
191
+ }));
349
192
 
350
- export async function generateMetadata({ params }: { params: { slug: string } }) {
351
- const slug = params.slug || 'overview';
352
- return {
353
- title: \`\${slug.charAt(0).toUpperCase() + slug.slice(1)} — Froot Fullstack Docs\`,
354
- };
355
- }
193
+ // Route handlers
194
+ app.get('/', (c) => {
195
+ return c.render(<HomePage />);
196
+ });
356
197
 
357
- export default async function DocSlugPage({ params }: { params: { slug: string } }) {
358
- const slug = params.slug || 'overview';
359
- const docPath = path.resolve(process.cwd(), 'content/docs', \`\${slug}.md\`);
360
- const { frontmatter, html } = await renderMarkdownFile(docPath);
198
+ app.get('/about', (c) => {
199
+ return c.render(<AboutPage />);
200
+ });
361
201
 
362
- return (
202
+ app.get('/features', (c) => {
203
+ return c.render(
363
204
  <div>
364
- <div class="text-xs font-mono text-emerald-400 mb-2 uppercase tracking-wider">
365
- {frontmatter['category'] || 'Documentation'}
366
- </div>
367
- <h1 class="text-3xl font-extrabold text-white mb-6">
368
- {frontmatter['title'] || slug}
369
- </h1>
370
- <article
371
- class="prose prose-invert max-w-none text-slate-300 leading-relaxed space-y-4"
372
- dangerouslySetInnerHTML={{ __html: html }}
373
- />
205
+ <h1 style={{ color: '#10b981', marginBottom: '1rem' }}>Framework Features</h1>
206
+ <ul style={{ paddingLeft: '1.5rem', color: '#cbd5e1' }}>
207
+ <li>RADIX tree router with O(K) lookup</li>
208
+ <li>Auto-generated OpenAPI 3.1 & Scalar docs</li>
209
+ <li>Native JSX & async component support</li>
210
+ <li>Full WebCrypto authentication ecosystem</li>
211
+ <li>Universal WebSockets & pub/sub hub</li>
212
+ </ul>
374
213
  </div>
375
214
  );
376
- }
377
- `,
378
- 'src/server.tsx': `import * as path from 'node:path';
379
- import { fileURLToPath } from 'node:url';
380
- import { Froot } from 'frootjs';
381
- import { createAppRouter } from 'froot-fullstack';
382
-
383
- const __filename = fileURLToPath(import.meta.url);
384
- const __dirname = path.dirname(__filename);
385
-
386
- export const app = new Froot();
387
- export const router = createAppRouter(app);
388
-
389
- // 1. Enable built-in Tailwind CSS v4 pipeline (watches in dev, serves /styles.css)
390
- await router.enableTailwind({
391
- input: path.resolve(__dirname, 'styles.css'),
392
- output: path.resolve(__dirname, '../dist/styles.css'),
393
215
  });
394
216
 
395
- // 2. Discover file-based routes and nested layouts in src/app
396
- const appDir = path.resolve(__dirname, 'app');
397
- await router.discover(appDir);
398
-
399
- const PORT = Number(process.env['PORT'] || 3000);
400
- const isDirectEntry = process.argv[1] ? path.basename(process.argv[1]).includes('server') : false;
401
- if (isDirectEntry && process.env['NODE_ENV'] !== 'test') {
402
- app.listen(PORT, () => {
403
- console.log(\`🍏 Froot Fullstack server running at http://localhost:\${PORT}\`);
404
- });
405
- }
406
- `,
407
- 'src/build.ts': `/**
408
- * Static Site Generation (SSG) Builder
409
- */
410
- process.env['FROOT_BUILD'] = 'true';
411
-
412
- import * as path from 'node:path';
413
- import { fileURLToPath } from 'node:url';
414
- import { router } from './server.js';
415
-
416
- const __filename = fileURLToPath(import.meta.url);
417
- const __dirname = path.dirname(__filename);
418
- const outDir = path.resolve(__dirname, '../dist/static');
419
-
420
- async function build() {
421
- console.log('🍏 Building static site with froot-fullstack...');
422
- const result = await router.exportStatic({ outDir });
423
- console.log(\`✅ Export complete in \${result.durationMs}ms: \${result.renderedRoutes.length} routes pre-rendered.\`);
424
- }
425
-
426
- build().catch((err) => {
427
- console.error('❌ Build failed:', err);
428
- process.exit(1);
217
+ const PORT = Number(process.env.PORT) || 3000;
218
+ app.listen(PORT, () => {
219
+ console.log(\`Fullstack JSX server running on http://localhost:\${PORT}\`);
429
220
  });
430
221
  `,
431
222
  };
@@ -1 +1 @@
1
- {"version":3,"file":"fullstack.js","sourceRoot":"","sources":["../../src/templates/fullstack.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAuC,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnF,MAAM,CAAC,MAAM,iBAAiB,GAAuB;IACnD,EAAE,EAAE,WAAW;IACf,IAAI,EAAE,iCAAiC;IACvC,WAAW,EAAE,0BAA0B;IACvC,QAAQ,EAAE,CAAC,WAAmB,EAAmB,EAAE;QACjD,OAAO;YACL,cAAc,EAAE,IAAI,CAAC,SAAS,CAC5B;gBACE,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,OAAO;gBAChB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE;oBACP,GAAG,EAAE,0BAA0B;oBAC/B,KAAK,EAAE,yBAAyB;oBAChC,cAAc,EAAE,kBAAkB;oBAClC,KAAK,EAAE,qBAAqB;iBAC7B;gBACD,YAAY,EAAE;oBACZ,iBAAiB,EAAE,QAAQ;oBAC3B,OAAO,EAAE,QAAQ;oBACjB,MAAM,EAAE,SAAS;oBACjB,yBAAyB,EAAE,QAAQ;iBACpC;gBACD,eAAe,EAAE;oBACf,kBAAkB,EAAE,QAAQ;oBAC5B,WAAW,EAAE,QAAQ;oBACrB,aAAa,EAAE,UAAU;oBACzB,GAAG,EAAE,SAAS;oBACd,UAAU,EAAE,QAAQ;iBACrB;aACF,EACD,IAAI,EACJ,CAAC,CACF,GAAG,IAAI;YAER,eAAe,EAAE;;;;;;;;;;;;;;;;;;;;;;CAsBtB;YACK,YAAY,EAAE,gBAAgB;YAE9B,WAAW,EAAE,KAAK,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgClC;YAEK,0BAA0B,EAAE;;;;;;;;;;;;;;;CAejC;YAEK,4BAA4B,EAAE;;;;;;;;;;;;;;;;;;CAkBnC;YAEK,gBAAgB,EAAE;;;;;;;CAOvB;YAEK,oBAAoB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4B3B;YAEK,kBAAkB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2EzB;YAEK,yBAAyB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6DhC;YAEK,uBAAuB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+B9B;YAEK,8BAA8B,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCrC;YAEK,gBAAgB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BvB;YAEK,cAAc,EAAE;;;;;;;;;;;;;;;;;;;;;;;CAuBrB;SACI,CAAC;IACJ,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"fullstack.js","sourceRoot":"","sources":["../../src/templates/fullstack.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAuC,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEpG,MAAM,CAAC,MAAM,iBAAiB,GAAuB;IACnD,EAAE,EAAE,WAAW;IACf,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,2BAA2B;IACxC,QAAQ,EAAE,CAAC,WAAmB,EAAmB,EAAE;QACjD,OAAO;YACL,cAAc,EAAE,IAAI,CAAC,SAAS,CAC5B;gBACE,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,OAAO;gBAChB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE;oBACP,GAAG,EAAE,0BAA0B;oBAC/B,KAAK,EAAE,KAAK;oBACZ,KAAK,EAAE,qBAAqB;iBAC7B;gBACD,YAAY,EAAE;oBACZ,OAAO,EAAE,QAAQ;iBAClB;gBACD,eAAe,EAAE;oBACf,aAAa,EAAE,UAAU;oBACzB,GAAG,EAAE,SAAS;oBACd,UAAU,EAAE,QAAQ;iBACrB;aACF,EACD,IAAI,EACJ,CAAC,CACF,GAAG,IAAI;YAER,eAAe,EAAE,eAAe;YAChC,YAAY,EAAE,gBAAgB;YAE9B,WAAW,EAAE,KAAK,WAAW;;;;;;;;;;;;;;;;;;;;;;CAsBlC;YAEK,2BAA2B,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyClC;YAEK,yBAAyB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmChC;YAEK,oBAAoB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6B3B;YAEK,qBAAqB,EAAE;;;;;;;;;;;;;;;;CAgB5B;YAEK,gBAAgB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCvB;SACI,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAShD,cAAc,YAAY,CAAC;AAE3B,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAQxD,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,kBAAkB,EAA6B,CAAC;AAE5E,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEtE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAQhD,cAAc,YAAY,CAAC;AAE3B,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAOxD,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,kBAAkB,EAA6B,CAAC;AAE5E,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAEtE"}
@@ -7,7 +7,6 @@ import { modularTemplate } from './modular.js';
7
7
  import { streamingTemplate } from './streaming.js';
8
8
  import { websocketTemplate } from './websocket.js';
9
9
  import { openapiTemplate } from './openapi.js';
10
- import { fullstackTemplate } from './fullstack.js';
11
10
  import { minimalTemplate } from './minimal.js';
12
11
  export * from './types.js';
13
12
  export const TEMPLATES = {
@@ -16,7 +15,6 @@ export const TEMPLATES = {
16
15
  streaming: streamingTemplate,
17
16
  websocket: websocketTemplate,
18
17
  openapi: openapiTemplate,
19
- fullstack: fullstackTemplate,
20
18
  minimal: minimalTemplate,
21
19
  };
22
20
  export const TEMPLATE_LIST = Object.values(TEMPLATES);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,cAAc,YAAY,CAAC;AAE3B,MAAM,CAAC,MAAM,SAAS,GAAuC;IAC3D,GAAG,EAAE,WAAW;IAChB,OAAO,EAAE,eAAe;IACxB,SAAS,EAAE,iBAAiB;IAC5B,SAAS,EAAE,iBAAiB;IAC5B,OAAO,EAAE,eAAe;IACxB,SAAS,EAAE,iBAAiB;IAC5B,OAAO,EAAE,eAAe;CACzB,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAyB,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAE5E,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AACrC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,cAAc,YAAY,CAAC;AAE3B,MAAM,CAAC,MAAM,SAAS,GAAuC;IAC3D,GAAG,EAAE,WAAW;IAChB,OAAO,EAAE,eAAe;IACxB,SAAS,EAAE,iBAAiB;IAC5B,SAAS,EAAE,iBAAiB;IAC5B,OAAO,EAAE,eAAe;IACxB,OAAO,EAAE,eAAe;CACzB,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAyB,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAE5E,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AACrC,CAAC"}