react-client 1.0.7 → 1.0.8

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.
@@ -5,25 +5,224 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.default = dev;
7
7
  const esbuild_1 = __importDefault(require("esbuild"));
8
+ const connect_1 = __importDefault(require("connect"));
9
+ const http_1 = __importDefault(require("http"));
10
+ const ws_1 = require("ws");
11
+ const chokidar_1 = __importDefault(require("chokidar"));
12
+ const detect_port_1 = __importDefault(require("detect-port"));
13
+ const prompts_1 = __importDefault(require("prompts"));
8
14
  const path_1 = __importDefault(require("path"));
9
15
  const fs_extra_1 = __importDefault(require("fs-extra"));
16
+ const trace_mapping_1 = require("@jridgewell/trace-mapping");
17
+ const loadConfig_1 = require("../../utils/loadConfig");
18
+ const open_1 = __importDefault(require("open"));
19
+ const child_process_1 = require("child_process");
20
+ const chalk_1 = __importDefault(require("chalk"));
10
21
  async function dev() {
11
22
  const root = process.cwd();
12
- const entry = path_1.default.join(root, 'src', 'main.tsx');
23
+ // 🧩 Load config
24
+ const userConfig = await (0, loadConfig_1.loadReactClientConfig)(root);
25
+ const appRoot = path_1.default.resolve(root, userConfig.root || '.');
26
+ const defaultPort = userConfig.server?.port || 5173;
27
+ const outDir = path_1.default.join(appRoot, userConfig.build?.outDir || '.react-client/dev');
28
+ const entry = path_1.default.join(appRoot, 'src', 'main.tsx');
29
+ const indexHtml = path_1.default.join(appRoot, 'index.html');
13
30
  if (!fs_extra_1.default.existsSync(entry)) {
14
- console.error('Entry not found: src/main.tsx');
31
+ console.error(chalk_1.default.red('Entry not found: src/main.tsx'));
15
32
  process.exit(1);
16
33
  }
17
- const outdir = path_1.default.join(root, '.react-client', 'dev');
18
- await fs_extra_1.default.ensureDir(outdir);
34
+ await fs_extra_1.default.ensureDir(outDir);
35
+ const availablePort = await (0, detect_port_1.default)(defaultPort);
36
+ const port = availablePort;
37
+ if (availablePort !== defaultPort) {
38
+ const res = await (0, prompts_1.default)({
39
+ type: 'confirm',
40
+ name: 'useNewPort',
41
+ message: `Port ${defaultPort} is occupied. Use ${availablePort} instead?`,
42
+ initial: true,
43
+ });
44
+ if (!res.useNewPort) {
45
+ console.log('🛑 Dev server cancelled.');
46
+ process.exit(0);
47
+ }
48
+ }
49
+ // ⚡ Auto-install + resolve react-refresh runtime
50
+ function safeResolveReactRefresh() {
51
+ try {
52
+ return require.resolve('react-refresh/runtime');
53
+ }
54
+ catch {
55
+ console.warn(chalk_1.default.yellow('⚠️ react-refresh not found — attempting to install...'));
56
+ try {
57
+ (0, child_process_1.execSync)('npm install react-refresh --no-audit --no-fund --silent', {
58
+ cwd: root,
59
+ stdio: 'inherit',
60
+ });
61
+ console.log(chalk_1.default.green('✅ react-refresh installed successfully.'));
62
+ return require.resolve('react-refresh/runtime');
63
+ }
64
+ catch (err) {
65
+ const msg = err instanceof Error ? err.message : String(err);
66
+ console.error(msg);
67
+ console.error(chalk_1.default.red('❌ Failed to install react-refresh automatically.'));
68
+ console.error('Please run: npm install react-refresh');
69
+ process.exit(1);
70
+ }
71
+ }
72
+ }
73
+ const reactRefreshRuntime = safeResolveReactRefresh();
74
+ // 🏗️ esbuild context
19
75
  const ctx = await esbuild_1.default.context({
20
76
  entryPoints: [entry],
21
77
  bundle: true,
22
78
  sourcemap: true,
23
- outdir,
79
+ outdir: outDir,
24
80
  define: { 'process.env.NODE_ENV': '"development"' },
25
81
  loader: { '.ts': 'ts', '.tsx': 'tsx', '.js': 'jsx', '.jsx': 'jsx' },
26
82
  });
27
83
  await ctx.watch();
28
- await ctx.serve({ servedir: outdir, port: 5173 });
84
+ // 🌐 connect server
85
+ const app = (0, connect_1.default)();
86
+ // 1️⃣ Serve react-refresh runtime
87
+ app.use('/@react-refresh', async (_req, res) => {
88
+ const runtime = await fs_extra_1.default.readFile(reactRefreshRuntime, 'utf8');
89
+ res.setHeader('Content-Type', 'application/javascript');
90
+ res.end(runtime);
91
+ });
92
+ // 2️⃣ Serve PrismJS for highlighting
93
+ app.use('/@prismjs', async (_req, res) => {
94
+ const prismPath = require.resolve('prismjs/prism.js');
95
+ const css = await fs_extra_1.default.readFile(require.resolve('prismjs/themes/prism-tomorrow.css'), 'utf8');
96
+ const js = await fs_extra_1.default.readFile(prismPath, 'utf8');
97
+ res.setHeader('Content-Type', 'application/javascript');
98
+ res.end(`
99
+ (function(){
100
+ const style = document.createElement('style');
101
+ style.textContent = \`${css}\`;
102
+ document.head.appendChild(style);
103
+ ${js}
104
+ })();
105
+ `);
106
+ });
107
+ // 3️⃣ Serve source map resolver
108
+ app.use('/@source-map', async (req, res) => {
109
+ const url = new URL(req.url ?? '', `http://localhost:${port}`);
110
+ const file = url.searchParams.get('file');
111
+ const line = Number(url.searchParams.get('line'));
112
+ const column = Number(url.searchParams.get('column'));
113
+ if (!file) {
114
+ res.writeHead(400);
115
+ res.end('Missing ?file parameter');
116
+ return;
117
+ }
118
+ const mapPath = path_1.default.join(outDir, file + '.map');
119
+ if (!fs_extra_1.default.existsSync(mapPath)) {
120
+ res.writeHead(404);
121
+ res.end('Map not found');
122
+ return;
123
+ }
124
+ try {
125
+ const mapJson = JSON.parse(await fs_extra_1.default.readFile(mapPath, 'utf8'));
126
+ const traceMap = new trace_mapping_1.TraceMap(mapJson);
127
+ const pos = (0, trace_mapping_1.originalPositionFor)(traceMap, { line, column });
128
+ if (!pos.source) {
129
+ res.writeHead(404);
130
+ res.end('Source not found');
131
+ return;
132
+ }
133
+ const absSource = path_1.default.resolve(outDir, '../', pos.source);
134
+ let snippet = '';
135
+ if (await fs_extra_1.default.pathExists(absSource)) {
136
+ const lines = (await fs_extra_1.default.readFile(absSource, 'utf8')).split('\n');
137
+ const start = Math.max((pos.line || 1) - 3, 0);
138
+ const end = Math.min(lines.length, (pos.line || 1) + 2);
139
+ snippet = lines
140
+ .slice(start, end)
141
+ .map((l, i) => `<span class="line-number">${start + i + 1}</span> ${l
142
+ .replace(/</g, '&lt;')
143
+ .replace(/>/g, '&gt;')}`)
144
+ .join('\\n');
145
+ }
146
+ res.setHeader('Content-Type', 'application/json');
147
+ res.end(JSON.stringify({ ...pos, snippet }));
148
+ }
149
+ catch (err) {
150
+ const msg = err instanceof Error ? err.message : String(err);
151
+ res.writeHead(500);
152
+ res.end(JSON.stringify({ error: msg }));
153
+ }
154
+ });
155
+ // 4️⃣ Inject overlay + HMR
156
+ app.use(async (req, res, next) => {
157
+ if (req.url === '/' || req.url === '/index.html') {
158
+ if (!fs_extra_1.default.existsSync(indexHtml)) {
159
+ res.writeHead(404);
160
+ res.end('index.html not found');
161
+ return;
162
+ }
163
+ let html = await fs_extra_1.default.readFile(indexHtml, 'utf8');
164
+ html = html.replace('</body>', `
165
+ <script type="module">
166
+ import "/@react-refresh";
167
+ import "/@prismjs";
168
+ const ws = new WebSocket("ws://" + location.host);
169
+ ws.onmessage = async (e) => {
170
+ const msg = JSON.parse(e.data);
171
+ if (msg.type === "error") {
172
+ console.error(msg);
173
+ return window.showErrorOverlay?.(msg);
174
+ }
175
+ if (msg.type === "update") {
176
+ try {
177
+ await import(msg.path + "?t=" + Date.now());
178
+ window.clearErrorOverlay?.();
179
+ window.$RefreshRuntime?.performReactRefresh?.();
180
+ } catch (err) {
181
+ window.showErrorOverlay?.(err);
182
+ }
183
+ }
184
+ if (msg.type === "reload") location.reload();
185
+ };
186
+ </script>
187
+ </body>`);
188
+ res.setHeader('Content-Type', 'text/html');
189
+ res.end(html);
190
+ }
191
+ else
192
+ next();
193
+ });
194
+ const server = http_1.default.createServer(app);
195
+ const wss = new ws_1.WebSocketServer({ server });
196
+ const broadcast = (data) => {
197
+ const json = JSON.stringify(data);
198
+ wss.clients.forEach((c) => c.readyState === 1 && c.send(json));
199
+ };
200
+ chokidar_1.default.watch(path_1.default.join(appRoot, 'src'), { ignoreInitial: true }).on('change', async (file) => {
201
+ try {
202
+ console.log(`🔄 Rebuilding: ${file}`);
203
+ await ctx.rebuild();
204
+ broadcast({ type: 'update', path: '/' + path_1.default.relative(appRoot, file).replace(/\\/g, '/') });
205
+ }
206
+ catch (err) {
207
+ if (err instanceof Error) {
208
+ broadcast({ type: 'error', message: err.message, stack: err.stack });
209
+ }
210
+ else {
211
+ broadcast({ type: 'error', message: String(err) });
212
+ }
213
+ }
214
+ });
215
+ server.listen(port, async () => {
216
+ const url = `http://localhost:${port}`;
217
+ console.log(chalk_1.default.green(`\n⚡ Dev Server running at ${url}`));
218
+ if (port !== defaultPort)
219
+ console.log(chalk_1.default.yellow(`⚠️ Using alternate port (default ${defaultPort} was occupied).`));
220
+ await (0, open_1.default)(url, { newInstance: true });
221
+ });
222
+ process.on('SIGINT', async () => {
223
+ console.log(chalk_1.default.red('\n🛑 Shutting down...'));
224
+ await ctx.dispose();
225
+ server.close();
226
+ process.exit(0);
227
+ });
29
228
  }
