react-client 1.0.1 → 1.0.6

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Venkatesh Sundaram
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,141 @@
1
+ [![npm](https://img.shields.io/npm/v/react-client.svg)](https://www.npmjs.com/package/react-client)
2
+ [![npm](https://img.shields.io/npm/dt/react-client.svg)](https://npm-stat.com/charts.html?package=react-client)
3
+ [![GitHub issues](https://img.shields.io/github/issues/venkateshsundaram/react-client.svg)](https://github.com/venkateshsundaram/react-client/issues)
4
+
5
+ react-client is a lightweight CLI and runtime for building React apps with fast iteration. It is designed to be esbuild-based, Node-native, and modular like Vite/Next.js while remaining minimal.
6
+
7
+ ## Table of Contents
8
+ - [Installation](#installation)
9
+ - [With Config](#with-config)
10
+ - [Wiki](#wiki)
11
+ - [Available templates](#available-templates)
12
+ - [Features supported by the CLI](#features-supported-by-the-cli)
13
+ - [Template specifics](#template-specifics)
14
+ * [react-ssr-ts](#react-ssr-ts)
15
+ * [react-tailwind-ts](#react-tailwind-ts)
16
+ - [How the CLI wires features](#how-the-cli-wires-features)
17
+ - [Local testing checklist](#local-testing-checklist)
18
+ - [Troubleshooting](#troubleshooting)
19
+ - [Extending & Contributing](#extending-contributing)
20
+ - [Contributing](#contributing)
21
+ - [Publishing](#publishing)
22
+ - [Feedbacks and Issues](#feedbacks-and-issues)
23
+ - [License](#license)
24
+
25
+ ## Installation
26
+
27
+ The React-client package lives in npm.
28
+
29
+ To install the latest stable version, run the following command:
30
+
31
+ ```bash
32
+ npm install -g react-client
33
+ react-client init myapp --template react-ts
34
+ cd myapp
35
+ npm run dev
36
+ ```
37
+
38
+ ## With Config
39
+
40
+ The `init` command supports a small set of helpers for scaffolding projects from the bundled templates. Notably:
41
+
42
+ - `--template <name>`: choose a template (defaults to `react-ts`).
43
+ - `--with-config`: also create a `react-client.config.ts` file in the generated project with a minimal `defineConfig({})` stub.
44
+
45
+ Example:
46
+
47
+ ```bash
48
+ react-client init myapp --template react-ts --with-config
49
+ # creates `myapp/` and writes `myapp/react-client.config.ts`
50
+ ```
51
+
52
+ ## Wiki
53
+
54
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/venkateshsundaram/react-client)
55
+
56
+ ## Available templates
57
+
58
+ - react — JavaScript SPA
59
+ - react-ts — TypeScript SPA
60
+ - react-ssr — JavaScript SSR app
61
+ - react-ssr-ts — TypeScript SSR app
62
+ - react-tailwind — JavaScript + Tailwind
63
+ - react-tailwind-ts — TypeScript + Tailwind
64
+
65
+ ## Features supported by the CLI
66
+
67
+ - React Fast Refresh: HMR that preserves component state
68
+ - PostCSS/Tailwind auto-injection and setup for Tailwind templates
69
+ - CSS Modules support with hashing and AST-based import rewriting
70
+ - Asset hashing and manifest generation for SSR runtime lookups
71
+ - Plugin hook system (configResolved, transform, buildEnd)
72
+ - Generators: component/route/test scaffolding
73
+ - SSR runtime with server that consults manifest.json
74
+
75
+ ## Template specifics
76
+
77
+ ### react-ssr-ts
78
+
79
+ - `src/entry-client.tsx` — client hydration entry
80
+ - `src/entry-server.tsx` — server rendering entry (exports `render(url)`)
81
+ - `src/pages/` — route components
82
+ - `index.html` — template used by build system
83
+ - `package.json` lists devDependencies required for local testing (esbuild, react-refresh)
84
+
85
+ ### react-tailwind-ts
86
+
87
+ - `postcss.config.cjs` and `tailwind.config.cjs` included
88
+ - `src/index.css` with Tailwind directives
89
+ - `package.json` includes tailwind/postcss devDependencies (install locally in the app)
90
+
91
+ ## How the CLI wires features
92
+
93
+ 1. **HMR & React Refresh**: dev plugin injects `import '/@react-refresh-shim'` into files that import React. During build, the CLI attempts to `require.resolve('react-refresh/runtime')` and copy it into the client vendor folder to be included in bundles.
94
+ 2. **CSS Modules**: build step uses `postcss-modules` to produce JSON class maps and then uses `es-module-lexer` + `magic-string` to rewrite `.module.css` import specifiers to the hashed filenames emitted by the bundler.
95
+ 3. **Manifest**: after building, the CLI hashes outputs and writes `client/manifest.json` mapping original -> hashed filenames. The SSR server uses this manifest to serve correct hashed assets and update HTML script tags dynamically.
96
+ 4. **PostCSS/Tailwind**: if `postcss.config.cjs` or `tailwind.config.cjs` exists in the project, the build process runs `npx postcss` to process CSS and includes the output in the final client bundle.
97
+
98
+ ## Local testing checklist
99
+
100
+ 1. Node 20+ installed.
101
+ 2. Scaffold a new app using the CLI `init` command pointing to these templates.
102
+ 3. `npm install` in the new app to get dependencies.
103
+ 4. Run `node /path/to/react-client/dist/cli/index.js dev` for HMR-enabled dev server, or `build:ssr` to produce SSR build and run `node dist/server/server.js` to preview.
104
+
105
+ ## Troubleshooting
106
+
107
+ - If `react-refresh/runtime` isn't found during build, install in the environment running the CLI:
108
+ ```bash
109
+ npm install --save-dev react-refresh
110
+ ```
111
+ - For PostCSS/Tailwind errors, ensure tailwind & postcss installed in the target app:
112
+ ```bash
113
+ npm install --save-dev tailwindcss postcss autoprefixer
114
+ ```
115
+ - For AST rewriting, ensure `es-module-lexer` and `magic-string` are installed where the CLI runs:
116
+ ```bash
117
+ npm install --save-dev es-module-lexer magic-string
118
+ ```
119
+
120
+ ## Extending & Contributing
121
+
122
+ - Add plugins under `src/plugins` with `configResolved` and `transform` hooks.
123
+ - Tests: add Jest configurations inside templates and include `test` npm scripts.
124
+
125
+ ## Contributing
126
+
127
+ Development of react-client happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving react-client.
128
+
129
+ - [Contributing Guide](./CONTRIBUTING.md)
130
+
131
+ ## Publishing
132
+
133
+ Before pushing your changes to Github, make sure that `version` in `package.json` is changed to newest version. Then run `npm install` for synchronize it to `package-lock.json` and `pnpm install` for synchronize it to `pnpm-lock.yaml`
134
+
135
+ ## Feedbacks and Issues
136
+
137
+ Feel free to open issues if you found any feedback or issues on `react-client`. And feel free if you want to contribute too! 😄
138
+
139
+ ## License
140
+
141
+ React-client is [MIT licensed](./LICENSE).
@@ -0,0 +1,61 @@
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.default = build;
7
+ const esbuild_1 = __importDefault(require("esbuild"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_extra_1 = __importDefault(require("fs-extra"));
10
+ const child_process_1 = require("child_process");
11
+ const crypto_1 = __importDefault(require("crypto"));
12
+ function hash(buf) {
13
+ return crypto_1.default.createHash('sha256').update(buf).digest('hex').slice(0, 8);
14
+ }
15
+ async function build() {
16
+ const root = process.cwd();
17
+ const entry = path_1.default.join(root, 'src', 'main.tsx');
18
+ const out = path_1.default.join(root, 'dist');
19
+ await fs_extra_1.default.remove(out);
20
+ const result = await esbuild_1.default.build({
21
+ entryPoints: [entry],
22
+ bundle: true,
23
+ outdir: path_1.default.join(out, 'client'),
24
+ metafile: true,
25
+ minify: true,
26
+ loader: {
27
+ '.ts': 'ts',
28
+ '.tsx': 'tsx',
29
+ '.js': 'jsx',
30
+ '.jsx': 'jsx',
31
+ '.png': 'file',
32
+ '.jpg': 'file',
33
+ '.svg': 'file',
34
+ },
35
+ });
36
+ const postcssConfig = path_1.default.join(root, 'postcss.config.cjs');
37
+ if (fs_extra_1.default.existsSync(postcssConfig)) {
38
+ try {
39
+ (0, child_process_1.execSync)('npx postcss ' + path_1.default.join(out, 'client', '*.css') + ' -d ' + path_1.default.join(out, 'client'));
40
+ }
41
+ catch (e) {
42
+ console.warn('PostCSS failed', e && e.message);
43
+ }
44
+ }
45
+ const manifest = {};
46
+ for (const outPath in result.metafile.outputs) {
47
+ const abs = path_1.default.join(root, outPath);
48
+ if (!fs_extra_1.default.existsSync(abs))
49
+ continue;
50
+ const data = await fs_extra_1.default.readFile(abs);
51
+ const h = hash(data);
52
+ const rel = outPath.replace(/^client\//, '');
53
+ const ext = path_1.default.extname(rel);
54
+ const hashed = rel.replace(ext, '.' + h + ext);
55
+ await fs_extra_1.default.ensureDir(path_1.default.join(out, 'client', path_1.default.dirname(hashed)));
56
+ await fs_extra_1.default.move(abs, path_1.default.join(out, 'client', hashed));
57
+ manifest[rel] = hashed;
58
+ }
59
+ await fs_extra_1.default.writeFile(path_1.default.join(out, 'client', 'manifest.json'), JSON.stringify(manifest, null, 2), 'utf8');
60
+ console.log('Built client to', path_1.default.join(out, 'client'));
61
+ }
@@ -0,0 +1,69 @@
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.default = buildSsr;
7
+ const esbuild_1 = __importDefault(require("esbuild"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_extra_1 = __importDefault(require("fs-extra"));
10
+ const crypto_1 = __importDefault(require("crypto"));
11
+ function hash(buf) {
12
+ return crypto_1.default.createHash('sha256').update(buf).digest('hex').slice(0, 8);
13
+ }
14
+ async function buildSsr() {
15
+ const root = process.cwd();
16
+ const clientEntry = path_1.default.join(root, 'src', 'entry-client.tsx');
17
+ const serverEntry = path_1.default.join(root, 'src', 'entry-server.tsx');
18
+ if (!fs_extra_1.default.existsSync(clientEntry) || !fs_extra_1.default.existsSync(serverEntry)) {
19
+ console.error('SSR entries missing');
20
+ process.exit(1);
21
+ }
22
+ const out = path_1.default.join(root, 'dist');
23
+ await fs_extra_1.default.remove(out);
24
+ const clientResult = await esbuild_1.default.build({
25
+ entryPoints: [clientEntry],
26
+ bundle: true,
27
+ outdir: path_1.default.join(out, 'client'),
28
+ metafile: true,
29
+ minify: true,
30
+ loader: {
31
+ '.ts': 'ts',
32
+ '.tsx': 'tsx',
33
+ '.js': 'jsx',
34
+ '.jsx': 'jsx',
35
+ '.png': 'file',
36
+ '.jpg': 'file',
37
+ '.svg': 'file',
38
+ },
39
+ });
40
+ const _serverResult = await esbuild_1.default.build({
41
+ entryPoints: [serverEntry],
42
+ bundle: true,
43
+ platform: 'node',
44
+ format: 'cjs',
45
+ outfile: path_1.default.join(out, 'server', 'entry-server.js'),
46
+ external: ['react', 'react-dom'],
47
+ });
48
+ const manifest = {};
49
+ for (const outPath in clientResult.metafile.outputs) {
50
+ if (!outPath.startsWith('client/'))
51
+ continue;
52
+ const abs = path_1.default.join(out, outPath);
53
+ if (!fs_extra_1.default.existsSync(abs))
54
+ continue;
55
+ const data = await fs_extra_1.default.readFile(abs);
56
+ const h = hash(data);
57
+ const rel = outPath.replace(/^client\//, '');
58
+ const ext = path_1.default.extname(rel);
59
+ const hashed = rel.replace(ext, '.' + h + ext);
60
+ await fs_extra_1.default.ensureDir(path_1.default.join(out, 'client', path_1.default.dirname(hashed)));
61
+ await fs_extra_1.default.move(abs, path_1.default.join(out, 'client', hashed));
62
+ manifest[rel] = hashed;
63
+ }
64
+ await fs_extra_1.default.writeFile(path_1.default.join(out, 'client', 'manifest.json'), JSON.stringify(manifest, null, 2), 'utf8');
65
+ const runtime = `const http = require('http');const fs = require('fs');const path=require('path');const { render } = require('./entry-server.js');const clientDir = path.join(__dirname,'..','client');const manifest = JSON.parse(fs.readFileSync(path.join(clientDir,'manifest.json'),'utf8'));const PORT = process.env.PORT||3000;const server = http.createServer(async (req,res)=>{ try{ if(req.url && req.url.startsWith('/client/')){ const rel = req.url.replace('/client/',''); const mapped = manifest[rel] || rel; const p = path.join(clientDir, mapped); if(fs.existsSync(p)) { res.writeHead(200); res.end(fs.readFileSync(p)); return; } } const htmlPath = path.join(clientDir,'index.html'); let html = '<!doctype html><html><head></head><body><div id="root"></div><script type="module" src="/client/bundle.js"></script></body></html>'; if(fs.existsSync(htmlPath)) html = fs.readFileSync(htmlPath,'utf8'); const content = await render(req.url||'/'); const outHtml = html.replace('<div id="root"></div>','<div id="root">'+content+'</div>'); res.writeHead(200,{'Content-Type':'text/html'}); res.end(outHtml);}catch(e){ console.error(e); res.writeHead(500); res.end('SSR error');}});server.listen(PORT,()=>console.log('SSR server running on port '+PORT));`;
66
+ await fs_extra_1.default.ensureDir(path_1.default.join(out, 'server'));
67
+ await fs_extra_1.default.writeFile(path_1.default.join(out, 'server', 'server.js'), runtime, 'utf8');
68
+ console.log('SSR build complete at', out);
69
+ }
@@ -0,0 +1,29 @@
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.default = dev;
7
+ const esbuild_1 = __importDefault(require("esbuild"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_extra_1 = __importDefault(require("fs-extra"));
10
+ async function dev() {
11
+ const root = process.cwd();
12
+ const entry = path_1.default.join(root, 'src', 'main.tsx');
13
+ if (!fs_extra_1.default.existsSync(entry)) {
14
+ console.error('Entry not found: src/main.tsx');
15
+ process.exit(1);
16
+ }
17
+ const outdir = path_1.default.join(root, '.react-client', 'dev');
18
+ await fs_extra_1.default.ensureDir(outdir);
19
+ const ctx = await esbuild_1.default.context({
20
+ entryPoints: [entry],
21
+ bundle: true,
22
+ sourcemap: true,
23
+ outdir,
24
+ define: { 'process.env.NODE_ENV': '"development"' },
25
+ loader: { '.ts': 'ts', '.tsx': 'tsx', '.js': 'jsx', '.jsx': 'jsx' },
26
+ });
27
+ await ctx.watch();
28
+ await ctx.serve({ servedir: outdir, port: 5173 });
29
+ }
@@ -0,0 +1,42 @@
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.default = generate;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const string_1 = require("../../utils/string");
10
+ async function generate(kind, name, opts = {}) {
11
+ const root = process.cwd();
12
+ const useTS = opts.ts !== false && opts['no-ts'] !== true;
13
+ if (kind === 'component') {
14
+ const pascal = (0, string_1.pascalCase)(name);
15
+ const dir = path_1.default.join(root, opts.path || 'src/components');
16
+ await fs_extra_1.default.ensureDir(dir);
17
+ const ext = useTS ? 'tsx' : 'jsx';
18
+ const compPath = path_1.default.join(dir, `${pascal}.${ext}`);
19
+ const css = path_1.default.join(dir, `${pascal}.module.css`);
20
+ await fs_extra_1.default.writeFile(compPath, `import React from 'react';\nimport styles from './${pascal}.module.css';\nexport default function ${pascal}(){ return <div className={styles.root}>${pascal}</div>; }\n`);
21
+ await fs_extra_1.default.writeFile(css, `.root{display:block}`);
22
+ console.log('Created component', compPath);
23
+ return;
24
+ }
25
+ if (kind === 'route') {
26
+ const parts = name.replace(/^\//, '').split('/').filter(Boolean);
27
+ const pages = path_1.default.join(root, 'src', 'pages', ...parts.slice(0, -1));
28
+ await fs_extra_1.default.ensureDir(pages);
29
+ const last = parts[parts.length - 1] || 'index';
30
+ const file = path_1.default.join(pages, last + '.' + (useTS ? 'tsx' : 'jsx'));
31
+ if (await fs_extra_1.default.pathExists(file)) {
32
+ console.error('Route exists');
33
+ return;
34
+ }
35
+ const compName = (0, string_1.pascalCase)(parts.join('-') || 'IndexPage');
36
+ const content = `import React from 'react';\nexport default function ${compName}(){ return (<div style={{padding:20}}><h1>${compName}</h1></div>); }\n`;
37
+ await fs_extra_1.default.writeFile(file, content, 'utf8');
38
+ console.log('Created route', file);
39
+ return;
40
+ }
41
+ console.log('Unknown generator', kind);
42
+ }
@@ -0,0 +1,44 @@
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.default = init;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ async function init(name, opts = {}) {
10
+ const root = path_1.default.resolve(process.cwd(), name);
11
+ 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;
23
+ }
24
+ const parent = path_1.default.dirname(cur);
25
+ if (parent === cur)
26
+ break; // reached filesystem root
27
+ cur = parent;
28
+ }
29
+ if (!tplDir) {
30
+ console.error('Templates directory not found in package layout');
31
+ process.exit(1);
32
+ }
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 (opts.withConfig) {
40
+ const cfg = "import { defineConfig } from 'react-client';\nexport default defineConfig({});\n";
41
+ await fs_extra_1.default.writeFile(path_1.default.join(root, 'react-client.config.ts'), cfg, 'utf8');
42
+ }
43
+ console.log('Project created at', root);
44
+ }
@@ -0,0 +1,30 @@
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.default = preview;
7
+ const http_1 = __importDefault(require("http"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ 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');
14
+ process.exit(1);
15
+ }
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;
25
+ }
26
+ res.writeHead(404);
27
+ res.end('Not found');
28
+ });
29
+ server.listen(5000, () => console.log('Preview running at http://localhost:5000'));
30
+ }
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const init_1 = __importDefault(require("./commands/init"));
9
+ const generate_1 = __importDefault(require("./commands/generate"));
10
+ const dev_1 = __importDefault(require("./commands/dev"));
11
+ const build_1 = __importDefault(require("./commands/build"));
12
+ const build_ssr_1 = __importDefault(require("./commands/build.ssr"));
13
+ const preview_1 = __importDefault(require("./commands/preview"));
14
+ const program = new commander_1.Command();
15
+ program.name('react-client').version('1.0.0').description('react-client CLI');
16
+ program
17
+ .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));
21
+ program
22
+ .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));
27
+ program
28
+ .command('dev')
29
+ .description('start dev server')
30
+ .action(() => (0, dev_1.default)());
31
+ program
32
+ .command('build')
33
+ .description('build app')
34
+ .action(() => (0, build_1.default)());
35
+ program
36
+ .command('build:ssr')
37
+ .description('build ssr')
38
+ .action(() => (0, build_ssr_1.default)());
39
+ program
40
+ .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.
44
+ if (require.main === module) {
45
+ program.parse(process.argv);
46
+ }
47
+ exports.default = program;
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = {};
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.defineConfig = void 0;
18
+ const defineConfig = (c) => c;
19
+ exports.defineConfig = defineConfig;
20
+ __exportStar(require("./cli/index"), exports);
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pascalCase = pascalCase;
4
+ function pascalCase(s) {
5
+ return s.replace(/(^|[-_/\s]+)([a-zA-Z])/g, (_, __, ch) => ch.toUpperCase());
6
+ }
package/package.json CHANGED
@@ -1,17 +1,100 @@
1
1
  {
2
2
  "name": "react-client",
3
- "version": "1.0.1",
4
- "description": "react client command",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
3
+ "version": "1.0.6",
4
+ "description": "react-client is a lightweight CLI and runtime for building React apps with fast iteration. It is designed to be esbuild-based, Node-native, and modular like Vite/Next.js with SSR, HMR, Tailwind, CSS Modules, and generators.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "sideEffects": false,
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "bin": {
12
+ "react-client": "dist/cli/index.js"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/venkateshsundaram/react-client.git"
8
17
  },
9
18
  "keywords": [
10
19
  "react",
20
+ "javascript",
21
+ "typescript",
11
22
  "cli",
12
23
  "react-cli",
13
- "react-client"
24
+ "react-client",
25
+ "ssr",
26
+ "esbuild",
27
+ "tailwind",
28
+ "css-modules",
29
+ "hmr",
30
+ "framework",
31
+ "tooling"
14
32
  ],
15
- "author": "venkateshguru2661994@gmail.com",
16
- "license": "MIT"
33
+ "author": "venkateshsundaram",
34
+ "license": "MIT",
35
+ "workspaces": [
36
+ "templates/*"
37
+ ],
38
+ "bugs": {
39
+ "url": "https://github.com/venkateshsundaram/react-client/issues"
40
+ },
41
+ "scripts": {
42
+ "clean": "rm -rf dist",
43
+ "compile": "tsc -p tsconfig.build.json",
44
+ "build": "npm run clean && npm run compile",
45
+ "build:cli": "node dist/cli/index.js build",
46
+ "build:ssr": "node dist/cli/index.js build:ssr",
47
+ "dev": "node dist/cli/index.js dev",
48
+ "prepare": "npm run compile",
49
+ "lint": "eslint . --ext .ts",
50
+ "format": "prettier --write \"src/**/*.ts\"",
51
+ "format:check": "prettier --check \"src/**/*.ts\"",
52
+ "release": "standard-version",
53
+ "postrelease": "git push --follow-tags",
54
+ "prepublishOnly": "npm run compile",
55
+ "test": "jest",
56
+ "typecheck": "tsc --noEmit"
57
+ },
58
+ "husky": {
59
+ "hooks": {
60
+ "pre-commit": "lint-staged"
61
+ }
62
+ },
63
+ "lint-staged": {
64
+ "*.ts": [
65
+ "eslint --fix",
66
+ "prettier --write"
67
+ ]
68
+ },
69
+ "commitlint": {
70
+ "extends": [
71
+ "@commitlint/config-conventional"
72
+ ]
73
+ },
74
+ "devDependencies": {
75
+ "@commitlint/cli": "^19.8.0",
76
+ "@commitlint/config-conventional": "^19.8.0",
77
+ "@types/commander": "^2.12.0",
78
+ "@types/fs-extra": "^9.0.13",
79
+ "@types/jest": "^29.0.0",
80
+ "@types/node": "^18.0.0",
81
+ "@typescript-eslint/eslint-plugin": "^8.46.3",
82
+ "@typescript-eslint/parser": "^8.46.3",
83
+ "eslint": "^8.0.0",
84
+ "eslint-config-prettier": "^8.0.0",
85
+ "eslint-plugin-prettier": "^4.0.0",
86
+ "eslint-plugin-react": "^7.32.2",
87
+ "husky": "^9.1.7",
88
+ "jest": "^29.0.0",
89
+ "lint-staged": "^15.4.3",
90
+ "prettier": "^2.8.8",
91
+ "standard-version": "^9.5.0",
92
+ "ts-jest": "^29.0.0",
93
+ "typescript": "^5.3.0"
94
+ },
95
+ "dependencies": {
96
+ "commander": "^14.0.2",
97
+ "fs-extra": "^11.1.1",
98
+ "esbuild": "^0.25.12"
99
+ }
17
100
  }
package/index.js DELETED
@@ -1,3 +0,0 @@
1
- exports.print =function() {
2
- console.log('welcome to react cli');
3
- }