@adriankulik/create-fullstack-app 1.0.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +84 -0
  3. package/cli/index.js +170 -0
  4. package/cli/package-lock.json +1338 -0
  5. package/cli/package.json +23 -0
  6. package/package.json +40 -0
  7. package/templates/backend/fastapi/lint.sh +9 -0
  8. package/templates/backend/fastapi/main.py +28 -0
  9. package/templates/backend/fastapi/requirements.txt +5 -0
  10. package/templates/backend/fastapi/start.sh +7 -0
  11. package/templates/backend/fastapi/test.sh +7 -0
  12. package/templates/backend/fastapi/test_main.py +19 -0
  13. package/templates/backend/flask/lint.sh +9 -0
  14. package/templates/backend/flask/main.py +24 -0
  15. package/templates/backend/flask/requirements.txt +5 -0
  16. package/templates/backend/flask/start.sh +7 -0
  17. package/templates/backend/flask/test.sh +7 -0
  18. package/templates/backend/flask/test_main.py +21 -0
  19. package/templates/base/.github/workflows/test.yml +36 -0
  20. package/templates/base/.vscode/extensions.json +8 -0
  21. package/templates/base/GEMINI.md +65 -0
  22. package/templates/base/README.md +37 -0
  23. package/templates/base/gitignore +13 -0
  24. package/templates/base/lint.sh +10 -0
  25. package/templates/base/start.sh +13 -0
  26. package/templates/base/test.sh +10 -0
  27. package/templates/frontend/angular/angular.json +84 -0
  28. package/templates/frontend/angular/karma.conf.js +45 -0
  29. package/templates/frontend/angular/lint.sh +2 -0
  30. package/templates/frontend/angular/package-lock.json +16204 -0
  31. package/templates/frontend/angular/package.json +40 -0
  32. package/templates/frontend/angular/src/app/app.component.spec.ts +24 -0
  33. package/templates/frontend/angular/src/app/app.component.ts +73 -0
  34. package/templates/frontend/angular/src/favicon.ico +0 -0
  35. package/templates/frontend/angular/src/index.html +12 -0
  36. package/templates/frontend/angular/src/main.ts +5 -0
  37. package/templates/frontend/angular/src/styles.css +1 -0
  38. package/templates/frontend/angular/start.sh +2 -0
  39. package/templates/frontend/angular/test.sh +2 -0
  40. package/templates/frontend/angular/tsconfig.app.json +16 -0
  41. package/templates/frontend/angular/tsconfig.json +32 -0
  42. package/templates/frontend/angular/tsconfig.spec.json +14 -0
  43. package/templates/frontend/nextjs/.eslintrc.json +3 -0
  44. package/templates/frontend/nextjs/__tests__/page.test.tsx +39 -0
  45. package/templates/frontend/nextjs/app/layout.tsx +18 -0
  46. package/templates/frontend/nextjs/app/page.tsx +69 -0
  47. package/templates/frontend/nextjs/jest.config.js +16 -0
  48. package/templates/frontend/nextjs/jest.setup.js +1 -0
  49. package/templates/frontend/nextjs/lint.sh +3 -0
  50. package/templates/frontend/nextjs/next.config.js +4 -0
  51. package/templates/frontend/nextjs/package-lock.json +9631 -0
  52. package/templates/frontend/nextjs/package.json +31 -0
  53. package/templates/frontend/nextjs/start.sh +2 -0
  54. package/templates/frontend/nextjs/test.sh +2 -0
  55. package/templates/frontend/nextjs/tsconfig.json +27 -0
  56. package/templates/frontend/svelte/.eslintrc.cjs +27 -0
  57. package/templates/frontend/svelte/index.html +12 -0
  58. package/templates/frontend/svelte/lint.sh +3 -0
  59. package/templates/frontend/svelte/package-lock.json +6129 -0
  60. package/templates/frontend/svelte/package.json +30 -0
  61. package/templates/frontend/svelte/src/App.spec.ts +36 -0
  62. package/templates/frontend/svelte/src/App.svelte +61 -0
  63. package/templates/frontend/svelte/src/main.ts +8 -0
  64. package/templates/frontend/svelte/src/setupTests.ts +1 -0
  65. package/templates/frontend/svelte/src/svelte-env.d.ts +2 -0
  66. package/templates/frontend/svelte/start.sh +2 -0
  67. package/templates/frontend/svelte/svelte.config.js +5 -0
  68. package/templates/frontend/svelte/test.sh +2 -0
  69. package/templates/frontend/svelte/tsconfig.json +9 -0
  70. package/templates/frontend/svelte/vite.config.ts +15 -0
  71. package/templates/frontend/vue/.eslintrc.cjs +18 -0
  72. package/templates/frontend/vue/index.html +12 -0
  73. package/templates/frontend/vue/lint.sh +3 -0
  74. package/templates/frontend/vue/package-lock.json +5110 -0
  75. package/templates/frontend/vue/package.json +30 -0
  76. package/templates/frontend/vue/src/App.vue +61 -0
  77. package/templates/frontend/vue/src/__tests__/App.spec.ts +37 -0
  78. package/templates/frontend/vue/src/main.ts +4 -0
  79. package/templates/frontend/vue/src/vite-env.d.ts +7 -0
  80. package/templates/frontend/vue/start.sh +2 -0
  81. package/templates/frontend/vue/test.sh +2 -0
  82. package/templates/frontend/vue/tsconfig.json +12 -0
  83. package/templates/frontend/vue/vite.config.ts +14 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Adrian Kulik
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 ADDED
@@ -0,0 +1,84 @@
1
+ # create-fullstack-app
2
+
3
+ A CLI tool for scaffolding a full-stack web application with your choice of frontend and backend technologies. The generated projects use `npm ci` and pinned Python dependencies to ensure fully deterministic and reproducible installations.
4
+
5
+ ## Prerequisites
6
+
7
+ Before running the CLI or the scaffolded applications, ensure you have the following installed on your system:
8
+ - **Node.js**: v20 or newer
9
+ - **npm**: v10 or newer
10
+ - **Python**: v3.11 or newer
11
+
12
+ ## Quickstart
13
+
14
+ Run the CLI tool directly using Node.js:
15
+
16
+ ```bash
17
+ cd cli
18
+ npm install
19
+ node index.js
20
+ ```
21
+
22
+ You will be prompted to choose a project name, your preferred frontend, and backend framework.
23
+
24
+ ## Features
25
+
26
+ - **Frontend Options**:
27
+ - Next.js (v16.2.4)
28
+ - Angular (v21.0.0) - *Configured with Zone.js*
29
+ - Vue (v3.5.33)
30
+ - Svelte (v5.55.5)
31
+ - **Backend Options**:
32
+ - FastAPI (v0.136.1)
33
+ - Flask (v3.1.3)
34
+ - **Opinionated Defaults**: We bake in sensible, predefined choices (e.g., Angular uses `zone.js`, testing is unified under Playwright and framework-native test runners).
35
+ - **Unified Scripts**: `start.sh`, `test.sh`, and `lint.sh` available out of the box to manage both frontend and backend seamlessly.
36
+ - **CI/CD Ready**: Includes a pre-configured `.github/workflows/cli-e2e.yml` that tests both ends. *Tip: To enforce this, enable branch protection in your GitHub repository settings and require the "test" status check to pass.*
37
+ - **Developer Experience**: Includes `.vscode/extensions.json` recommending the necessary linters and formatters, and a `GEMINI.md` file providing behavioral guidelines for AI agents (based on [andrej-karpathy-skills](https://github.com/forrestchang/andrej-karpathy-skills)).
38
+
39
+ ## Generated Project
40
+
41
+ The generated application will look like this:
42
+
43
+ ```
44
+ my-app/
45
+ ├── .github/
46
+ ├── .vscode/
47
+ ├── backend/
48
+ │ ├── main.py
49
+ │ ├── test_main.py
50
+ │ └── requirements.txt
51
+ ├── frontend/
52
+ │ ├── app/ (or src/)
53
+ │ └── package.json
54
+ ├── start.sh
55
+ ├── test.sh
56
+ └── lint.sh
57
+ ```
58
+
59
+ *Note: Depending on your environment, you may need to ensure the generated shell scripts are executable by running `chmod +x *.sh` inside your new project directory.*
60
+
61
+ ## Local E2E Testing
62
+
63
+ You can automatically test all frontend and backend permutations locally via **Playwright** integration tests using the provided script in the root directory.
64
+
65
+ Ensure you make the script executable first:
66
+
67
+ ```bash
68
+ chmod +x run_e2e.sh
69
+ ```
70
+
71
+ Then run it:
72
+
73
+ ```bash
74
+ ./run_e2e.sh
75
+ ```
76
+
77
+ **Note for Windows Users:** The `run_e2e.sh` script utilizes Unix commands (like `lsof` and `kill -9`) for process teardown. You must run this script inside a **WSL** (Windows Subsystem for Linux) or **Git Bash** terminal.
78
+
79
+ ## Roadmap
80
+
81
+ Future plans for this CLI include:
82
+
83
+ - Adding frontend framework-specific component libraries during the scaffold step.
84
+ - Tackling **.NET** as a new backend option.
package/cli/index.js ADDED
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+
3
+ const prompts = require('prompts');
4
+ const pc = require('picocolors');
5
+ const fs = require('fs-extra');
6
+ const path = require('path');
7
+ const { execSync } = require('child_process');
8
+
9
+ async function main() {
10
+ console.log(pc.cyan('\nWelcome to create-fullstack-app!\n'));
11
+
12
+ // Simple argument parsing
13
+ const args = process.argv.slice(2);
14
+ let argProjectName = args[0] && !args[0].startsWith('--') ? args[0] : null;
15
+ let argFrontend = null;
16
+ let argBackend = null;
17
+
18
+ for (let i = 0; i < args.length; i++) {
19
+ if (args[i] === '--frontend' && args[i + 1]) argFrontend = args[i + 1];
20
+ if (args[i] === '--backend' && args[i + 1]) argBackend = args[i + 1];
21
+ }
22
+
23
+ const questions = [];
24
+ if (!argProjectName) {
25
+ questions.push({
26
+ type: 'text',
27
+ name: 'projectName',
28
+ message: 'What is your project named?',
29
+ initial: 'my-fullstack-app',
30
+ validate: value => value.trim().length > 0 ? true : 'Project name cannot be empty'
31
+ });
32
+ }
33
+
34
+ if (!argFrontend) {
35
+ questions.push({
36
+ type: 'select',
37
+ name: 'frontend',
38
+ message: 'Which frontend framework would you like to use?',
39
+ choices: [
40
+ { title: 'Next.js', value: 'nextjs', description: 'React framework' },
41
+ { title: 'Angular', value: 'angular', description: 'Enterprise-grade platform' },
42
+ { title: 'Vue', value: 'vue', description: 'Progressive JavaScript framework' },
43
+ { title: 'Svelte', value: 'svelte', description: 'Cybernetically enhanced web apps' }
44
+ ],
45
+ initial: 0
46
+ });
47
+ }
48
+
49
+ if (!argBackend) {
50
+ questions.push({
51
+ type: 'select',
52
+ name: 'backend',
53
+ message: 'Which backend framework would you like to use?',
54
+ choices: [
55
+ { title: 'FastAPI', value: 'fastapi', description: 'Modern, fast Python web framework' },
56
+ { title: 'Flask', value: 'flask', description: 'Lightweight WSGI web application framework' }
57
+ ],
58
+ initial: 0
59
+ });
60
+ }
61
+
62
+ const response = await prompts(questions);
63
+
64
+ const projectName = argProjectName || response.projectName;
65
+ const frontend = argFrontend || response.frontend;
66
+ const backend = argBackend || response.backend;
67
+
68
+ if (!projectName || !frontend || !backend) {
69
+ console.log(pc.red('Setup cancelled.'));
70
+ process.exit(1);
71
+ }
72
+ const targetDir = path.resolve(process.cwd(), projectName);
73
+
74
+ if (fs.existsSync(targetDir)) {
75
+ console.log(pc.red(`Directory ${projectName} already exists.`));
76
+ process.exit(1);
77
+ }
78
+
79
+ console.log(pc.blue(`\nScaffolding project in ${targetDir}...`));
80
+
81
+ // Determine paths to templates relative to the CLI script
82
+ const templatesDir = path.resolve(__dirname, '../templates');
83
+ const baseDir = path.join(templatesDir, 'base');
84
+ const frontendDir = path.join(templatesDir, 'frontend', frontend);
85
+ const backendDir = path.join(templatesDir, 'backend', backend);
86
+
87
+ try {
88
+ // 1. Copy base template
89
+ await fs.copy(baseDir, targetDir);
90
+ if (fs.existsSync(path.join(targetDir, 'gitignore'))) {
91
+ await fs.rename(path.join(targetDir, 'gitignore'), path.join(targetDir, '.gitignore'));
92
+ }
93
+
94
+ // 2. Copy frontend
95
+ const targetFrontend = path.join(targetDir, 'frontend');
96
+ await fs.copy(frontendDir, targetFrontend);
97
+
98
+ // 3. Copy backend
99
+ const targetBackend = path.join(targetDir, 'backend');
100
+ await fs.copy(backendDir, targetBackend);
101
+
102
+ // 4. Update package.json name for the frontend
103
+ const pkgPath = path.join(targetFrontend, 'package.json');
104
+ if (fs.existsSync(pkgPath)) {
105
+ const pkg = await fs.readJson(pkgPath);
106
+ pkg.name = `${projectName}-frontend`;
107
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
108
+ }
109
+
110
+ // 5. Make all shell scripts executable
111
+ const makeExecutable = (dir) => {
112
+ const files = fs.readdirSync(dir);
113
+ files.forEach(file => {
114
+ const filePath = path.join(dir, file);
115
+ if (fs.statSync(filePath).isDirectory()) {
116
+ makeExecutable(filePath);
117
+ } else if (file.endsWith('.sh')) {
118
+ fs.chmodSync(filePath, 0o755);
119
+ }
120
+ });
121
+ };
122
+ makeExecutable(targetDir);
123
+
124
+ // 6. Install dependencies
125
+ console.log(pc.blue('\nInstalling dependencies (this may take a minute)...'));
126
+
127
+ // Frontend installation
128
+ console.log(pc.cyan(' Installing frontend dependencies...'));
129
+ execSync('npm ci', { cwd: targetFrontend, stdio: 'inherit' });
130
+
131
+ // Backend installation
132
+ console.log(pc.cyan(' Setting up backend virtual environment...'));
133
+ const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
134
+ try {
135
+ execSync(`${pythonCmd} -m venv venv`, { cwd: targetBackend, stdio: 'inherit' });
136
+
137
+ const pipPath = process.platform === 'win32'
138
+ ? path.join('venv', 'Scripts', 'pip')
139
+ : path.join('venv', 'bin', 'pip');
140
+
141
+ console.log(pc.cyan(' Installing backend dependencies...'));
142
+ execSync(`${pipPath} install -r requirements.txt`, { cwd: targetBackend, stdio: 'inherit' });
143
+ } catch (e) {
144
+ console.log(pc.yellow(' Could not set up Python virtual environment automatically. Please set it up manually.'));
145
+ }
146
+
147
+ console.log(pc.green(`\nSuccess! Created ${projectName} at ${targetDir}`));
148
+ console.log('\nInside that directory, you can run several commands:\n');
149
+
150
+ console.log(` ${pc.cyan('./start.sh')}`);
151
+ console.log(' Starts both the backend and frontend development servers.\n');
152
+
153
+ console.log(` ${pc.cyan('./test.sh')}`);
154
+ console.log(' Runs tests for both frontend and backend.\n');
155
+
156
+ console.log(` ${pc.cyan('./lint.sh')}`);
157
+ console.log(' Lints and formats both frontend and backend code.\n');
158
+
159
+ console.log('\nWe suggest that you begin by typing:\n');
160
+ console.log(pc.cyan(` cd ${projectName}`));
161
+ console.log(pc.cyan(' ./start.sh'));
162
+ console.log('\nHappy coding!');
163
+
164
+ } catch (error) {
165
+ console.error(pc.red('Error scaffolding project:'), error);
166
+ process.exit(1);
167
+ }
168
+ }
169
+
170
+ main().catch(console.error);