@totaland/create-starter-kit 2.0.1 → 2.0.3

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/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # @totaland/create-starter-kit
2
2
 
3
- Scaffolding tool for creating new starter-kit projects with a choice between backend and frontend templates.
3
+ Scaffolding tool for creating new starter-kit projects with a choice between backend, frontend, or fullstack templates.
4
4
 
5
5
  ## Features
6
6
 
7
- - ✨ Interactive template selection (backend or frontend)
7
+ - ✨ Interactive template selection (backend, frontend, or fullstack)
8
8
  - 🎯 CLI argument support for automation
9
9
  - 📦 Clean, production-ready templates
10
10
  - 🚀 Quick project initialization
@@ -20,6 +20,7 @@ pnpm create @totaland/starter-kit my-new-project
20
20
  You'll be prompted to select a template:
21
21
  - **Backend** - Express.js + TypeScript + Drizzle ORM + Scalar API docs
22
22
  - **Frontend** - React + Vite + TypeScript + Tailwind CSS v4 + shadcn/ui + TanStack Query
23
+ - **Fullstack** - Both Backend and Frontend in one project
23
24
 
24
25
  ### With Template Argument
25
26
 
@@ -31,6 +32,9 @@ pnpm create @totaland/starter-kit my-backend backend
31
32
 
32
33
  # Create frontend project
33
34
  pnpm create @totaland/starter-kit my-frontend frontend
35
+
36
+ # Create fullstack project (both backend and frontend)
37
+ pnpm create @totaland/starter-kit my-app fullstack
34
38
  ```
35
39
 
36
40
  ### Alternative Package Managers
@@ -107,10 +111,29 @@ pnpm dev
107
111
  pnpm dlx shadcn@latest add button card dialog
108
112
  ```
109
113
 
114
+ ### Fullstack Template
115
+
116
+ Creates both backend and frontend in separate subdirectories.
117
+
118
+ **After Creation:**
119
+ ```bash
120
+ cd my-app
121
+
122
+ # Run backend
123
+ cd backend
124
+ pnpm install
125
+ pnpm dev
126
+
127
+ # Run frontend (in another terminal)
128
+ cd frontend
129
+ pnpm install
130
+ pnpm dev
131
+ ```
132
+
110
133
  ## What It Does
111
134
 
112
135
  1. ✅ Creates a new directory with your project name
113
- 2. ✅ Copies the selected template (backend or frontend)
136
+ 2. ✅ Copies the selected template (backend, frontend, or both for fullstack)
114
137
  3. ✅ Updates the `package.json` name field to match your project name
115
138
  4. ✅ Provides next steps for installation and running the project
116
139
 
@@ -139,6 +162,7 @@ To test this locally before publishing:
139
162
  # Or specify template directly
140
163
  pnpm create @totaland/starter-kit test-backend backend
141
164
  pnpm create @totaland/starter-kit test-frontend frontend
