initkit 1.2.1 → 1.2.2

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
@@ -751,6 +751,34 @@ initkit my-app --verbose
751
751
 
752
752
  ---
753
753
 
754
+ ## Recent Updates
755
+
756
+ ### Version 1.2.2 (January 2026)
757
+
758
+ **Critical Bug Fixes:**
759
+
760
+ - ✅ **Fixed Tailwind CSS installation** - Resolved issue where styling was not installed if no other addons were selected
761
+ - ✅ **Fixed package manager compatibility** - All 4 package managers (npm, yarn, pnpm, bun) now work correctly with Tailwind CSS
762
+ - ✅ **Fixed Next.js duplicate configs** - Prevents duplicate Tailwind config files in Next.js projects
763
+ - ✅ **Improved file creation** - Uses proper fs-extra methods for reliable config file generation
764
+
765
+ **What's Fixed:**
766
+
767
+ - `hasAddons()` function now properly checks for styling configuration
768
+ - Changed from unreliable `npx tailwindcss init` to direct config file creation
769
+ - All package managers tested and verified working
770
+ - Next.js now uses built-in Tailwind setup (no duplicates)
771
+
772
+ **Testing:**
773
+
774
+ - ✅ 4/4 package managers passing tests (npm, yarn, pnpm, bun)
775
+ - ✅ Verified across React+Vite, Next.js, and Vue.js
776
+ - ✅ No duplicate configuration files
777
+
778
+ [View Full Changelog](./docs/CHANGELOG.md)
779
+
780
+ ---
781
+
754
782
  ## Contributing
755
783
 
756
784
  We welcome contributions! InitKit has comprehensive documentation to help you get started.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "initkit",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "type": "module",
5
5
  "description": "A modern CLI tool for scaffolding production-ready web projects with live npm version fetching, multiple frameworks, and best practices built-in",
6
6
  "main": "src/index.js",
@@ -61,16 +61,17 @@
61
61
  "dependencies": {
62
62
  "chalk": "^5.3.0",
63
63
  "commander": "^12.0.0",
64
+ "ejs": "^3.1.9",
65
+ "fs-extra": "^11.2.0",
66
+ "initkit": "^1.2.1",
64
67
  "inquirer": "^9.2.15",
65
68
  "ora": "^8.0.1",
66
- "fs-extra": "^11.2.0",
67
- "ejs": "^3.1.9",
68
69
  "validate-npm-package-name": "^5.0.0"
69
70
  },
70
71
  "devDependencies": {
72
+ "@types/node": "^20.11.5",
71
73
  "eslint": "^8.56.0",
72
- "prettier": "^3.2.4",
73
74
  "jest": "^29.7.0",
74
- "@types/node": "^20.11.5"
75
+ "prettier": "^3.2.4"
75
76
  }
76
77
  }
@@ -239,115 +239,4 @@ function getInstallCommand(packageManager) {
239
239
  return commands[packageManager] || 'npm install';
240
240
  }
241
241
 