@@ -3,61 +3,92 @@ 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.default = init;
7
- const fs_extra_1 = __importDefault(require("fs-extra"));
6
+ exports.default = initCmd;
8
7
  const path_1 = __importDefault(require("path"));
9
- async function init(name, opts = {}) {
10
- const root = path_1.default.resolve(process.cwd(), name);
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const prompts_1 = __importDefault(require("prompts"));
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const child_process_1 = require("child_process");
12
+ async function initCmd(name, opts) {
13
+ const root = process.cwd();
14
+ const projectDir = path_1.default.resolve(root, name);
11
15
  const template = opts.template || 'react-ts';
12
- await fs_extra_1.default.ensureDir(root);
13
- // Resolve templates directory by walking up from __dirname until we find a
14
- // `templates` folder. This handles different install layouts (local dev,
15
- // global install, packaged dist) transparently.
16
- let cur = __dirname;
17
- let tplDir = null;
18
- while (true) {
19
- const candidate = path_1.default.join(cur, 'templates');
20
- if (fs_extra_1.default.existsSync(candidate)) {
21
- tplDir = candidate;
22
- break;
16
+ console.log(chalk_1.default.cyan(`\n📦 Creating new React Client app: ${chalk_1.default.bold(name)}`));
17
+ // 1️⃣ Check if directory exists
18
+ if (fs_extra_1.default.existsSync(projectDir)) {
19
+ const res = await (0, prompts_1.default)({
20
+ type: 'confirm',
21
+ name: 'overwrite',
22
+ message: chalk_1.default.yellow(`Directory "${name}" already exists. Overwrite?`),
23
+ initial: false,
24
+ });
25
+ if (!res.overwrite) {
26
+ console.log(chalk_1.default.red('❌ Operation cancelled.'));
27
+ process.exit(1);
23
28
  }
24
- const parent = path_1.default.dirname(cur);
25
- if (parent === cur)
26
- break; // reached filesystem root
27
- cur = parent;
29
+ await fs_extra_1.default.remove(projectDir);
28
30
  }
29
- if (!tplDir) {
30
- console.error('Templates directory not found in package layout');
31
+ await fs_extra_1.default.ensureDir(projectDir);
32
+ // 2️⃣ Locate template
33
+ const templateDir = path_1.default.resolve(__dirname, '../../../templates', template);
34
+ if (!fs_extra_1.default.existsSync(templateDir)) {
35
+ console.error(chalk_1.default.red(`❌ Template not found: ${template}`));
31
36
  process.exit(1);
32
37
  }
33
- const tpl = path_1.default.join(tplDir, template);
34
- if (!fs_extra_1.default.existsSync(tpl)) {
35
- console.error('Template not found:', template);
36
- process.exit(1);
37
- }
38
- await fs_extra_1.default.copy(tpl, root);
39
- // If the template contains a package.json, update its name field to the
40
- // user provided project name so the scaffolded project has the correct
41
- // package identity.
42
- const pkgPath = path_1.default.join(root, 'package.json');
43
- if (fs_extra_1.default.existsSync(pkgPath)) {
44
- try {
45
- const raw = await fs_extra_1.default.readFile(pkgPath, 'utf8');
46
- const pkg = JSON.parse(raw);
47
- // Use the final directory name as the package name so users can pass
48
- // either a simple name ("myapp") or a path ("/abs/path/myapp").
49
- pkg.name = path_1.default.basename(root);
50
- // If template marks package private, leave it as-is; do not force publish.
51
- await fs_extra_1.default.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8');
52
- }
53
- catch (err) {
54
- // Non-fatal: log and continue
55
- console.warn('Warning: could not update package.json name for template:', err);
38
+ // 3️⃣ Copy template
39
+ console.log(chalk_1.default.gray(`\n📁 Copying template: ${template}...`));
40
+ await fs_extra_1.default.copy(templateDir, projectDir);
41
+ // 4️⃣ Optionally create react-client.config.js (not .ts)
42
+ if (opts.withConfig) {
43
+ const configPath = path_1.default.join(projectDir, 'react-client.config.js');
44
+ if (!fs_extra_1.default.existsSync(configPath)) {
45
+ const configContent = `// react-client.config.js
46
+ import { defineConfig } from 'react-client/config';
47
+
48
+ export default defineConfig({
49
+ // 🧭 Root directory for the app
50
+ root: './src',
51
+
52
+ // Dev server settings
53
+ server: {
54
+ port: 5173,
55
+ },
56
+
57
+ // 🏗️ Build options
58
+ build: {
59
+ outDir: '.react-client/build',
60
+ },
61
+
62
+ // 💡 Add plugins, aliases, etc.
63
+ });
64
+ `;
65
+ await fs_extra_1.default.writeFile(configPath, configContent, 'utf8');
66
+ console.log(chalk_1.default.green('📝 Created react-client.config.js'));
56
67
  }
57
68
  }
58
- if (opts.withConfig) {
59
- const cfg = "import { defineConfig } from 'react-client';\nexport default defineConfig({});\n";
60
- await fs_extra_1.default.writeFile(path_1.default.join(root, 'react-client.config.ts'), cfg, 'utf8');
69
+ // 5️⃣ Initialize git repo
70
+ try {
71
+ (0, child_process_1.execSync)('git init', { cwd: projectDir, stdio: 'ignore' });
72
+ console.log(chalk_1.default.gray('🔧 Initialized Git repository.'));
73
+ }
74
+ catch {
75
+ console.warn(chalk_1.default.yellow('⚠️ Git init failed (skipping).'));
76
+ }
77
+ // 6️⃣ Install dependencies
78
+ const pkgManager = /yarn/.test(process.env.npm_execpath || '') ? 'yarn' : 'npm';
79
+ console.log(chalk_1.default.gray(`\n📦 Installing dependencies using ${pkgManager}...`));
80
+ try {
81
+ (0, child_process_1.execSync)(`${pkgManager} install`, { cwd: projectDir, stdio: 'inherit' });
82
+ }
83
+ catch {
84
+ console.warn(chalk_1.default.yellow('⚠️ Dependency installation failed, please run manually.'));
61
85
  }
62
- console.log('Project created at', root);
86
+ // 7️⃣ Completion message
87
+ console.log();
88
+ console.log(chalk_1.default.green('✅ Project setup complete!'));
89
+ console.log(chalk_1.default.cyan(`\nNext steps:`));
90
+ console.log(chalk_1.default.gray(` cd ${name}`));
91
+ console.log(chalk_1.default.gray(` ${pkgManager === 'yarn' ? 'yarn dev' : 'npm run dev'}`));
92
+ console.log();
93
+ console.log(chalk_1.default.dim('Happy coding! ⚡'));
63
94
  }
@@ -4,27 +4,55 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.default = preview;
7
+ const connect_1 = __importDefault(require("connect"));
8
+ const serve_static_1 = __importDefault(require("serve-static"));
7
9
  const http_1 = __importDefault(require("http"));
8
- const fs_1 = __importDefault(require("fs"));
9
10
  const path_1 = __importDefault(require("path"));
11
+ const detect_port_1 = __importDefault(require("detect-port"));
12
+ const prompts_1 = __importDefault(require("prompts"));
13
+ const chalk_1 = __importDefault(require("chalk"));
14
+ const open_1 = __importDefault(require("open"));
15
+ const fs_extra_1 = __importDefault(require("fs-extra"));
16
+ const loadConfig_1 = require("../../utils/loadConfig");
10
17
  async function preview() {
11
- const out = path_1.default.join(process.cwd(), 'dist');
12
- if (!fs_1.default.existsSync(out)) {
13
- console.error('dist not found, run build');
18
+ const root = process.cwd();
19
+ const config = await (0, loadConfig_1.loadReactClientConfig)(root);
20
+ const appRoot = path_1.default.resolve(root, config.root || '.');
21
+ const outDir = path_1.default.join(appRoot, config.build?.outDir || '.react-client/build');
22
+ const defaultPort = config.server?.port || 5173;
23
+ if (!fs_extra_1.default.existsSync(outDir)) {
24
+ console.error(chalk_1.default.red(`❌ Build output not found at: ${outDir}`));
25
+ console.log(chalk_1.default.gray('Please run `react-client build` first.'));
14
26
  process.exit(1);
15
27
  }
16
- const server = http_1.default.createServer((req, res) => {
17
- let url = req.url?.split('?')[0] || '/';
18
- if (url === '/')
19
- url = '/index.html';
20
- const f = path_1.default.join(out, url);
21
- if (fs_1.default.existsSync(f)) {
22
- res.writeHead(200);
23
- res.end(fs_1.default.readFileSync(f));
24
- return;
28
+ const availablePort = await (0, detect_port_1.default)(defaultPort);
29
+ const port = availablePort;
30
+ if (availablePort !== defaultPort) {
31
+ const res = await (0, prompts_1.default)({
32
+ type: 'confirm',
33
+ name: 'useNewPort',
34
+ message: `Port ${defaultPort} is occupied. Use ${availablePort} instead?`,
35
+ initial: true,
36
+ });
37
+ if (!res.useNewPort) {
38
+ console.log(chalk_1.default.red('🛑 Preview server cancelled.'));
39
+ process.exit(0);
25
40
  }
26
- res.writeHead(404);
27
- res.end('Not found');
41
+ }
42
+ const app = (0, connect_1.default)();
43
+ app.use((0, serve_static_1.default)(outDir));
44
+ const server = http_1.default.createServer(app);
45
+ server.listen(port, async () => {
46
+ const url = `http://localhost:${port}`;
47
+ console.log(chalk_1.default.green(`\n🌐 Preview server running at ${url}`));
48
+ if (port !== defaultPort) {
49
+ console.log(chalk_1.default.yellow(`⚠️ Using alternate port (default ${defaultPort} was occupied).`));
50
+ }
51
+ await (0, open_1.default)(url, { newInstance: true });
52
+ });
53
+ process.on('SIGINT', () => {
54
+ console.log(chalk_1.default.red('\n🛑 Shutting down preview server...'));
55
+ server.close();
56
+ process.exit(0);
28
57
  });
29
- server.listen(5000, () => console.log('Preview running at http://localhost:5000'));
30
58
  }
package/dist/cli/index.js CHANGED
@@ -5,43 +5,129 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const commander_1 = require("commander");
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_extra_1 = __importDefault(require("fs-extra"));
10
+ const chalk_1 = __importDefault(require("chalk"));
8
11
  const init_1 = __importDefault(require("./commands/init"));
9
12
  const generate_1 = __importDefault(require("./commands/generate"));
10
13
  const dev_1 = __importDefault(require("./commands/dev"));
11
14
  const build_1 = __importDefault(require("./commands/build"));
12
15
  const build_ssr_1 = __importDefault(require("./commands/build.ssr"));
13
16
  const preview_1 = __importDefault(require("./commands/preview"));
17
+ // Load package.json version dynamically
18
+ const pkgPath = path_1.default.resolve(__dirname, '../../package.json');
19
+ const pkg = fs_extra_1.default.existsSync(pkgPath)
20
+ ? JSON.parse(fs_extra_1.default.readFileSync(pkgPath, 'utf8'))
21
+ : { version: '0.0.0' };
22
+ // 🧠 Fancy startup banner
23
+ function showBanner(cmd) {
24
+ const title = chalk_1.default.bold.cyan('⚡ React Client');
25
+ const version = chalk_1.default.gray(`v${pkg.version}`);
26
+ const tagline = chalk_1.default.dim('Fast esbuild-based React CLI with HMR, SSR & Overlay');
27
+ const line = chalk_1.default.gray('──────────────────────────────────────────────────────────────');
28
+ console.log(`\n${title} ${version}`);
29
+ console.log(tagline);
30
+ console.log(line);
31
+ switch (cmd) {
32
+ case 'init':
33
+ console.log(chalk_1.default.cyan('📦 Initializing new React project...\n'));
34
+ break;
35
+ case 'generate':
36
+ console.log(chalk_1.default.white('✨ Generating boilerplate files...\n'));
37
+ break;
38
+ case 'dev':
39
+ console.log(chalk_1.default.green('🚀 Starting development server...\n'));
40
+ break;
41
+ case 'build':
42
+ console.log(chalk_1.default.yellow('🏗️ Building for production...\n'));
43
+ break;
44
+ case 'build:ssr':
45
+ console.log(chalk_1.default.magenta('🧱 Building for server-side rendering (SSR)...\n'));
46
+ break;
47
+ case 'preview':
48
+ console.log(chalk_1.default.blue('🌐 Starting production preview server...\n'));
49
+ break;
50
+ default:
51
+ console.log();
52
+ }
53
+ }
54
+ // 🧩 Commander setup
14
55
  const program = new commander_1.Command();
15
- program.name('react-client').version('1.0.0').description('react-client CLI');
56
+ program
57
+ .name('react-client')
58
+ .description('react-client CLI – A lightweight React toolkit for fast builds & dev server')
59
+ .version(pkg.version, '-v, --version', 'display version information');
60
+ // ------------------------------------------------------
61
+ // CLI Commands
62
+ // ------------------------------------------------------
16
63
  program
17
64
  .command('init <name>')
18
- .option('-t,--template <template>', 'template', 'react-ts')
19
- .option('--with-config', 'create config')
20
- .action((name, opts) => (0, init_1.default)(name, opts));
65
+ .option('-t, --template <template>', 'choose a template', 'react-ts')
66
+ .option('--with-config', 'create a config file')
67
+ .description('initialize a new React project')
68
+ .action((name, opts) => {
69
+ showBanner('init');
70
+ (0, init_1.default)(name, opts);
71
+ });
21
72
  program
22
73
  .command('generate <kind> <name>')
23
- .option('-p,--path <path>', 'path')
24
- .option('--no-ts', 'generate JS')
25
- .option('-f,--force', 'force')
26
- .action((k, n, o) => (0, generate_1.default)(k, n, o));
74
+ .alias('g')
75
+ .option('-p, --path <path>', 'output path')
76
+ .option('--no-ts', 'generate JS instead of TS')
77
+ .option('-f, --force', 'overwrite if exists')
78
+ .description('generate components, pages, or stores')
79
+ .action((kind, name, opts) => {
80
+ showBanner('generate');
81
+ (0, generate_1.default)(kind, name, opts);
82
+ });
27
83
  program
28
84
  .command('dev')
29
- .description('start dev server')
30
- .action(() => (0, dev_1.default)());
85
+ .description('start dev server (with React Fast Refresh)')
86
+ .action(() => {
87
+ showBanner('dev');
88
+ (0, dev_1.default)();
89
+ });
31
90
  program
32
91
  .command('build')
33
- .description('build app')
34
- .action(() => (0, build_1.default)());
92
+ .description('build production assets')
93
+ .action(() => {
94
+ showBanner('build');
95
+ (0, build_1.default)();
96
+ });
35
97
  program
36
98
  .command('build:ssr')
37
- .description('build ssr')
38
- .action(() => (0, build_ssr_1.default)());
99
+ .description('build for server-side rendering (SSR)')
100
+ .action(() => {
101
+ showBanner('build:ssr');
102
+ (0, build_ssr_1.default)();
103
+ });
39
104
  program
40
105
  .command('preview')
41
- .description('preview build')
42
- .action(() => (0, preview_1.default)());
43
- // Only parse argv when executed directly as a CLI, not when imported by tests or other code.
106
+ .description('preview production build')
107
+ .action(() => {
108
+ showBanner('preview');
109
+ (0, preview_1.default)();
110
+ });
111
+ // ------------------------------------------------------
112
+ // Default / Unknown command handling
113
+ // ------------------------------------------------------
114
+ program.on('command:*', () => {
115
+ console.error(chalk_1.default.red('❌ Invalid command:'), program.args.join(' '));
116
+ console.log();
117
+ program.outputHelp();
118
+ process.exit(1);
119
+ });
120
+ // ------------------------------------------------------
121
+ // Entry point
122
+ // ------------------------------------------------------
44
123
  if (require.main === module) {
45
- program.parse(process.argv);
124
+ if (process.argv.length <= 2) {
125
+ console.clear();
126
+ showBanner();
127
+ program.outputHelp();
128
+ }
129
+ else {
130
+ program.parse(process.argv);
131
+ }
46
132
  }
47
133
  exports.default = program;