create-cloudinary-react 1.0.0-beta.20 β 1.0.0-beta.22
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/CHANGELOG.md +17 -0
- package/README.md +3 -3
- package/cli.js +89 -12
- package/package.json +1 -1
- package/templates/README.md.template +4 -0
- package/templates/package.json.template +3 -0
- package/templates/src/App.tsx.template +19 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
# [1.0.0-beta.22](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.21...v1.0.0-beta.22) (2026-04-08)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* add comments ([5dd6f00](https://github.com/cloudinary-devs/create-cloudinary-react/commit/5dd6f002d514d5e488eb1fcf8e9f003fa09fc22c))
|
|
7
|
+
* comment and render secure url after upload ([4061546](https://github.com/cloudinary-devs/create-cloudinary-react/commit/40615464f260693a1f9a5f6b7ceca3c10456bbe6))
|
|
8
|
+
* detect invoking package manager ([8e3547c](https://github.com/cloudinary-devs/create-cloudinary-react/commit/8e3547c9b97b1c806dacf853a0764d5fe9e36b9e))
|
|
9
|
+
* version in readme ([0325e1b](https://github.com/cloudinary-devs/create-cloudinary-react/commit/0325e1be42db7e042710a6249f72ca4a6738bd4d))
|
|
10
|
+
|
|
11
|
+
# [1.0.0-beta.21](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.20...v1.0.0-beta.21) (2026-02-25)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* update title in readme and ui ([54f633e](https://github.com/cloudinary-devs/create-cloudinary-react/commit/54f633e6fc2a6e800979c9962383c8f83523f79b))
|
|
17
|
+
|
|
1
18
|
# [1.0.0-beta.20](https://github.com/cloudinary-devs/create-cloudinary-react/compare/v1.0.0-beta.19...v1.0.0-beta.20) (2026-02-23)
|
|
2
19
|
|
|
3
20
|
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
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.
|
|
10
10
|
|
|
11
|
-
- Node.js
|
|
11
|
+
- **Node.js** β use a [current LTS](https://nodejs.org/) release. The generated app lists supported versions under `engines` in its `package.json`.
|
|
12
12
|
- A Cloudinary account (free tier available)
|
|
13
13
|
- [Sign up for free](https://cld.media/reactregister)
|
|
14
14
|
- 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
|
|
|
36
36
|
|
|
37
37
|
## π Quick Start
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
Use a current **Node.js LTS** release. If installs fail, match the `engines` range in the generated projectβs `package.json`.
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
42
|
npx create-cloudinary-react
|
|
@@ -80,7 +80,7 @@ During setup, select your AI tool to generate **Context Rules**. These rules tea
|
|
|
80
80
|
|
|
81
81
|
## π Prerequisites
|
|
82
82
|
|
|
83
|
-
- **Node.js
|
|
83
|
+
- **Node.js** β LTS recommended; exact ranges for the scaffolded app are in `package.json` β `engines`.
|
|
84
84
|
- **Cloudinary Account**: [Sign up for free](https://cloudinary.com/users/register/free) if you haven't already.
|
|
85
85
|
|
|
86
86
|
## π€ Contributing
|
package/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { dirname, join } from 'path';
|
|
5
5
|
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
6
|
-
import {
|
|
6
|
+
import { spawnSync } from 'child_process';
|
|
7
7
|
import inquirer from 'inquirer';
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import fs from 'fs-extra';
|
|
@@ -14,6 +14,64 @@ const __dirname = dirname(__filename);
|
|
|
14
14
|
|
|
15
15
|
const TEMPLATES_DIR = join(__dirname, 'templates');
|
|
16
16
|
|
|
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
|
+
/**
|
|
33
|
+
* Resolve which client to run for install / dev.
|
|
34
|
+
* Only npm, pnpm, yarn, and bun have explicit command mappings below; anything else
|
|
35
|
+
* (missing env, exotic clients, parse quirks) falls back to npm as the safe default that
|
|
36
|
+
* ships with Node and matches the install instructions most users expect.
|
|
37
|
+
*/
|
|
38
|
+
function detectPackageManager() {
|
|
39
|
+
const pkg = pkgFromUserAgent(process.env.npm_config_user_agent);
|
|
40
|
+
if (pkg && SUPPORTED_PACKAGE_MANAGERS.has(pkg.name)) {
|
|
41
|
+
return pkg.name;
|
|
42
|
+
}
|
|
43
|
+
return 'npm';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getInstallCommand(packageManager) {
|
|
47
|
+
if (packageManager === 'yarn') {
|
|
48
|
+
return ['yarn'];
|
|
49
|
+
}
|
|
50
|
+
return [packageManager, 'install'];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getRunDevCommand(packageManager) {
|
|
54
|
+
switch (packageManager) {
|
|
55
|
+
case 'yarn':
|
|
56
|
+
case 'pnpm':
|
|
57
|
+
case 'bun':
|
|
58
|
+
return [packageManager, 'dev'];
|
|
59
|
+
default:
|
|
60
|
+
return ['npm', 'run', 'dev'];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function runPackageManagerCommand(args, cwd) {
|
|
65
|
+
const [command, ...cmdArgs] = args;
|
|
66
|
+
const result = spawnSync(command, cmdArgs, { stdio: 'inherit', cwd, shell: false });
|
|
67
|
+
if (result.error) {
|
|
68
|
+
throw result.error;
|
|
69
|
+
}
|
|
70
|
+
if (result.status !== 0) {
|
|
71
|
+
throw new Error(`Command failed: ${args.join(' ')}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
17
75
|
// Validate cloud name format
|
|
18
76
|
function isValidCloudName(name) {
|
|
19
77
|
return /^[a-z0-9_-]+$/.test(name) && name.length > 0;
|
|
@@ -61,15 +119,19 @@ async function main() {
|
|
|
61
119
|
startDev: {
|
|
62
120
|
type: 'boolean',
|
|
63
121
|
default: false
|
|
64
|
-
}
|
|
65
|
-
|
|
122
|
+
},
|
|
123
|
+
packageManager: {
|
|
124
|
+
type: 'string',
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
allowPositionals: true,
|
|
66
128
|
});
|
|
67
129
|
|
|
68
130
|
Object.assign(answers, values);
|
|
69
131
|
|
|
70
132
|
} else {
|
|
71
133
|
|
|
72
|
-
console.log(chalk.cyan.bold('\nπ Cloudinary React
|
|
134
|
+
console.log(chalk.cyan.bold('\nπ Cloudinary React Starter Kit\n'));
|
|
73
135
|
console.log(chalk.gray('π‘ Need a Cloudinary account? Sign up for free: https://cld.media/reactregister\n'));
|
|
74
136
|
|
|
75
137
|
const questions = [
|
|
@@ -166,6 +228,17 @@ async function main() {
|
|
|
166
228
|
|
|
167
229
|
const { projectName, cloudName, uploadPreset, aiTools, installDeps, startDev } = answers;
|
|
168
230
|
|
|
231
|
+
let packageManager = answers.packageManager;
|
|
232
|
+
if (packageManager && !SUPPORTED_PACKAGE_MANAGERS.has(packageManager)) {
|
|
233
|
+
console.warn(
|
|
234
|
+
chalk.yellow(
|
|
235
|
+
`Unknown package manager "${packageManager}". Use npm, pnpm, yarn, or bun. Ignoring --packageManager; using npm_config_user_agent when it names a supported client, otherwise npm.`
|
|
236
|
+
)
|
|
237
|
+
);
|
|
238
|
+
packageManager = undefined;
|
|
239
|
+
}
|
|
240
|
+
packageManager = packageManager || detectPackageManager();
|
|
241
|
+
|
|
169
242
|
console.log(chalk.blue('\nπ¦ Creating project...\n'));
|
|
170
243
|
|
|
171
244
|
// Create project directory
|
|
@@ -311,34 +384,38 @@ async function main() {
|
|
|
311
384
|
console.log(chalk.cyan(' 5. Save the file and restart the dev server so it loads correctly\n'));
|
|
312
385
|
}
|
|
313
386
|
|
|
387
|
+
const installCmd = getInstallCommand(packageManager);
|
|
388
|
+
const devCmd = getRunDevCommand(packageManager);
|
|
389
|
+
const installCmdStr = installCmd.join(' ');
|
|
390
|
+
const devCmdStr = devCmd.join(' ');
|
|
391
|
+
|
|
314
392
|
if (installDeps) {
|
|
315
|
-
console.log(chalk.blue(
|
|
393
|
+
console.log(chalk.blue(`π¦ Installing dependencies with ${packageManager}...\n`));
|
|
316
394
|
try {
|
|
317
|
-
|
|
318
|
-
execSync('npm install', { stdio: 'inherit' });
|
|
395
|
+
runPackageManagerCommand(installCmd, projectPath);
|
|
319
396
|
console.log(chalk.green('\nβ
Dependencies installed!\n'));
|
|
320
397
|
|
|
321
398
|
if (startDev) {
|
|
322
399
|
console.log(chalk.blue('π Starting development server...\n'));
|
|
323
|
-
|
|
400
|
+
runPackageManagerCommand(devCmd, projectPath);
|
|
324
401
|
} else {
|
|
325
402
|
console.log(chalk.cyan(`\nπ Project created at: ${projectPath}`));
|
|
326
403
|
console.log(chalk.cyan(`\nNext steps:`));
|
|
327
404
|
console.log(chalk.cyan(` cd ${projectName}`));
|
|
328
|
-
console.log(chalk.cyan(`
|
|
405
|
+
console.log(chalk.cyan(` ${devCmdStr}\n`));
|
|
329
406
|
}
|
|
330
407
|
} catch (error) {
|
|
331
408
|
console.error(chalk.red('\nβ Error installing dependencies:'), error.message);
|
|
332
409
|
console.log(chalk.cyan(`\nYou can install manually:`));
|
|
333
410
|
console.log(chalk.cyan(` cd ${projectName}`));
|
|
334
|
-
console.log(chalk.cyan(`
|
|
411
|
+
console.log(chalk.cyan(` ${installCmdStr}\n`));
|
|
335
412
|
}
|
|
336
413
|
} else {
|
|
337
414
|
console.log(chalk.cyan(`\nπ Project created at: ${projectPath}`));
|
|
338
415
|
console.log(chalk.cyan(`\nNext steps:`));
|
|
339
416
|
console.log(chalk.cyan(` cd ${projectName}`));
|
|
340
|
-
console.log(chalk.cyan(`
|
|
341
|
-
console.log(chalk.cyan(`
|
|
417
|
+
console.log(chalk.cyan(` ${installCmdStr}`));
|
|
418
|
+
console.log(chalk.cyan(` ${devCmdStr}\n`));
|
|
342
419
|
}
|
|
343
420
|
}
|
|
344
421
|
|
package/package.json
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
A Cloudinary React + Vite + TypeScript project scaffolded with [create-cloudinary-react](https://github.com/cloudinary-devs/create-cloudinary-react).
|
|
4
4
|
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- **Node.js** β use a current LTS release. Supported ranges are listed under `engines` in this `package.json`.
|
|
8
|
+
|
|
5
9
|
## Quick Start
|
|
6
10
|
|
|
7
11
|
```bash
|
|
@@ -25,11 +25,21 @@ const PROMPTS_WITHOUT_UPLOAD = [
|
|
|
25
25
|
|
|
26
26
|
function App() {
|
|
27
27
|
const [uploadedImageId, setUploadedImageId] = useState<string | null>(null);
|
|
28
|
+
const [uploadedUrl, setUploadedUrl] = useState<string | null>(null);
|
|
28
29
|
const [clickedIds, setClickedIds] = useState(new Set<number>());
|
|
29
30
|
|
|
30
31
|
const handleUploadSuccess = (result: CloudinaryUploadResult) => {
|
|
31
32
|
console.log('Upload successful:', result);
|
|
33
|
+
// result contains everything you need to work with the uploaded asset:
|
|
34
|
+
// result.public_id β Cloudinary asset ID (use with cld.image() for transformations)
|
|
35
|
+
// result.secure_url β direct HTTPS URL to the original file
|
|
36
|
+
// result.url β HTTP URL (prefer secure_url)
|
|
37
|
+
// result.width / result.height β image dimensions
|
|
38
|
+
// result.format β file format (e.g. 'jpg', 'png', 'webp')
|
|
39
|
+
// result.bytes β file size in bytes
|
|
40
|
+
// result.resource_type β 'image', 'video', or 'raw'
|
|
32
41
|
setUploadedImageId(result.public_id);
|
|
42
|
+
setUploadedUrl(result.secure_url); // store the URL to use anywhere in your app
|
|
33
43
|
};
|
|
34
44
|
|
|
35
45
|
const handleUploadError = (error: Error) => {
|
|
@@ -60,7 +70,7 @@ function App() {
|
|
|
60
70
|
return (
|
|
61
71
|
<div className="app">
|
|
62
72
|
<main className="main-content">
|
|
63
|
-
<h1>Cloudinary React
|
|
73
|
+
<h1>Cloudinary React Starter Kit</h1>
|
|
64
74
|
<p>This is a ready-to-use development environment with Cloudinary integration.</p>
|
|
65
75
|
|
|
66
76
|
{hasUploadPreset && (
|
|
@@ -85,6 +95,14 @@ function App() {
|
|
|
85
95
|
{uploadedImageId && (
|
|
86
96
|
<p className="image-info">Public ID: {uploadedImageId}</p>
|
|
87
97
|
)}
|
|
98
|
+
{uploadedUrl && (
|
|
99
|
+
<p className="image-info">
|
|
100
|
+
URL:{' '}
|
|
101
|
+
<a href={uploadedUrl} target="_blank" rel="noopener noreferrer">
|
|
102
|
+
{uploadedUrl}
|
|
103
|
+
</a>
|
|
104
|
+
</p>
|
|
105
|
+
)}
|
|
88
106
|
</div>
|
|
89
107
|
|
|
90
108
|
<div className="ai-prompts-section">
|