242
- /** * Display comprehensive success summary after project creation (LEGACY - DEPRECATED)
243
- * This function is kept for backward compatibility but is no longer used
244
- * @deprecated Use displaySuccessMessage instead
245
- */
246
- function displaySuccessSummary(answers, projectPath, _verbose = false) {
247
- console.log('');
248
- console.log(chalk.green('╔════════════════════════════════════════════════════════════╗'));
249
- console.log(
250
- chalk.green('║') +
251
- chalk.green.bold(' ✨ Project Created Successfully! ✨ ') +
252
- chalk.green('║')
253
- );
254
- console.log(chalk.green('╚════════════════════════════════════════════════════════════╝'));
255
- console.log('');
256
-
257
- // Project info section
258
- console.log(chalk.cyan.bold(' 📦 Project Information'));
259
- console.log(chalk.white(` ${chalk.gray('Name:')} ${chalk.bold(answers.projectName)}`));
260
- console.log(chalk.white(` ${chalk.gray('Type:')} ${answers.projectType}`));
261
- console.log(
262
- chalk.white(` ${chalk.gray('Language:')} ${answers.language || 'JavaScript'}`)
263
- );
264
-
265
- if (answers.frontend) {
266
- console.log(chalk.white(` ${chalk.gray('Frontend:')} ${answers.frontend}`));
267
- }
268
-
269
- if (answers.backend) {
270
- console.log(chalk.white(` ${chalk.gray('Backend:')} ${answers.backend}`));
271
- }
272
-
273
- if (answers.database && answers.database !== 'none') {
274
- console.log(chalk.white(` ${chalk.gray('Database:')} ${answers.database}`));
275
- }
276
- console.log('');
277
-
278
- // Location section
279
- console.log(chalk.cyan.bold(' 📁 Project Location'));
280
- console.log(chalk.white(` ${projectPath}`));
281
- console.log('');
282
-
283
- // Features section
284
- if (answers.features && answers.features.length > 0) {
285
- console.log(chalk.cyan.bold(' ⚙️ Configured Features'));
286
- answers.features.forEach((feature) => {
287
- console.log(chalk.white(` ${chalk.green('✓')} ${feature}`));
288
- });
289
- console.log('');
290
- }
291
-
292
- // Additional libraries
293
- if (answers.additionalLibraries && answers.additionalLibraries.length > 0) {
294
- console.log(chalk.cyan.bold(' 📚 Additional Libraries'));
295
- answers.additionalLibraries.slice(0, 5).forEach((lib) => {
296
- console.log(chalk.white(` ${chalk.green('✓')} ${lib}`));
297
- });
298
- if (answers.additionalLibraries.length > 5) {
299
- console.log(chalk.gray(` ... and ${answers.additionalLibraries.length - 5} more`));
300
- }
301
- console.log('');
302
- }
303
-
304
- // Package manager info
305
- const packagesInstalled = answers.installDependencies !== false;
306
- if (packagesInstalled) {
307
- console.log(chalk.cyan.bold(' 📦 Dependencies'));
308
- console.log(chalk.white(` ${chalk.green('✓')} Installed with ${answers.packageManager}`));
309
- console.log('');
310
- }
311
-
312
- // Next steps
313
- console.log(chalk.cyan.bold(' 🚀 Next Steps'));
314
- console.log('');
315
- console.log(chalk.white(` ${chalk.yellow('1.')} Navigate to your project:`));
316
- console.log(chalk.gray(` cd ${answers.projectName}`));
317
- console.log('');
318
-
319
- if (!packagesInstalled) {
320
- console.log(chalk.white(` ${chalk.yellow('2.')} Install dependencies:`));
321
- console.log(chalk.gray(` ${answers.packageManager} install`));
322
- console.log('');
323
- }
324
-
325
- const stepNum = packagesInstalled ? 2 : 3;
326
- console.log(chalk.white(` ${chalk.yellow(stepNum + '.')} Start development server:`));
327
- console.log(
328
- chalk.gray(
329
- ` ${answers.packageManager} ${answers.packageManager === 'npm' ? 'run ' : ''}dev`
330
- )
331
- );
332
- console.log('');
333
-
334
- console.log(
335
- chalk.white(` ${chalk.yellow(stepNum + 1 + '.')} Read the README for more info:`)
336
- );
337
- console.log(chalk.gray(` cat README.md`));
338
- console.log('');
339
-
340
- // Documentation link
341
- console.log(chalk.cyan.bold(' 📚 Documentation'));
342
- console.log(chalk.white(` Check out the README.md in your project folder`));
343
- console.log(chalk.white(` for setup instructions and best practices.`));
344
- console.log('');
345
-
346
- // Footer
347
- console.log(chalk.green(' ─────────────────────────────────────────────────────────────'));
348
- console.log(chalk.green.bold(' 🎉 Happy coding! Your project is ready! 🎉'));
349
- console.log(chalk.green(' ─────────────────────────────────────────────────────────────'));
350
- console.log('');
351
- }
352
-
353
242
  export { createProject };
@@ -1,5 +1,4 @@
1
1
  import chalk from 'chalk';
