create-react-on-rails-app 16.6.0-rc.0 → 16.6.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.
- package/lib/index.d.ts +2 -1
- package/lib/index.js +49 -18
- package/lib/prompt.d.ts +7 -0
- package/lib/prompt.js +72 -0
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -3,15 +3,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ready = void 0;
|
|
6
7
|
const commander_1 = require("commander");
|
|
7
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
9
|
const validators_js_1 = require("./validators.js");
|
|
9
10
|
const create_app_js_1 = require("./create-app.js");
|
|
10
11
|
const utils_js_1 = require("./utils.js");
|
|
12
|
+
const prompt_js_1 = require("./prompt.js");
|
|
11
13
|
// Use require() for CJS compatibility - avoids __dirname + fs.readFileSync
|
|
12
14
|
// eslint-disable-next-line @typescript-eslint/no-require-imports, global-require
|
|
13
15
|
const packageJson = require('../package.json');
|
|
14
|
-
function run(appName, rawOpts) {
|
|
16
|
+
async function run(appName, rawOpts) {
|
|
15
17
|
const { template } = rawOpts;
|
|
16
18
|
if (typeof template !== 'string' || (template !== 'javascript' && template !== 'typescript')) {
|
|
17
19
|
(0, utils_js_1.logError)(`Invalid template "${String(template)}". Must be "javascript" or "typescript".`);
|
|
@@ -27,13 +29,8 @@ function run(appName, rawOpts) {
|
|
|
27
29
|
else {
|
|
28
30
|
packageManager = (0, utils_js_1.detectPackageManager)() ?? 'npm';
|
|
29
31
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
packageManager: packageManager,
|
|
33
|
-
rspack: Boolean(rawOpts.rspack),
|
|
34
|
-
pro: Boolean(rawOpts.pro),
|
|
35
|
-
rsc: Boolean(rawOpts.rsc),
|
|
36
|
-
};
|
|
32
|
+
let pro = Boolean(rawOpts.pro);
|
|
33
|
+
let rsc = Boolean(rawOpts.rsc);
|
|
37
34
|
console.log('');
|
|
38
35
|
console.log(`${chalk_1.default.bold('create-react-on-rails-app')} v${packageJson.version}`);
|
|
39
36
|
console.log('');
|
|
@@ -42,6 +39,26 @@ function run(appName, rawOpts) {
|
|
|
42
39
|
(0, utils_js_1.logError)(nameValidation.error ?? 'Invalid app name');
|
|
43
40
|
process.exit(1);
|
|
44
41
|
}
|
|
42
|
+
// When no mode flag is explicitly passed, prompt interactively (TTY only).
|
|
43
|
+
// Non-interactive environments (CI, pipes) fall back to standard mode.
|
|
44
|
+
const modeExplicit = rawOpts.pro !== undefined || rawOpts.rsc !== undefined || rawOpts.standard !== undefined;
|
|
45
|
+
if (!modeExplicit) {
|
|
46
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
47
|
+
const choice = await (0, prompt_js_1.promptForMode)();
|
|
48
|
+
pro = choice.pro;
|
|
49
|
+
rsc = choice.rsc;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
(0, utils_js_1.logInfo)('No mode flag specified and not running interactively (stdin/stdout is not a TTY); using standard mode.');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const options = {
|
|
56
|
+
template,
|
|
57
|
+
packageManager: packageManager,
|
|
58
|
+
rspack: Boolean(rawOpts.rspack),
|
|
59
|
+
pro,
|
|
60
|
+
rsc,
|
|
61
|
+
};
|
|
45
62
|
if (options.rsc && options.pro) {
|
|
46
63
|
(0, utils_js_1.logInfo)('Note: --rsc takes precedence over --pro; --pro will be ignored.');
|
|
47
64
|
}
|
|
@@ -93,22 +110,28 @@ program
|
|
|
93
110
|
.option('-t, --template <type>', 'javascript or typescript', 'typescript')
|
|
94
111
|
.option('-p, --package-manager <pm>', 'npm or pnpm (auto-detected if not specified)')
|
|
95
112
|
.option('--rspack', 'Use Rspack instead of Webpack (~20x faster builds)', false)
|
|
96
|
-
.option('--
|
|
97
|
-
.option('--
|
|
113
|
+
.option('--standard', 'Generate open-source React on Rails setup (skip prompt)')
|
|
114
|
+
.option('--pro', 'Generate React on Rails Pro setup (installs react_on_rails_pro)')
|
|
115
|
+
.option('--rsc', 'Generate React Server Components setup (installs react_on_rails_pro)')
|
|
98
116
|
.addHelpText('after', `
|
|
99
117
|
Examples:
|
|
100
|
-
$ npx create-react-on-rails-app my-app
|
|
118
|
+
$ npx create-react-on-rails-app my-app # prompts for mode
|
|
119
|
+
$ npx create-react-on-rails-app my-app --rsc # skip prompt, use RSC
|
|
120
|
+
$ npx create-react-on-rails-app my-app --pro # skip prompt, use Pro
|
|
121
|
+
$ npx create-react-on-rails-app my-app --standard # skip prompt, use Standard
|
|
101
122
|
$ npx create-react-on-rails-app my-app --template javascript
|
|
102
123
|
$ npx create-react-on-rails-app my-app --rspack
|
|
103
|
-
$ npx create-react-on-rails-app my-app --pro
|
|
104
|
-
$ npx create-react-on-rails-app my-app --rsc
|
|
105
|
-
$ npx create-react-on-rails-app my-app --rspack --pro
|
|
106
124
|
$ npx create-react-on-rails-app my-app --rspack --rsc
|
|
107
125
|
$ npx create-react-on-rails-app my-app --package-manager pnpm
|
|
108
126
|
|
|
127
|
+
When no mode flag (--standard, --pro, or --rsc) is given, an interactive prompt
|
|
128
|
+
lets you choose between Standard, Pro, and RSC modes (default: RSC). When stdin
|
|
129
|
+
or stdout is not a TTY (for example in CI, piped input, or redirected output),
|
|
130
|
+
standard mode is used automatically.
|
|
131
|
+
|
|
109
132
|
What it does:
|
|
110
133
|
1. Creates a new Rails app with PostgreSQL
|
|
111
|
-
2. Adds required gem(s) (react_on_rails, plus react_on_rails_pro for
|
|
134
|
+
2. Adds required gem(s) (react_on_rails, plus react_on_rails_pro for Pro/RSC)
|
|
112
135
|
3. Runs the React on Rails generator (Shakapacker, components, webpack config)
|
|
113
136
|
4. Creates educational git commits for each major scaffold step
|
|
114
137
|
|
|
@@ -125,14 +148,22 @@ The generated app includes one git commit per logical setup step.`)
|
|
|
125
148
|
--pro and --rsc support both JavaScript and TypeScript templates.
|
|
126
149
|
|
|
127
150
|
Documentation: https://reactonrails.com/docs/`)
|
|
128
|
-
.action((appName, opts) => {
|
|
151
|
+
.action(async (appName, opts) => {
|
|
129
152
|
try {
|
|
130
|
-
run(appName, opts);
|
|
153
|
+
await run(appName, opts);
|
|
131
154
|
}
|
|
132
155
|
catch (error) {
|
|
156
|
+
if (error instanceof Error && error.message === prompt_js_1.PROMPT_CANCELLED) {
|
|
157
|
+
console.log('');
|
|
158
|
+
process.exit(0);
|
|
159
|
+
}
|
|
133
160
|
(0, utils_js_1.logError)(error instanceof Error ? error.message : String(error));
|
|
134
161
|
process.exit(1);
|
|
135
162
|
}
|
|
136
163
|
});
|
|
137
|
-
|
|
164
|
+
// eslint-disable-next-line import/prefer-default-export -- named export for test clarity
|
|
165
|
+
exports.ready = program.parseAsync().catch((error) => {
|
|
166
|
+
(0, utils_js_1.logError)(error instanceof Error ? error.message : String(error));
|
|
167
|
+
process.exit(1);
|
|
168
|
+
});
|
|
138
169
|
//# sourceMappingURL=index.js.map
|
package/lib/prompt.d.ts
ADDED
package/lib/prompt.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PROMPT_CANCELLED = void 0;
|
|
7
|
+
exports.promptForMode = promptForMode;
|
|
8
|
+
const readline_1 = __importDefault(require("readline"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
exports.PROMPT_CANCELLED = 'Prompt cancelled by user';
|
|
11
|
+
const MODES = [
|
|
12
|
+
{
|
|
13
|
+
key: '1',
|
|
14
|
+
label: 'Standard',
|
|
15
|
+
desc: 'Open-source React on Rails with SSR',
|
|
16
|
+
pro: false,
|
|
17
|
+
rsc: false,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
key: '2',
|
|
21
|
+
label: 'Pro',
|
|
22
|
+
desc: 'Adds Node.js server rendering (requires react_on_rails_pro)',
|
|
23
|
+
pro: true,
|
|
24
|
+
rsc: false,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
key: '3',
|
|
28
|
+
label: 'RSC',
|
|
29
|
+
desc: 'React Server Components (requires react_on_rails_pro)',
|
|
30
|
+
pro: false,
|
|
31
|
+
rsc: true,
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
const DEFAULT_KEY = '3';
|
|
35
|
+
function promptForMode() {
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
const rl = readline_1.default.createInterface({
|
|
38
|
+
input: process.stdin,
|
|
39
|
+
output: process.stdout,
|
|
40
|
+
});
|
|
41
|
+
let answered = false;
|
|
42
|
+
rl.on('SIGINT', () => {
|
|
43
|
+
answered = true;
|
|
44
|
+
rl.close();
|
|
45
|
+
reject(new Error(exports.PROMPT_CANCELLED));
|
|
46
|
+
});
|
|
47
|
+
rl.once('close', () => {
|
|
48
|
+
if (!answered) {
|
|
49
|
+
reject(new Error(exports.PROMPT_CANCELLED));
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
console.log(chalk_1.default.bold('Select a setup mode:\n'));
|
|
53
|
+
for (const mode of MODES) {
|
|
54
|
+
const recommended = mode.key === DEFAULT_KEY ? chalk_1.default.cyan(' (recommended)') : '';
|
|
55
|
+
console.log(` ${mode.key}. ${chalk_1.default.bold(mode.label.padEnd(10))} ${mode.desc}${recommended}`);
|
|
56
|
+
}
|
|
57
|
+
console.log('');
|
|
58
|
+
rl.question(`Choice (1-3) [${DEFAULT_KEY}]: `, (answer) => {
|
|
59
|
+
answered = true;
|
|
60
|
+
rl.close();
|
|
61
|
+
const key = answer.trim() || DEFAULT_KEY;
|
|
62
|
+
const selected = MODES.find((m) => m.key === key);
|
|
63
|
+
if (!selected) {
|
|
64
|
+
console.log(chalk_1.default.yellow(`Invalid choice "${key}", defaulting to RSC.`));
|
|
65
|
+
resolve({ pro: false, rsc: true });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
resolve({ pro: selected.pro, rsc: selected.rsc });
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=prompt.js.map
|
package/package.json
CHANGED