165
+ pnpm create @totaland/starter-kit test-fullstack fullstack
142
166
  ```
143
167
 
144
168
  ## Publishing
package/bin/index.js CHANGED
@@ -21,7 +21,7 @@ const templateArg = process.argv[3]; // Optional template argument
21
21
  if (!projectName) {
22
22
  console.error('Error: Please provide a project name');
23
23
  console.log('Usage: pnpm create @totaland/starter-kit <project-name> [template]');
24
- console.log('Templates: backend, frontend');
24
+ console.log('Templates: backend, frontend, fullstack');
25
25
  process.exit(1);
26
26
  }
27
27
 
@@ -47,8 +47,30 @@ const TEMPLATES = {
47
47
  description: 'React + Vite with TypeScript, Tailwind CSS v4, shadcn/ui, and TanStack Query',
48
48
  dir: 'frontend',
49
49
  },
50
+ fullstack: {
51
+ name: 'Fullstack',
52
+ description: 'Both Backend and Frontend templates combined',
53
+ dirs: ['backend', 'frontend'],
54
+ },
50
55
  };
51
56
 
57
+ // Directories and files to exclude when copying
58
+ const EXCLUDE = new Set([
59
+ 'node_modules',
60
+ '.git',
61
+ 'dist',
62
+ 'build',
63
+ '.turbo',
64
+ '.next',
65
+ '.nuxt',
66
+ '.output',
67
+ '.cache',
68
+ 'coverage',
69
+ '.env',
70
+ '.env.local',
71
+ '.DS_Store',
72
+ ]);
73
+
52
74
  // Function to recursively copy directory
53
75
  function copyDir(src, dest) {
54
76
  mkdirSync(dest, { recursive: true });
@@ -56,6 +78,11 @@ function copyDir(src, dest) {
56
78
  const entries = readdirSync(src, { withFileTypes: true });
57
79
 
58
80
  for (const entry of entries) {
81
+ // Skip excluded files and directories
82
+ if (EXCLUDE.has(entry.name)) {
83
+ continue;
84
+ }
85
+
59
86
  const srcPath = join(src, entry.name);
60
87
  const destPath = join(dest, entry.name);
61
88
 
@@ -75,10 +102,11 @@ async function promptTemplate() {
75
102
  });
76
103
 
77
104
  console.log('\n📦 Select a template:\n');
78
- console.log('1. Backend - Express.js + TypeScript + Drizzle ORM');
79
- console.log('2. Frontend - React + Vite + Tailwind CSS v4 + shadcn/ui\n');
105
+ console.log('1. Backend - Express.js + TypeScript + Drizzle ORM');
106
+ console.log('2. Frontend - React + Vite + Tailwind CSS v4 + shadcn/ui');
107
+ console.log('3. Fullstack - Both Backend and Frontend\n');
80
108
 
81
- const answer = await rl.question('Enter your choice (1 or 2): ');
109
+ const answer = await rl.question('Enter your choice (1, 2, or 3): ');
82
110
  rl.close();
83
111
 
84
112
  if (answer === '1' || answer.toLowerCase() === 'backend') {
@@ -87,6 +115,9 @@ async function promptTemplate() {
87
115
  if (answer === '2' || answer.toLowerCase() === 'frontend') {
88
116
  return 'frontend';
89
117
  }
118
+ if (answer === '3' || answer.toLowerCase() === 'fullstack') {
119
+ return 'fullstack';
120
+ }
90
121
 
91
122
  console.error('Invalid choice. Please run the command again.');
92
123
  process.exit(1);
@@ -102,7 +133,7 @@ async function main() {
102
133
  templateKey = templateArg.toLowerCase();
103
134
  if (!TEMPLATES[templateKey]) {
104
135
  console.error(`Error: Invalid template "${templateArg}"`);
105
- console.log('Available templates: backend, frontend');
136
+ console.log('Available templates: backend, frontend, fullstack');
106
137
  process.exit(1);
107
138
  }
108
139
  } else {
@@ -111,37 +142,63 @@ async function main() {
111
142
  }
112
143
 
113
144
  const template = TEMPLATES[templateKey];
114
- const templateDir = join(templatesDir, template.dir);
115
-
116
- // Verify template directory exists
117
- if (!existsSync(templateDir)) {
118
- console.error(`Error: Template directory not found: ${templateDir}`);
119
- process.exit(1);
120
- }
121
145
 
122
146
  console.log(`\n🚀 Creating ${template.name} project: ${projectName}`);
123
147
  console.log(`📁 ${template.description}\n`);
124
148
 
125
- // Copy template to target directory
126
- copyDir(templateDir, targetDir);
127
-
128
- // Update package.json with the new project name
129
- const packageJsonPath = join(targetDir, 'package.json');
130
- if (existsSync(packageJsonPath)) {
131
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
132
- packageJson.name = projectName;
133
- writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
149
+ // Handle fullstack (multiple templates) or single template
150
+ if (template.dirs) {
151
+ // Fullstack: copy each template to a subdirectory
152
+ for (const dir of template.dirs) {
153
+ const templateDir = join(templatesDir, dir);
154
+ if (!existsSync(templateDir)) {
155
+ console.error(`Error: Template directory not found: ${templateDir}`);
156
+ process.exit(1);
157
+ }
158
+ const subTargetDir = join(targetDir, dir);
159
+ copyDir(templateDir, subTargetDir);
160
+
161
+ // Update package.json name for each sub-project
162
+ const packageJsonPath = join(subTargetDir, 'package.json');
163
+ if (existsSync(packageJsonPath)) {
164
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
165
+ packageJson.name = `${projectName}-${dir}`;
166
+ writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
167
+ }
168
+ }
169
+ } else {
170
+ // Single template
171
+ const templateDir = join(templatesDir, template.dir);
172
+ if (!existsSync(templateDir)) {
173
+ console.error(`Error: Template directory not found: ${templateDir}`);
174
+ process.exit(1);
175
+ }
176
+ copyDir(templateDir, targetDir);
177
+
178
+ // Update package.json with the new project name
179
+ const packageJsonPath = join(targetDir, 'package.json');
180
+ if (existsSync(packageJsonPath)) {
181
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
182
+ packageJson.name = projectName;
183
+ writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
184
+ }
134
185
  }
135
186
 
136
187
  console.log('✅ Project created successfully!\n');
137
188
  console.log('📝 Next steps:');
138
189
  console.log(` cd ${projectName}`);
139
- console.log(' pnpm install');
140
- console.log(' pnpm dev\n');
190
+ if (templateKey === 'fullstack') {
191
+ console.log(' cd backend && pnpm install && pnpm dev');
192
+ console.log(' cd frontend && pnpm install && pnpm dev\n');
193
+ } else {
194
+ console.log(' pnpm install');
195
+ console.log(' pnpm dev\n');
196
+ }
141
197
 
142
- if (templateKey === 'frontend') {
198
+ if (templateKey === 'frontend' || templateKey === 'fullstack') {
143
199
  console.log('💡 Tip: Add shadcn/ui components with:');
144
- console.log(' pnpm dlx shadcn@latest add button card dialog\n');
200
+ const cdPath = templateKey === 'fullstack' ? 'cd frontend && ' : '';
201
+ console.log(` ${cdPath}pnpm dlx shadcn@latest add button card dialog\n`);
145
202
  }
146
203
  } catch (error) {
147
204
  console.error('Error creating project:', error.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@totaland/create-starter-kit",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Scaffolding tool for creating new starter-kit projects",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -13,6 +13,10 @@
13
13
  "bin",
14
14
  "templates"
15
15
  ],
16
+ "scripts": {
17
+ "sync-templates": "node scripts/sync-templates.js",
18
+ "prepublishOnly": "node scripts/sync-templates.js"
19
+ },
16
20
  "keywords": [
17
21
  "starter-kit",
18
22
  "scaffold",
@@ -21,4 +25,4 @@
21
25
  "dependencies": {
22
26
  "fast-glob": "^3.3.2"
23
27
  }
24
- }
28
+ }