Skip to content

Commit 8e3547c

Browse files
author
strausr
committed
fix: detect invoking package manager
1 parent 4061546 commit 8e3547c

5 files changed

Lines changed: 86 additions & 14 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
Scaffold a modern, production-ready Cloudinary application with React 19, Vite 6, and TypeScript 5. Features interactive setup, automatic environment configuration, and built-in AI coding assistance.
1010

11-
- Node.js 18+ installed
11+
- **Node.js 20.19+** or **22.12+** (required by `@vitejs/plugin-react` 5.x with Vite 6)
1212
- A Cloudinary account (free tier available)
1313
- [Sign up for free](https://cld.media/reactregister)
1414
- Your cloud name is in your [dashboard](https://console.cloudinary.com/app/home/dashboard)
@@ -36,7 +36,7 @@ Part of the [Cloudinary Developers](https://github.com/cloudinary-devs) organiza
3636

3737
## 🚀 Quick Start
3838

39-
Ensure you have Node.js 18+ installed.
39+
Ensure you have **Node.js 20.19+** or **22.12+** installed (see prerequisites above).
4040

4141
```bash
4242
npx create-cloudinary-react

cli.js

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,52 @@ const __dirname = dirname(__filename);
1414

1515
const TEMPLATES_DIR = join(__dirname, 'templates');
1616

17+
/** Package managers we know how to drive for install / dev scripts */
18+
const SUPPORTED_PACKAGE_MANAGERS = new Set(['npm', 'pnpm', 'yarn', 'bun']);
19+
20+
/**
21+
* Parse npm_config_user_agent (set by npm, pnpm, yarn, bun when they run a package).
22+
* Same approach as create-vite: first space-separated segment is "name/version".
23+
*/
24+
function pkgFromUserAgent(userAgent) {
25+
if (!userAgent) return undefined;
26+
const pkgSpec = userAgent.split(' ')[0];
27+
const [name, version = ''] = pkgSpec.split('/');
28+
if (!name) return undefined;
29+
return { name, version };
30+
}
31+
32+
function detectPackageManager() {
33+
const pkg = pkgFromUserAgent(process.env.npm_config_user_agent);
34+
if (pkg && SUPPORTED_PACKAGE_MANAGERS.has(pkg.name)) {
35+
return pkg.name;
36+
}
37+
return 'npm';
38+
}
39+
40+
function getInstallCommand(packageManager) {
41+
if (packageManager === 'yarn') {
42+
return ['yarn'];
43+
}
44+
return [packageManager, 'install'];
45+
}
46+
47+
function getRunDevCommand(packageManager) {
48+
switch (packageManager) {
49+
case 'yarn':
50+
case 'pnpm':
51+
case 'bun':
52+
return [packageManager, 'dev'];
53+
default:
54+
return ['npm', 'run', 'dev'];
55+
}
56+
}
57+
58+
function runPackageManagerCommand(args, cwd) {
59+
const quoted = args.map((arg) => (/[\s"'\\]/.test(arg) ? JSON.stringify(arg) : arg));
60+
execSync(quoted.join(' '), { stdio: 'inherit', cwd, shell: true });
61+
}
62+
1763
// Validate cloud name format
1864
function isValidCloudName(name) {
1965
return /^[a-z0-9_-]+$/.test(name) && name.length > 0;
@@ -61,8 +107,12 @@ async function main() {
61107
startDev: {
62108
type: 'boolean',
63109
default: false
64-
}
65-
}
110+
},
111+
packageManager: {
112+
type: 'string',
113+
},
114+
},
115+
allowPositionals: true,
66116
});
67117

68118
Object.assign(answers, values);
@@ -166,6 +216,17 @@ async function main() {
166216

167217
const { projectName, cloudName, uploadPreset, aiTools, installDeps, startDev } = answers;
168218

219+
let packageManager = answers.packageManager;
220+
if (packageManager && !SUPPORTED_PACKAGE_MANAGERS.has(packageManager)) {
221+
console.warn(
222+
chalk.yellow(
223+
`Unknown package manager "${packageManager}". Use npm, pnpm, yarn, or bun. Falling back to auto-detect.`
224+
)
225+
);
226+
packageManager = undefined;
227+
}
228+
packageManager = packageManager || detectPackageManager();
229+
169230
console.log(chalk.blue('\n📦 Creating project...\n'));
170231

171232
// Create project directory
@@ -311,34 +372,38 @@ async function main() {
311372
console.log(chalk.cyan(' 5. Save the file and restart the dev server so it loads correctly\n'));
312373
}
313374

375+
const installCmd = getInstallCommand(packageManager);
376+
const devCmd = getRunDevCommand(packageManager);
377+
const installCmdStr = installCmd.join(' ');
378+
const devCmdStr = devCmd.join(' ');
379+
314380
if (installDeps) {
315-
console.log(chalk.blue('📦 Installing dependencies...\n'));
381+
console.log(chalk.blue(`📦 Installing dependencies with ${packageManager}...\n`));
316382
try {
317-
process.chdir(projectPath);
318-
execSync('npm install', { stdio: 'inherit' });
383+
runPackageManagerCommand(installCmd, projectPath);
319384
console.log(chalk.green('\n✅ Dependencies installed!\n'));
320385

321386
if (startDev) {
322387
console.log(chalk.blue('🚀 Starting development server...\n'));
323-
execSync('npm run dev', { stdio: 'inherit' });
388+
runPackageManagerCommand(devCmd, projectPath);
324389
} else {
325390
console.log(chalk.cyan(`\n📁 Project created at: ${projectPath}`));
326391
console.log(chalk.cyan(`\nNext steps:`));
327392
console.log(chalk.cyan(` cd ${projectName}`));
328-
console.log(chalk.cyan(` npm run dev\n`));
393+
console.log(chalk.cyan(` ${devCmdStr}\n`));
329394
}
330395
} catch (error) {
331396
console.error(chalk.red('\n❌ Error installing dependencies:'), error.message);
332397
console.log(chalk.cyan(`\nYou can install manually:`));
333398
console.log(chalk.cyan(` cd ${projectName}`));
334-
console.log(chalk.cyan(` npm install\n`));
399+
console.log(chalk.cyan(` ${installCmdStr}\n`));
335400
}
336401
} else {
337402
console.log(chalk.cyan(`\n📁 Project created at: ${projectPath}`));
338403
console.log(chalk.cyan(`\nNext steps:`));
339404
console.log(chalk.cyan(` cd ${projectName}`));
340-
console.log(chalk.cyan(` npm install`));
341-
console.log(chalk.cyan(` npm run dev\n`));
405+
console.log(chalk.cyan(` ${installCmdStr}`));
406+
console.log(chalk.cyan(` ${devCmdStr}\n`));
342407
}
343408
}
344409

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

templates/README.md.template

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
A Cloudinary React + Vite + TypeScript project scaffolded with [create-cloudinary-react](https://github.com/cloudinary-devs/create-cloudinary-react).
44

5+
## Prerequisites
6+
7+
- **Node.js** `^20.19.0` or `>=22.12.0` (matches `@vitejs/plugin-react` 5.x)
8+
59
## Quick Start
610

711
```bash

templates/package.json.template

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"private": true,
44
"version": "0.0.0",
55
"type": "module",
6+
"engines": {
7+
"node": "^20.19.0 || >=22.12.0"
8+
},
69
"scripts": {
710
"dev": "vite",
811
"build": "tsc -b && vite build",

0 commit comments

Comments
 (0)