2
- import validateNpmName from 'validate-npm-package-name';
3
2
  import {
4
3
  validateProjectName,
5
4
  checkDirectoryExists,
@@ -24,13 +24,19 @@ export async function installAddons(projectPath, config) {
24
24
  additionalLibraries = [],
25
25
  } = config;
26
26
 
27
+ // Styling (MUST be installed before UI libraries like shadcn)
28
+ if (styling && styling !== 'none' && styling !== 'css') {
29
+ console.log(chalk.cyan('\n🎨 Installing styling solution...'));
30
+ await installStyling(projectPath, styling, config);
31
+ }
32
+
27
33
  // State Management
28
34
  if (stateManagement && stateManagement !== 'none') {
29
35
  console.log(chalk.cyan('\n📦 Installing state management...'));
30
36
  await installStateManagement(projectPath, stateManagement, config);
31
37
  }
32
38
 
33
- // UI Library
39
+ // UI Library (must come AFTER styling, especially for shadcn which needs Tailwind)
34
40
  if (uiLibrary && uiLibrary !== 'none') {
35
41
  console.log(chalk.cyan('\n🎨 Installing UI library...'));
36
42
  await installUILibrary(projectPath, uiLibrary, config);
@@ -104,20 +110,143 @@ async function installStateManagement(projectPath, library, config) {
104
110
  }
105
111
  }
106
112
 
113
+ /**
114
+ * Install styling solution
115
+ */
116
+ async function installStyling(projectPath, styling, config) {
117
+ const { packageManager, frontend } = config;
118
+ const installCmd = getInstallCommand(packageManager);
119
+
120
+ switch (styling) {
121
+ case 'tailwind': {
122
+ // Next.js already includes Tailwind CSS when --tailwind flag is used
123
+ if (frontend === 'nextjs') {
124
+ console.log(chalk.dim(' Tailwind CSS already configured by Next.js'));
125
+ return;
126
+ }
127
+
128
+ console.log(chalk.dim(' Installing Tailwind CSS...'));
129
+ await execCommand(`${installCmd} -D tailwindcss postcss autoprefixer`, {
130
+ cwd: projectPath,
131
+ });
132
+
133
+ // Create Tailwind config files directly (more reliable than running init command)
134
+ console.log(chalk.dim(' Initializing Tailwind configuration...'));
135
+ const fs = await import('fs-extra');
136
+ const path = await import('path');
137
+
138
+ // Create tailwind.config.js with proper content paths
139
+ const tailwindConfigPath = path.join(projectPath, 'tailwind.config.js');
140
+ const tailwindConfig = `/** @type {import('tailwindcss').Config} */
141
+ export default {
142
+ content: [
143
+ "./index.html",
144
+ "./src/**/*.{js,ts,jsx,tsx}",
145
+ ],
146
+ theme: {
147
+ extend: {},
148
+ },
149
+ plugins: [],
150
+ }`;
151
+ await fs.outputFile(tailwindConfigPath, tailwindConfig);
152
+
153
+ // Create postcss.config.js
154
+ const postcssConfigPath = path.join(projectPath, 'postcss.config.js');
155
+ const postcssConfig = `export default {
156
+ plugins: {
157
+ tailwindcss: {},
158
+ autoprefixer: {},
159
+ },
160
+ }`;
161
+ await fs.outputFile(postcssConfigPath, postcssConfig);
162
+
163
+ // For Vite projects, update the main CSS file
164
+ if (frontend === 'react' || frontend === 'vue') {
165
+ // Create/update main CSS file with Tailwind directives
166
+ const cssPath = path.join(projectPath, 'src', 'index.css');
167
+ const tailwindDirectives = `@tailwind base;
168
+ @tailwind components;
169
+ @tailwind utilities;
170
+ `;
171
+ await fs.outputFile(cssPath, tailwindDirectives);
172
+ }
173
+ break;
174
+ }
175
+
176
+ case 'scss':
177
+ case 'sass':
178
+ console.log(chalk.dim(' Installing Sass...'));
179
+ await execCommand(`${installCmd} -D sass`, { cwd: projectPath });
180
+ break;
181
+
182
+ case 'styled-components':
183
+ console.log(chalk.dim(' Installing Styled Components...'));
184
+ await execCommand(`${installCmd} styled-components`, { cwd: projectPath });
185
+ if (config.language === 'typescript') {
186
+ await execCommand(`${installCmd} -D @types/styled-components`, {
187
+ cwd: projectPath,
188
+ });
189
+ }
190
+ break;
191
+
192
+ case 'emotion':
193
+ console.log(chalk.dim(' Installing Emotion...'));
194
+ await execCommand(`${installCmd} @emotion/react @emotion/styled`, {
195
+ cwd: projectPath,
196
+ });
197
+ break;
198
+
199
+ case 'css-modules':
200
+ // CSS Modules are built into Vite and Next.js, no installation needed
201
+ console.log(chalk.dim(' CSS Modules are built-in, no installation needed'));
202
+ break;
203
+
204
+ default:
205
+ console.log(chalk.yellow(` Unknown styling solution: ${styling}`));
206
+ }
207
+ }
208
+
107
209
  /**
108
210
  * Install UI library (some have their own CLIs!)
109
211
  */
110
212
  async function installUILibrary(projectPath, library, config) {
111
- const { packageManager, language } = config;
213
+ const { packageManager } = config;
112
214
  const installCmd = getInstallCommand(packageManager);
113
215
 
114
216
  switch (library) {
115
217
  case 'shadcn':
116
- case 'shadcn-ui':
218
+ case 'shadcn-ui': {
117
219
  console.log(chalk.dim(' Running shadcn-ui init...'));
118
- // shadcn has its own CLI!
119
- await execCommand(`npx shadcn@latest init -y`, { cwd: projectPath });
220
+
221
+ // Ensure tsconfig has path aliases for shadcn
222
+ const fs = await import('fs-extra');
223
+ const path = await import('path');
224
+ const tsconfigPath = path.join(projectPath, 'tsconfig.json');
225
+
226
+ if (await fs.pathExists(tsconfigPath)) {
227
+ const tsconfig = await fs.readJson(tsconfigPath);
228
+ if (!tsconfig.compilerOptions) tsconfig.compilerOptions = {};
229
+ if (!tsconfig.compilerOptions.baseUrl) tsconfig.compilerOptions.baseUrl = '.';
230
+ if (!tsconfig.compilerOptions.paths) tsconfig.compilerOptions.paths = {};
231
+ tsconfig.compilerOptions.paths['@/*'] = ['./src/*'];
232
+ await fs.writeJson(tsconfigPath, tsconfig, { spaces: 2 });
233
+ }
234
+
235
+ // shadcn has its own CLI! Use package manager's binary runner
236
+ const { packageManager } = config;
237
+ const execCmd =
238
+ packageManager === 'npm'
239
+ ? 'npx'
240
+ : packageManager === 'yarn'
241
+ ? 'yarn dlx'
242
+ : packageManager === 'pnpm'
243
+ ? 'pnpm dlx'
244
+ : packageManager === 'bun'
245
+ ? 'bunx'
246
+ : 'npx';
247
+ await execCommand(`${execCmd} shadcn@latest init -y`, { cwd: projectPath });
120
248
  break;
249
+ }
121
250
 
122
251
  case 'mui':
123
252
  case 'material-ui':
@@ -175,10 +304,20 @@ async function installORM(projectPath, orm, database, config) {
175
304
  await execCommand(`${installCmd} -D prisma`, { cwd: projectPath });
176
305
  await execCommand(`${installCmd} @prisma/client`, { cwd: projectPath });
177
306
 
178
- // Initialize Prisma with database
307
+ // Initialize Prisma with database using package manager's binary runner
179
308
  const datasource = getDatasourceForPrisma(database);
180
309
  console.log(chalk.dim(` Initializing Prisma with ${datasource}...`));
181
- await execCommand(`npx prisma init --datasource-provider ${datasource}`, {
310
+ const execCmd =
311
+ packageManager === 'npm'
312
+ ? 'npx'
313
+ : packageManager === 'yarn'
314
+ ? 'yarn'
315
+ : packageManager === 'pnpm'
316
+ ? 'pnpm exec'
317
+ : packageManager === 'bun'
318
+ ? 'bunx'
319
+ : 'npx';
320
+ await execCommand(`${execCmd} prisma init --datasource-provider ${datasource}`, {
182
321
  cwd: projectPath,
183
322
  });
184
323
  break;
@@ -295,11 +434,22 @@ async function installTesting(projectPath, testingLibs, config) {
295
434
  });
296
435
  break;
297
436
 
298
- case 'playwright':
437
+ case 'playwright': {
299
438
  console.log(chalk.dim(' Installing Playwright...'));
300
- // Playwright has its own init CLI!
301
- await execCommand(`npm init playwright@latest`, { cwd: projectPath });
439
+ // Playwright has its own init CLI! Use package manager's create command
440
+ const initCmd =
441
+ packageManager === 'npm'
442
+ ? 'npm init'
443
+ : packageManager === 'yarn'
444
+ ? 'yarn create'
445
+ : packageManager === 'pnpm'
446
+ ? 'pnpm create'
447
+ : packageManager === 'bun'
448
+ ? 'bun create'
449
+ : 'npm init';
450
+ await execCommand(`${initCmd} playwright@latest`, { cwd: projectPath });
302
451
  break;
452
+ }
303
453
 
304
454
  case 'cypress':
305
455
  console.log(chalk.dim(' Installing Cypress...'));
@@ -392,6 +542,7 @@ function getDriverForTypeORM(database) {
392
542
  */
393
543
  export function hasAddons(config) {
394
544
  return !!(
545
+ (config.styling && config.styling !== 'none' && config.styling !== 'css') ||
395
546
  (config.stateManagement && config.stateManagement !== 'none') ||
396
547
  (config.uiLibrary && config.uiLibrary !== 'none') ||
397
548
  (config.orm && config.orm !== 'none') ||
@@ -14,7 +14,7 @@ import chalk from 'chalk';
14
14
  * @returns {Promise<void>}
15
15
  */
16
16
  export async function bootstrapWithOfficialCLI(projectPath, config) {
17
- const { projectType, frontend, backend } = config;
17
+ const { projectType, frontend: _frontend, backend: _backend } = config;
18
18
 
19
19
  switch (projectType) {
20
20
  case 'frontend':
@@ -239,7 +239,7 @@ export async function bootstrapSvelte(projectPath, config) {
239
239
  * @param {Object} config - Configuration object
240
240
  */
241
241
  export async function bootstrapExpress(projectPath, config) {
242
- const { language, packageManager = 'npm' } = config;
242
+ const { language } = config;
243
243
  const projectName = path.basename(projectPath);
244
244
  const parentDir = path.dirname(projectPath);
245
245
 
@@ -109,7 +109,7 @@ async function createFeatureBasedStructure(srcPath, config) {
109
109
  /**
110
110
  * Create component-based folder structure
111
111
  */
112
- async function createComponentBasedStructure(srcPath, config) {
112
+ async function createComponentBasedStructure(srcPath, _config) {
113
113
  await fs.ensureDir(path.join(srcPath, 'components', 'ui'));
114
114
  await fs.ensureDir(path.join(srcPath, 'components', 'layout'));
115
115
  await fs.ensureDir(path.join(srcPath, 'components', 'forms'));
@@ -6,7 +6,7 @@ import https from 'https';
6
6
  * @returns {Promise<string>} Latest version number
7
7
  */
8
8
  export async function getLatestVersion(packageName) {
9
- return new Promise((resolve, reject) => {
9
+ return new Promise((resolve) => {
10
10
  const url = `https://registry.npmjs.org/${packageName}/latest`;
11
11
 
12
12
  https
@@ -21,13 +21,13 @@ export async function getLatestVersion(packageName) {
21
21
  try {
22
22
  const json = JSON.parse(data);
23
23
  resolve(json.version || 'latest');
24
- } catch (error) {
24
+ } catch (_error) {
25
25
  // If parsing fails, return 'latest' as fallback
26
26
  resolve('latest');
27
27
  }
28
28
  });
29
29
  })
30
- .on('error', (error) => {
30
+ .on('error', () => {
31
31
  // On network error, return 'latest' as fallback
32
32
  console.warn(`Warning: Could not fetch version for ${packageName}, using 'latest'`);
33
33
  resolve('latest');