create-frootjs 0.0.0-stage → 1.0.1
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 +68 -2
- package/dist/generator.d.ts +21 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +62 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +215 -0
- package/dist/index.js.map +1 -0
- package/dist/templates/fullstack.d.ts +7 -0
- package/dist/templates/fullstack.d.ts.map +1 -0
- package/dist/templates/fullstack.js +224 -0
- package/dist/templates/fullstack.js.map +1 -0
- package/dist/templates/index.d.ts +10 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +26 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/minimal.d.ts +7 -0
- package/dist/templates/minimal.d.ts.map +1 -0
- package/dist/templates/minimal.js +89 -0
- package/dist/templates/minimal.js.map +1 -0
- package/dist/templates/modular.d.ts +7 -0
- package/dist/templates/modular.d.ts.map +1 -0
- package/dist/templates/modular.js +300 -0
- package/dist/templates/modular.js.map +1 -0
- package/dist/templates/mvc.d.ts +7 -0
- package/dist/templates/mvc.d.ts.map +1 -0
- package/dist/templates/mvc.js +239 -0
- package/dist/templates/mvc.js.map +1 -0
- package/dist/templates/openapi.d.ts +7 -0
- package/dist/templates/openapi.d.ts.map +1 -0
- package/dist/templates/openapi.js +206 -0
- package/dist/templates/openapi.js.map +1 -0
- package/dist/templates/streaming.d.ts +7 -0
- package/dist/templates/streaming.d.ts.map +1 -0
- package/dist/templates/streaming.js +211 -0
- package/dist/templates/streaming.js.map +1 -0
- package/dist/templates/types.d.ts +17 -0
- package/dist/templates/types.d.ts.map +1 -0
- package/dist/templates/types.js +47 -0
- package/dist/templates/types.js.map +1 -0
- package/dist/templates/websocket.d.ts +7 -0
- package/dist/templates/websocket.d.ts.map +1 -0
- package/dist/templates/websocket.js +198 -0
- package/dist/templates/websocket.js.map +1 -0
- package/dist/ui.d.ts +73 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +236 -0
- package/dist/ui.js.map +1 -0
- package/package.json +45 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OrbitNorth LLC
|
|
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,3 +1,69 @@
|
|
|
1
|
-
#
|
|
1
|
+
# create-frootjs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The official CLI project generator for Froot applications.
|
|
4
|
+
|
|
5
|
+
Quickly spin up production-ready Froot projects with your choice of architectural patterns, complete with TypeScript configuration, onion middleware, and developer tooling.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
Run any of the following commands in your terminal:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# Using npm
|
|
13
|
+
npm create frootjs@latest
|
|
14
|
+
|
|
15
|
+
# Using pnpm
|
|
16
|
+
pnpm create frootjs
|
|
17
|
+
|
|
18
|
+
# Using yarn
|
|
19
|
+
yarn create frootjs
|
|
20
|
+
|
|
21
|
+
# Using bun
|
|
22
|
+
bun create frootjs
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or invoke the binary directly:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx create-frootjs my-app
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Available Architectural Templates
|
|
32
|
+
|
|
33
|
+
| Template | Flag | Description |
|
|
34
|
+
| :--- | :--- | :--- |
|
|
35
|
+
| **MVC / Layered** | `--template mvc` | Enterprise layered pattern: routes, controllers, services, models, and middleware |
|
|
36
|
+
| **Modular (NestJS-style)** | `--template modular` | Feature-based domain modules (`src/modules/*`), auth guard, and error filters |
|
|
37
|
+
| **Streaming & SSE** | `--template streaming` | Server-Sent Events metrics, AI token streaming simulation, and HTML live client |
|
|
38
|
+
| **WebSocket Hub** | `--template websocket` | Cross-runtime WebSockets, pub/sub rooms hub, and interactive chat client |
|
|
39
|
+
| **OpenAPI 3.1 & Docs** | `--template openapi` | Auto-generated OpenAPI 3.1 JSON and Scalar interactive reference UI at `/docs` |
|
|
40
|
+
| **Fullstack JSX & SSR** | `--template fullstack` | Native JSX components, typed layout middleware, and zero-JS server rendering |
|
|
41
|
+
| **Minimal Starter** | `--template minimal` | Lean single-file API starter with JSON endpoints and CORS |
|
|
42
|
+
|
|
43
|
+
## CLI Options
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
Usage:
|
|
47
|
+
npx create-frootjs [project-directory] [options]
|
|
48
|
+
|
|
49
|
+
Options:
|
|
50
|
+
-t, --template <name> Template architecture (mvc, modular, streaming, websocket, openapi, fullstack, minimal)
|
|
51
|
+
--pm <manager> Package manager to use: pnpm | npm | yarn | bun
|
|
52
|
+
--git / --no-git Initialize a git repository
|
|
53
|
+
--install / --no-install Automatically install project dependencies
|
|
54
|
+
-y, --yes Accept all defaults non-interactively
|
|
55
|
+
-v, --version Display CLI version
|
|
56
|
+
-h, --help Display help information
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Non-Interactive Automation Example
|
|
60
|
+
|
|
61
|
+
For CI/CD or scripted setups:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx create-frootjs my-api --template modular --pm pnpm --git --install
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT (c) OrbitNorth LLC
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Scaffolding Engine
|
|
3
|
+
* Writes template files to disk, initializes git, and executes dependency installation.
|
|
4
|
+
*/
|
|
5
|
+
import { TemplateDefinition } from './templates/index.js';
|
|
6
|
+
export interface ScaffoldOptions {
|
|
7
|
+
targetDir: string;
|
|
8
|
+
projectName: string;
|
|
9
|
+
template: TemplateDefinition;
|
|
10
|
+
pkgManager: 'pnpm' | 'npm' | 'yarn' | 'bun';
|
|
11
|
+
gitInit: boolean;
|
|
12
|
+
installDeps: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface ScaffoldResult {
|
|
15
|
+
targetDir: string;
|
|
16
|
+
filesWritten: number;
|
|
17
|
+
gitInitialized: boolean;
|
|
18
|
+
depsInstalled: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function scaffoldProject(options: ScaffoldOptions): Promise<ScaffoldResult>;
|
|
21
|
+
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAK1D,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,UAAU,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAuDvF"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Scaffolding Engine
|
|
3
|
+
* Writes template files to disk, initializes git, and executes dependency installation.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'node:fs/promises';
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import { exec } from 'node:child_process';
|
|
8
|
+
import { promisify } from 'node:util';
|
|
9
|
+
import { c, printSuccess, printInfo, printWarning } from './ui.js';
|
|
10
|
+
const execAsync = promisify(exec);
|
|
11
|
+
export async function scaffoldProject(options) {
|
|
12
|
+
const { targetDir, projectName, template, pkgManager, gitInit, installDeps } = options;
|
|
13
|
+
// 1. Ensure target directory exists
|
|
14
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
15
|
+
// 2. Generate files map from template
|
|
16
|
+
const files = template.generate(projectName);
|
|
17
|
+
const fileKeys = Object.keys(files);
|
|
18
|
+
// 3. Write each file to destination
|
|
19
|
+
for (const relativePath of fileKeys) {
|
|
20
|
+
const filePath = path.join(targetDir, relativePath);
|
|
21
|
+
const dir = path.dirname(filePath);
|
|
22
|
+
await fs.mkdir(dir, { recursive: true });
|
|
23
|
+
await fs.writeFile(filePath, files[relativePath], 'utf8');
|
|
24
|
+
}
|
|
25
|
+
printSuccess(`Created ${c.bold}${fileKeys.length}${c.reset} files from template ${c.emerald}${template.name}${c.reset}`);
|
|
26
|
+
// 4. Git initialization
|
|
27
|
+
let gitInitialized = false;
|
|
28
|
+
if (gitInit) {
|
|
29
|
+
try {
|
|
30
|
+
await execAsync('git init', { cwd: targetDir });
|
|
31
|
+
gitInitialized = true;
|
|
32
|
+
printSuccess(`Initialized git repository`);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
printWarning(`Could not initialize git repository (is git installed?)`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// 5. Dependency installation
|
|
39
|
+
let depsInstalled = false;
|
|
40
|
+
if (installDeps) {
|
|
41
|
+
printInfo(`Installing dependencies using ${c.bold}${pkgManager}${c.reset}...`);
|
|
42
|
+
try {
|
|
43
|
+
// Use .cmd extension on Windows when running npm/pnpm/yarn
|
|
44
|
+
const isWin = process.platform === 'win32';
|
|
45
|
+
const cmd = isWin && pkgManager !== 'bun' ? `${pkgManager}.cmd` : pkgManager;
|
|
46
|
+
await execAsync(`${cmd} install`, { cwd: targetDir });
|
|
47
|
+
depsInstalled = true;
|
|
48
|
+
printSuccess(`Dependencies installed successfully`);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
52
|
+
printWarning(`Dependency installation skipped or failed: ${errMsg}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
targetDir,
|
|
57
|
+
filesWritten: fileKeys.length,
|
|
58
|
+
gitInitialized,
|
|
59
|
+
depsInstalled,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* create-frootjs CLI Project Generator
|
|
4
|
+
* Interactive, zero-dependency CLI tool for scaffolding modern Froot web applications.
|
|
5
|
+
*/
|
|
6
|
+
import * as path from 'node:path';
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import { printBanner, printStep, printError, printNextSteps, promptText, promptSelect, promptConfirm, c, } from './ui.js';
|
|
9
|
+
import { TEMPLATES, TEMPLATE_LIST, getTemplate } from './templates/index.js';
|
|
10
|
+
import { scaffoldProject } from './generator.js';
|
|
11
|
+
const VERSION = '1.0.1';
|
|
12
|
+
function parseCliArgs(argv) {
|
|
13
|
+
const args = {};
|
|
14
|
+
const raw = argv.slice(2);
|
|
15
|
+
for (let i = 0; i < raw.length; i++) {
|
|
16
|
+
const item = raw[i];
|
|
17
|
+
if (item === '--help' || item === '-h') {
|
|
18
|
+
args.help = true;
|
|
19
|
+
}
|
|
20
|
+
else if (item === '--version' || item === '-v') {
|
|
21
|
+
args.version = true;
|
|
22
|
+
}
|
|
23
|
+
else if (item === '--yes' || item === '-y') {
|
|
24
|
+
args.yes = true;
|
|
25
|
+
}
|
|
26
|
+
else if (item === '--git') {
|
|
27
|
+
args.git = true;
|
|
28
|
+
}
|
|
29
|
+
else if (item === '--no-git') {
|
|
30
|
+
args.git = false;
|
|
31
|
+
}
|
|
32
|
+
else if (item === '--install') {
|
|
33
|
+
args.install = true;
|
|
34
|
+
}
|
|
35
|
+
else if (item === '--no-install') {
|
|
36
|
+
args.install = false;
|
|
37
|
+
}
|
|
38
|
+
else if (item === '--template' || item === '-t') {
|
|
39
|
+
args.template = raw[++i];
|
|
40
|
+
}
|
|
41
|
+
else if (item.startsWith('--template=')) {
|
|
42
|
+
args.template = item.split('=')[1];
|
|
43
|
+
}
|
|
44
|
+
else if (item === '--pm') {
|
|
45
|
+
args.pkgManager = raw[++i];
|
|
46
|
+
}
|
|
47
|
+
else if (item.startsWith('--pm=')) {
|
|
48
|
+
args.pkgManager = item.split('=')[1];
|
|
49
|
+
}
|
|
50
|
+
else if (!item.startsWith('-') && !args.targetDir) {
|
|
51
|
+
args.targetDir = item;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return args;
|
|
55
|
+
}
|
|
56
|
+
function printUsage() {
|
|
57
|
+
console.log(`
|
|
58
|
+
${c.bold}Usage:${c.reset}
|
|
59
|
+
npm create frootjs [project-directory] [options]
|
|
60
|
+
npx create-frootjs [project-directory] [options]
|
|
61
|
+
|
|
62
|
+
${c.bold}Options:${c.reset}
|
|
63
|
+
-t, --template <name> Template architecture:
|
|
64
|
+
• mvc MVC / Layered Architecture
|
|
65
|
+
• modular Modular Architecture (NestJS-style)
|
|
66
|
+
• streaming Real-Time Streaming & SSE
|
|
67
|
+
• websocket WebSocket & Real-Time Pub/Sub
|
|
68
|
+
• openapi OpenAPI 3.1 & Interactive Docs
|
|
69
|
+
• fullstack Fullstack JSX & SSR
|
|
70
|
+
• minimal Minimal Starter (Single-file)
|
|
71
|
+
--pm <manager> Package manager: pnpm | npm | yarn | bun
|
|
72
|
+
--git / --no-git Initialize a git repository
|
|
73
|
+
--install / --no-install Automatically install dependencies
|
|
74
|
+
-y, --yes Accept all defaults non-interactively
|
|
75
|
+
-v, --version Display version
|
|
76
|
+
-h, --help Display help information
|
|
77
|
+
`);
|
|
78
|
+
}
|
|
79
|
+
/** Detect which package manager invoked create-frootjs */
|
|
80
|
+
function detectCurrentPackageManager() {
|
|
81
|
+
const userAgent = process.env.npm_config_user_agent || '';
|
|
82
|
+
if (userAgent.startsWith('pnpm'))
|
|
83
|
+
return 'pnpm';
|
|
84
|
+
if (userAgent.startsWith('yarn'))
|
|
85
|
+
return 'yarn';
|
|
86
|
+
if (userAgent.startsWith('bun'))
|
|
87
|
+
return 'bun';
|
|
88
|
+
return 'npm';
|
|
89
|
+
}
|
|
90
|
+
async function main() {
|
|
91
|
+
const args = parseCliArgs(process.argv);
|
|
92
|
+
if (args.version) {
|
|
93
|
+
console.log(`create-frootjs v${VERSION}`);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (args.help) {
|
|
97
|
+
printBanner(VERSION);
|
|
98
|
+
printUsage();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
printBanner(VERSION);
|
|
102
|
+
// 1. Resolve Project Directory & Name
|
|
103
|
+
let targetDir = args.targetDir;
|
|
104
|
+
if (!targetDir) {
|
|
105
|
+
if (args.yes) {
|
|
106
|
+
targetDir = 'froot-app';
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
printStep(1, 4, 'Project location');
|
|
110
|
+
targetDir = await promptText('Where would you like to create your project?', 'my-froot-app', (input) => {
|
|
111
|
+
if (!input.trim())
|
|
112
|
+
return 'Project name cannot be empty';
|
|
113
|
+
return true;
|
|
114
|
+
});
|
|
115
|
+
console.log();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const resolvedTarget = path.resolve(process.cwd(), targetDir);
|
|
119
|
+
const projectName = path.basename(resolvedTarget);
|
|
120
|
+
// Verify if directory already exists with files
|
|
121
|
+
if (fs.existsSync(resolvedTarget)) {
|
|
122
|
+
const existingFiles = fs.readdirSync(resolvedTarget);
|
|
123
|
+
if (existingFiles.length > 0 && !args.yes) {
|
|
124
|
+
printStep(1, 4, 'Target directory warning');
|
|
125
|
+
const proceed = await promptConfirm(`Target directory "${targetDir}" is not empty. Continue anyway?`, false);
|
|
126
|
+
console.log();
|
|
127
|
+
if (!proceed) {
|
|
128
|
+
printError('Aborted by user.');
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// 2. Select Template
|
|
134
|
+
let selectedTemplate = args.template ? getTemplate(args.template) : undefined;
|
|
135
|
+
if (args.template && !selectedTemplate) {
|
|
136
|
+
printError(`Unknown template "${args.template}".`);
|
|
137
|
+
console.log(`Available templates: ${Object.keys(TEMPLATES).join(', ')}`);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
if (!selectedTemplate) {
|
|
141
|
+
if (args.yes) {
|
|
142
|
+
selectedTemplate = TEMPLATES['mvc'];
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
printStep(2, 4, 'Choose architectural template');
|
|
146
|
+
const choice = await promptSelect('Select the project template that fits your architecture:', TEMPLATE_LIST.map((t) => ({
|
|
147
|
+
value: t.id,
|
|
148
|
+
label: t.name,
|
|
149
|
+
hint: t.description,
|
|
150
|
+
})));
|
|
151
|
+
selectedTemplate = getTemplate(choice);
|
|
152
|
+
console.log();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// 3. Package Manager Selection
|
|
156
|
+
const detectedPm = detectCurrentPackageManager();
|
|
157
|
+
let pkgManager = args.pkgManager || detectedPm;
|
|
158
|
+
if (!args.pkgManager && !args.yes) {
|
|
159
|
+
printStep(3, 4, 'Package manager');
|
|
160
|
+
pkgManager = await promptSelect('Which package manager do you want to use?', [
|
|
161
|
+
{ value: 'pnpm', label: 'pnpm', hint: 'Fast, disk space efficient' },
|
|
162
|
+
{ value: 'npm', label: 'npm', hint: 'Standard Node package manager' },
|
|
163
|
+
{ value: 'yarn', label: 'yarn', hint: 'Classic or Modern Yarn' },
|
|
164
|
+
{ value: 'bun', label: 'bun', hint: 'Ultra-fast all-in-one toolkit' },
|
|
165
|
+
]);
|
|
166
|
+
console.log();
|
|
167
|
+
}
|
|
168
|
+
// 4. Git Initialization & Install Preferences
|
|
169
|
+
let gitInit = args.git;
|
|
170
|
+
let installDeps = args.install;
|
|
171
|
+
if (!args.yes) {
|
|
172
|
+
printStep(4, 4, 'Project setup preferences');
|
|
173
|
+
if (gitInit === undefined) {
|
|
174
|
+
gitInit = await promptConfirm('Initialize a new git repository?', true);
|
|
175
|
+
}
|
|
176
|
+
if (installDeps === undefined) {
|
|
177
|
+
installDeps = await promptConfirm(`Install dependencies now with ${pkgManager}?`, true);
|
|
178
|
+
}
|
|
179
|
+
console.log();
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
if (gitInit === undefined)
|
|
183
|
+
gitInit = true;
|
|
184
|
+
if (installDeps === undefined)
|
|
185
|
+
installDeps = true;
|
|
186
|
+
}
|
|
187
|
+
// 5. Scaffold Project
|
|
188
|
+
try {
|
|
189
|
+
const result = await scaffoldProject({
|
|
190
|
+
targetDir: resolvedTarget,
|
|
191
|
+
projectName,
|
|
192
|
+
template: selectedTemplate,
|
|
193
|
+
pkgManager,
|
|
194
|
+
gitInit: Boolean(gitInit),
|
|
195
|
+
installDeps: Boolean(installDeps),
|
|
196
|
+
});
|
|
197
|
+
// 6. Print stylized next steps card
|
|
198
|
+
printNextSteps({
|
|
199
|
+
projectDir: targetDir,
|
|
200
|
+
pkgManager,
|
|
201
|
+
hasInstalled: result.depsInstalled,
|
|
202
|
+
port: 3000,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
207
|
+
printError(`Scaffolding failed: ${msg}`);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
main().catch((err) => {
|
|
212
|
+
printError(String(err));
|
|
213
|
+
process.exit(1);
|
|
214
|
+
});
|
|
215
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fullstack JSX & Server-Side Rendering (SSR) Template
|
|
3
|
+
* Native JSX components rendered on the server with zero client JavaScript overhead.
|
|
4
|
+
*/
|
|
5
|
+
import { TemplateDefinition } from './types.js';
|
|
6
|
+
export declare const fullstackTemplate: TemplateDefinition;
|
|
7
|
+
//# sourceMappingURL=fullstack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fullstack.d.ts","sourceRoot":"","sources":["../../src/templates/fullstack.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAsD,MAAM,YAAY,CAAC;AAEpG,eAAO,MAAM,iBAAiB,EAAE,kBAoO/B,CAAC"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fullstack JSX & Server-Side Rendering (SSR) Template
|
|
3
|
+
* Native JSX components rendered on the server with zero client JavaScript overhead.
|
|
4
|
+
*/
|
|
5
|
+
import { COMMON_GITIGNORE, COMMON_TSCONFIG } from './types.js';
|
|
6
|
+
export const fullstackTemplate = {
|
|
7
|
+
id: 'fullstack',
|
|
8
|
+
name: 'Fullstack JSX & Server-Side Rendering',
|
|
9
|
+
description: 'Native JSX components, typed layouts, and zero-JS HTML server rendering',
|
|
10
|
+
generate: (projectName) => {
|
|
11
|
+
return {
|
|
12
|
+
'package.json': JSON.stringify({
|
|
13
|
+
name: projectName,
|
|
14
|
+
version: '1.0.0',
|
|
15
|
+
type: 'module',
|
|
16
|
+
scripts: {
|
|
17
|
+
dev: 'node --experimental-strip-types src/server.tsx',
|
|
18
|
+
build: 'tsc',
|
|
19
|
+
start: 'node dist/server.js',
|
|
20
|
+
},
|
|
21
|
+
dependencies: {
|
|
22
|
+
frootjs: '^1.0.1',
|
|
23
|
+
},
|
|
24
|
+
devDependencies: {
|
|
25
|
+
'@types/node': '^22.10.0',
|
|
26
|
+
typescript: '^5.8.0',
|
|
27
|
+
},
|
|
28
|
+
}, null, 2) + '\n',
|
|
29
|
+
'tsconfig.json': COMMON_TSCONFIG,
|
|
30
|
+
'.gitignore': COMMON_GITIGNORE,
|
|
31
|
+
'README.md': `# ${projectName}
|
|
32
|
+
|
|
33
|
+
Froot application built with the **Fullstack JSX & Server-Side Rendering (SSR)** pattern.
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- **Native JSX / TSX**: Pure server-rendered JSX without React runtime baggage
|
|
38
|
+
- **Layout Middleware**: Automatic HTML wrapper layout with \`jsxRenderer()\`
|
|
39
|
+
- **Zero Client JS**: Ultra-fast initial page loads and 100% SEO-friendly markup
|
|
40
|
+
|
|
41
|
+
## Getting Started
|
|
42
|
+
|
|
43
|
+
\`\`\`bash
|
|
44
|
+
# 1. Install dependencies
|
|
45
|
+
pnpm install
|
|
46
|
+
|
|
47
|
+
# 2. Run in development mode
|
|
48
|
+
pnpm run dev
|
|
49
|
+
|
|
50
|
+
# 3. View in browser
|
|
51
|
+
http://localhost:3000
|
|
52
|
+
\`\`\`
|
|
53
|
+
`,
|
|
54
|
+
'src/components/Layout.tsx': `import type { FC, PropsWithChildren } from 'frootjs/jsx';
|
|
55
|
+
|
|
56
|
+
export interface LayoutProps {
|
|
57
|
+
title?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const Layout: FC<PropsWithChildren<LayoutProps>> = ({ title = 'Froot JSX App', children }) => {
|
|
61
|
+
return (
|
|
62
|
+
<html lang="en">
|
|
63
|
+
<head>
|
|
64
|
+
<meta charSet="UTF-8" />
|
|
65
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
66
|
+
<title>{title}</title>
|
|
67
|
+
<style>{\`
|
|
68
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
69
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0f172a; color: #f8fafc; line-height: 1.6; }
|
|
70
|
+
header { background: #1e293b; border-bottom: 1px solid #334155; padding: 1rem 2rem; display: flex; justify-content: space-between; align-items: center; }
|
|
71
|
+
.logo { font-size: 1.3rem; font-weight: bold; color: #10b981; text-decoration: none; }
|
|
72
|
+
nav a { color: #94a3b8; text-decoration: none; margin-left: 1.5rem; font-weight: 500; }
|
|
73
|
+
nav a:hover { color: #f8fafc; }
|
|
74
|
+
main { max-width: 900px; margin: 2rem auto; padding: 0 1.5rem; }
|
|
75
|
+
footer { text-align: center; padding: 2rem; color: #64748b; font-size: 0.9rem; border-top: 1px solid #1e293b; margin-top: 4rem; }
|
|
76
|
+
\`}</style>
|
|
77
|
+
</head>
|
|
78
|
+
<body>
|
|
79
|
+
<header>
|
|
80
|
+
<a href="/" className="logo">Froot JSX</a>
|
|
81
|
+
<nav>
|
|
82
|
+
<a href="/">Home</a>
|
|
83
|
+
<a href="/about">About</a>
|
|
84
|
+
<a href="/features">Features</a>
|
|
85
|
+
</nav>
|
|
86
|
+
</header>
|
|
87
|
+
<main>{children}</main>
|
|
88
|
+
<footer>
|
|
89
|
+
<p>Powered by Froot Server-Side Rendering Engine</p>
|
|
90
|
+
</footer>
|
|
91
|
+
</body>
|
|
92
|
+
</html>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
`,
|
|
96
|
+
'src/components/Card.tsx': `import type { FC, PropsWithChildren } from 'frootjs/jsx';
|
|
97
|
+
|
|
98
|
+
export interface CardProps {
|
|
99
|
+
title: string;
|
|
100
|
+
badge?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const Card: FC<PropsWithChildren<CardProps>> = ({ title, badge, children }) => {
|
|
104
|
+
return (
|
|
105
|
+
<div style={{
|
|
106
|
+
background: '#1e293b',
|
|
107
|
+
border: '1px solid #334155',
|
|
108
|
+
borderRadius: '8px',
|
|
109
|
+
padding: '1.5rem',
|
|
110
|
+
marginBottom: '1.25rem',
|
|
111
|
+
}}>
|
|
112
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.75rem' }}>
|
|
113
|
+
<h3 style={{ color: '#38bdf8', fontSize: '1.2rem' }}>{title}</h3>
|
|
114
|
+
{badge ? (
|
|
115
|
+
<span style={{
|
|
116
|
+
background: '#064e3b',
|
|
117
|
+
color: '#34d399',
|
|
118
|
+
fontSize: '0.75rem',
|
|
119
|
+
padding: '0.2rem 0.6rem',
|
|
120
|
+
borderRadius: '9999px',
|
|
121
|
+
fontWeight: 600,
|
|
122
|
+
}}>
|
|
123
|
+
{badge}
|
|
124
|
+
</span>
|
|
125
|
+
) : null}
|
|
126
|
+
</div>
|
|
127
|
+
<div>{children}</div>
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
`,
|
|
132
|
+
'src/pages/Home.tsx': `import type { FC } from 'frootjs/jsx';
|
|
133
|
+
import { Card } from '../components/Card.js';
|
|
134
|
+
|
|
135
|
+
export const HomePage: FC = () => {
|
|
136
|
+
return (
|
|
137
|
+
<div>
|
|
138
|
+
<div style={{ marginBottom: '2rem' }}>
|
|
139
|
+
<h1 style={{ fontSize: '2.25rem', color: '#10b981', marginBottom: '0.5rem' }}>
|
|
140
|
+
Server-Side Rendered JSX
|
|
141
|
+
</h1>
|
|
142
|
+
<p style={{ color: '#94a3b8', fontSize: '1.1rem' }}>
|
|
143
|
+
Blazing fast HTML generated on the server with TypeScript-native JSX components.
|
|
144
|
+
</p>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<Card title="Zero Client Runtime" badge="Performance">
|
|
148
|
+
<p>No heavy virtual DOM diffing in the browser. Pure, pre-rendered semantic HTML delivered instantly.</p>
|
|
149
|
+
</Card>
|
|
150
|
+
|
|
151
|
+
<Card title="Type-Safe Views" badge="DX">
|
|
152
|
+
<p>Full TypeScript compiler checking for props, children, styles, and HTML attributes.</p>
|
|
153
|
+
</Card>
|
|
154
|
+
|
|
155
|
+
<Card title="Streaming & Islands Ready" badge="Architecture">
|
|
156
|
+
<p>Seamlessly compose asynchronous server components and stream output as it becomes available.</p>
|
|
157
|
+
</Card>
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
};
|
|
161
|
+
`,
|
|
162
|
+
'src/pages/About.tsx': `import type { FC } from 'frootjs/jsx';
|
|
163
|
+
|
|
164
|
+
export const AboutPage: FC = () => {
|
|
165
|
+
return (
|
|
166
|
+
<div style={{ background: '#1e293b', padding: '2rem', borderRadius: '8px', border: '1px solid #334155' }}>
|
|
167
|
+
<h1 style={{ color: '#10b981', marginBottom: '1rem' }}>About This Application</h1>
|
|
168
|
+
<p style={{ marginBottom: '1rem' }}>
|
|
169
|
+
This project showcases Froot's built-in JSX rendering pipeline. Unlike traditional React or Next.js setups,
|
|
170
|
+
Froot renders JSX straight to HTML strings without requiring React, ReactDOM, or a Node.js bundling step.
|
|
171
|
+
</p>
|
|
172
|
+
<p style={{ color: '#94a3b8' }}>
|
|
173
|
+
It achieves sub-millisecond page render times while maintaining full component composition.
|
|
174
|
+
</p>
|
|
175
|
+
</div>
|
|
176
|
+
);
|
|
177
|
+
};
|
|
178
|
+
`,
|
|
179
|
+
'src/server.tsx': `import { Froot } from 'frootjs';
|
|
180
|
+
import { jsxRenderer } from 'frootjs/jsx';
|
|
181
|
+
import { Layout } from './components/Layout.js';
|
|
182
|
+
import { HomePage } from './pages/Home.js';
|
|
183
|
+
import { AboutPage } from './pages/About.js';
|
|
184
|
+
|
|
185
|
+
export const app = new Froot();
|
|
186
|
+
|
|
187
|
+
// Wrap all HTML responses in the global Layout shell
|
|
188
|
+
app.use('*', jsxRenderer(({ children }) => {
|
|
189
|
+
return <Layout>{children}</Layout>;
|
|
190
|
+
}));
|
|
191
|
+
|
|
192
|
+
// Route handlers
|
|
193
|
+
app.get('/', (c) => {
|
|
194
|
+
return c.render(<HomePage />);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
app.get('/about', (c) => {
|
|
198
|
+
return c.render(<AboutPage />);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
app.get('/features', (c) => {
|
|
202
|
+
return c.render(
|
|
203
|
+
<div>
|
|
204
|
+
<h1 style={{ color: '#10b981', marginBottom: '1rem' }}>Framework Features</h1>
|
|
205
|
+
<ul style={{ paddingLeft: '1.5rem', color: '#cbd5e1' }}>
|
|
206
|
+
<li>RADIX tree router with O(K) lookup</li>
|
|
207
|
+
<li>Auto-generated OpenAPI 3.1 & Scalar docs</li>
|
|
208
|
+
<li>Native JSX & async component support</li>
|
|
209
|
+
<li>Full WebCrypto authentication ecosystem</li>
|
|
210
|
+
<li>Universal WebSockets & pub/sub hub</li>
|
|
211
|
+
</ul>
|
|
212
|
+
</div>
|
|
213
|
+
);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const PORT = Number(process.env.PORT) || 3000;
|
|
217
|
+
app.listen(PORT, () => {
|
|
218
|
+
console.log(\`Fullstack JSX server running on http://localhost:\${PORT}\`);
|
|
219
|
+
});
|
|
220
|
+
`,
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
//# sourceMappingURL=fullstack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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,uCAAuC;IAC7C,WAAW,EAAE,yEAAyE;IACtF,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,gDAAgD;oBACrD,KAAK,EAAE,KAAK;oBACZ,KAAK,EAAE,qBAAqB;iBAC7B;gBACD,YAAY,EAAE;oBACZ,OAAO,EAAE,QAAQ;iBAClB;gBACD,eAAe,EAAE;oBACf,aAAa,EAAE,UAAU;oBACzB,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"}
|