react-client 1.0.8 β†’ 1.0.10

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.
Files changed (39) hide show
  1. package/README.md +0 -22
  2. package/dist/cli/commands/dev.js +35 -7
  3. package/dist/cli/index.js +1 -27
  4. package/dist/utils/loadConfig.js +31 -33
  5. package/package.json +23 -17
  6. package/templates/react/index.html +13 -1
  7. package/templates/react/public/favicon.ico +0 -0
  8. package/templates/react/src/App.jsx +1 -1
  9. package/templates/react/src/main.jsx +6 -1
  10. package/templates/react-tailwind/index.html +13 -1
  11. package/templates/react-tailwind/public/favicon.ico +0 -0
  12. package/templates/react-tailwind/src/App.jsx +3 -1
  13. package/templates/react-tailwind/src/index.css +1 -0
  14. package/templates/react-tailwind/src/main.jsx +9 -1
  15. package/templates/react-tailwind-ts/index.html +13 -1
  16. package/templates/react-tailwind-ts/public/favicon.ico +0 -0
  17. package/templates/react-tailwind-ts/src/App.tsx +3 -1
  18. package/templates/react-tailwind-ts/src/main.tsx +1 -0
  19. package/templates/react-ts/index.html +13 -1
  20. package/templates/react-ts/public/favicon.ico +0 -0
  21. package/templates/react-ts/src/main.tsx +6 -1
  22. package/templates/{react-ssr-ts β†’ react-ts}/tsconfig.json +1 -2
  23. package/dist/cli/commands/build.ssr.js +0 -46
  24. package/dist/cli/commands/generate.js +0 -42
  25. package/templates/react-ssr/index.html +0 -1
  26. package/templates/react-ssr/package.json +0 -14
  27. package/templates/react-ssr/src/entry-client.jsx +0 -1
  28. package/templates/react-ssr/src/entry-server.jsx +0 -1
  29. package/templates/react-ssr/src/pages/index.jsx +0 -1
  30. package/templates/react-ssr-ts/index.html +0 -1
  31. package/templates/react-ssr-ts/package.json +0 -21
  32. package/templates/react-ssr-ts/src/entry-client.js +0 -5
  33. package/templates/react-ssr-ts/src/entry-client.tsx +0 -6
  34. package/templates/react-ssr-ts/src/entry-server.js +0 -4
  35. package/templates/react-ssr-ts/src/entry-server.tsx +0 -5
  36. package/templates/react-ssr-ts/src/pages/index.js +0 -2
  37. package/templates/react-ssr-ts/src/pages/index.tsx +0 -3
  38. package/templates/react-tailwind-ts/src/App.js +0 -2
  39. package/templates/react-tailwind-ts/src/main.js +0 -7
package/README.md CHANGED
@@ -76,8 +76,6 @@ export default defineConfig({
76
76
  |-----------|-------------|
77
77
  | `react` | JavaScript SPA |
78
78
  | `react-ts` | TypeScript SPA |
79
- | `react-ssr` | JavaScript SSR |
80
- | `react-ssr-ts` | TypeScript SSR |
81
79
  | `react-tailwind` | JS + Tailwind |
82
80
  | `react-tailwind-ts` | TS + Tailwind |
83
81
 
@@ -94,8 +92,6 @@ Each template is pre-configured for esbuild, HMR, and fast bootstrapping.
94
92
  - πŸ’¬ **Auto Port Detection** β€” Prompts when default port 5173 is occupied
95
93
  - 🧠 **Smart Config Loader** β€” Detects project root, compiles `.ts` configs dynamically
96
94
  - 🎨 **PrismJS Highlighting** β€” For pretty overlay code frames
97
- - 🧱 **SSR Runtime Support** β€” For server-side templates (`react-ssr*`)
98
- - 🧩 **Generators** β€” Create components, routes, and tests instantly
99
95
  - πŸ”Œ **Plugin Hook System** β€” Extendable with `configResolved`, `transform`, `buildEnd`
100
96
 
101
97
  ---
@@ -200,21 +196,3 @@ Found an issue or have a feature request?
200
196
  ## πŸͺͺ License
201
197
 
202
198
  **MIT Licensed** Β© [Venkatesh Sundaram](https://github.com/venkateshsundaram)
203
-
204
- ---
205
-
206
- ## πŸ—ΊοΈ Architecture Overview (Bonus)
207
-
208
- ```text
209
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
210
- β”‚ react-client (CLI) β”‚
211
- β”‚ β”œβ”€β”€ esbuild (watch/bundle)
212
- β”‚ β”œβ”€β”€ connect (dev server)
213
- β”‚ β”œβ”€β”€ websocket (HMR)
214
- β”‚ β”œβ”€β”€ prismjs overlay
215
- β”‚ └── chokidar (file watch)
216
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
217
- β”‚
218
- β–Ό
219
- Browser ↔ Live HMR + Overlay
220
- ```
@@ -32,6 +32,7 @@ async function dev() {
32
32
  process.exit(1);
33
33
  }
34
34
  await fs_extra_1.default.ensureDir(outDir);
35
+ // 🧠 Detect open port
35
36
  const availablePort = await (0, detect_port_1.default)(defaultPort);
36
37
  const port = availablePort;
37
38
  if (availablePort !== defaultPort) {
@@ -79,17 +80,35 @@ async function dev() {
79
80
  outdir: outDir,
80
81
  define: { 'process.env.NODE_ENV': '"development"' },
81
82
  loader: { '.ts': 'ts', '.tsx': 'tsx', '.js': 'jsx', '.jsx': 'jsx' },
83
+ entryNames: '[name]', // βœ… output main.js (not src/main.js)
84
+ assetNames: 'assets/[name]',
82
85
  });
83
86
  await ctx.watch();
87
+ console.log(chalk_1.default.gray('πŸ“¦ Watching and building dev bundle...'));
88
+ console.log(chalk_1.default.gray(' Output dir:'), chalk_1.default.blue(outDir));
89
+ console.log(chalk_1.default.gray(' Entry file:'), chalk_1.default.yellow(entry));
84
90
  // 🌐 connect server
85
91
  const app = (0, connect_1.default)();
86
- // 1️⃣ Serve react-refresh runtime
92
+ // πŸ›‘ Security headers
93
+ app.use((_req, res, next) => {
94
+ res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
95
+ res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
96
+ next();
97
+ });
98
+ // 1️⃣ Serve react-refresh runtime with safe browser shim
87
99
  app.use('/@react-refresh', async (_req, res) => {
88
100
  const runtime = await fs_extra_1.default.readFile(reactRefreshRuntime, 'utf8');
101
+ const shim = `
102
+ // React Refresh browser shims
103
+ window.process = window.process || { env: { NODE_ENV: 'development' } };
104
+ window.module = { exports: {} };
105
+ window.global = window;
106
+ window.require = () => window.module.exports;
107
+ `;
89
108
  res.setHeader('Content-Type', 'application/javascript');
90
- res.end(runtime);
109
+ res.end(shim + '\n' + runtime);
91
110
  });
92
- // 2️⃣ Serve PrismJS for highlighting
111
+ // 2️⃣ Serve PrismJS for code highlighting (overlay)
93
112
  app.use('/@prismjs', async (_req, res) => {
94
113
  const prismPath = require.resolve('prismjs/prism.js');
95
114
  const css = await fs_extra_1.default.readFile(require.resolve('prismjs/themes/prism-tomorrow.css'), 'utf8');
@@ -104,7 +123,7 @@ async function dev() {
104
123
  })();
105
124
  `);
106
125
  });
107
- // 3️⃣ Serve source map resolver
126
+ // 3️⃣ Source map resolver (for overlay stack trace)
108
127
  app.use('/@source-map', async (req, res) => {
109
128
  const url = new URL(req.url ?? '', `http://localhost:${port}`);
110
129
  const file = url.searchParams.get('file');
@@ -152,7 +171,7 @@ async function dev() {
152
171
  res.end(JSON.stringify({ error: msg }));
153
172
  }
154
173
  });
155
- // 4️⃣ Inject overlay + HMR
174
+ // 4️⃣ Serve index.html with injected refresh + HMR
156
175
  app.use(async (req, res, next) => {
157
176
  if (req.url === '/' || req.url === '/index.html') {
158
177
  if (!fs_extra_1.default.existsSync(indexHtml)) {
@@ -188,8 +207,17 @@ async function dev() {
188
207
  res.setHeader('Content-Type', 'text/html');
189
208
  res.end(html);
190
209
  }
191
- else
192
- next();
210
+ else {
211
+ // βœ… Serve compiled output files
212
+ const filePath = path_1.default.join(outDir, req.url || '');
213
+ if (await fs_extra_1.default.pathExists(filePath)) {
214
+ const content = await fs_extra_1.default.readFile(filePath);
215
+ res.setHeader('Content-Type', 'application/javascript');
216
+ res.end(content);
217
+ }
218
+ else
219
+ next();
220
+ }
193
221
  });
194
222
  const server = http_1.default.createServer(app);
195
223
  const wss = new ws_1.WebSocketServer({ server });
package/dist/cli/index.js CHANGED
@@ -9,10 +9,8 @@ const path_1 = __importDefault(require("path"));
9
9
  const fs_extra_1 = __importDefault(require("fs-extra"));
10
10
  const chalk_1 = __importDefault(require("chalk"));
11
11
  const init_1 = __importDefault(require("./commands/init"));
12
- const generate_1 = __importDefault(require("./commands/generate"));
13
12
  const dev_1 = __importDefault(require("./commands/dev"));
14
13
  const build_1 = __importDefault(require("./commands/build"));
15
- const build_ssr_1 = __importDefault(require("./commands/build.ssr"));
16
14
  const preview_1 = __importDefault(require("./commands/preview"));
17
15
  // Load package.json version dynamically
18
16
  const pkgPath = path_1.default.resolve(__dirname, '../../package.json');
@@ -23,7 +21,7 @@ const pkg = fs_extra_1.default.existsSync(pkgPath)
23
21
  function showBanner(cmd) {
24
22
  const title = chalk_1.default.bold.cyan('⚑ React Client');
25
23
  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');
24
+ const tagline = chalk_1.default.dim('Fast esbuild-based React CLI with HMR & Overlay');
27
25
  const line = chalk_1.default.gray('──────────────────────────────────────────────────────────────');
28
26
  console.log(`\n${title} ${version}`);
29
27
  console.log(tagline);
@@ -32,18 +30,12 @@ function showBanner(cmd) {
32
30
  case 'init':
33
31
  console.log(chalk_1.default.cyan('πŸ“¦ Initializing new React project...\n'));
34
32
  break;
35
- case 'generate':
36
- console.log(chalk_1.default.white('✨ Generating boilerplate files...\n'));
37
- break;
38
33
  case 'dev':
39
34
  console.log(chalk_1.default.green('πŸš€ Starting development server...\n'));
40
35
  break;
41
36
  case 'build':
42
37
  console.log(chalk_1.default.yellow('πŸ—οΈ Building for production...\n'));
43
38
  break;
44
- case 'build:ssr':
45
- console.log(chalk_1.default.magenta('🧱 Building for server-side rendering (SSR)...\n'));
46
- break;
47
39
  case 'preview':
48
40
  console.log(chalk_1.default.blue('🌐 Starting production preview server...\n'));
49
41
  break;
@@ -69,17 +61,6 @@ program
69
61
  showBanner('init');
70
62
  (0, init_1.default)(name, opts);
71
63
  });
72
- program
73
- .command('generate <kind> <name>')
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
- });
83
64
  program
84
65
  .command('dev')
85
66
  .description('start dev server (with React Fast Refresh)')
@@ -94,13 +75,6 @@ program
94
75
  showBanner('build');
95
76
  (0, build_1.default)();
96
77
  });
97
- program
98
- .command('build:ssr')
99
- .description('build for server-side rendering (SSR)')
100
- .action(() => {
101
- showBanner('build:ssr');
102
- (0, build_ssr_1.default)();
103
- });
104
78
  program
105
79
  .command('preview')
106
80
  .description('preview production build')
@@ -41,71 +41,69 @@ const path_1 = __importDefault(require("path"));
41
41
  const fs_extra_1 = __importDefault(require("fs-extra"));
42
42
  const url_1 = require("url");
43
43
  const chalk_1 = __importDefault(require("chalk"));
44
+ const esbuild_1 = require("esbuild");
44
45
  /**
45
- * Dynamically load react-client.config.(js|mjs|ts)
46
- * from the user project, not the CLI’s own folder.
46
+ * Dynamically loads react-client.config.(ts|js|mjs)
47
+ * Compiles .ts and .js configs to .mjs temporarily for import.
47
48
  */
48
49
  async function loadReactClientConfig(cwd) {
49
50
  let projectRoot = cwd;
50
51
  try {
51
- // 🧭 Detect if running inside react-client source repo
52
+ // Detect if running inside react-client repo for local testing
52
53
  const pkgPath = path_1.default.join(cwd, 'package.json');
53
- if (fs_extra_1.default.existsSync(pkgPath)) {
54
- const pkgJson = JSON.parse(await fs_extra_1.default.readFile(pkgPath, 'utf8'));
55
- if (pkgJson.name === 'react-client') {
56
- // Running CLI locally β€” auto-switch into example project (if found)
57
- const myappPath = path_1.default.join(cwd, 'myapp');
58
- if (fs_extra_1.default.existsSync(myappPath)) {
59
- console.log(chalk_1.default.gray('🧩 Detected local CLI environment, using ./myapp as root.'));
60
- projectRoot = myappPath;
61
- }
54
+ if (await fs_extra_1.default.pathExists(pkgPath)) {
55
+ const pkg = JSON.parse(await fs_extra_1.default.readFile(pkgPath, 'utf8'));
56
+ if (pkg.name === 'react-client' && (await fs_extra_1.default.pathExists(path_1.default.join(cwd, 'myapp')))) {
57
+ console.log(chalk_1.default.gray('🧩 Detected local CLI environment, using ./myapp as root.'));
58
+ projectRoot = path_1.default.join(cwd, 'myapp');
62
59
  }
63
60
  }
64
- // πŸ” Possible config file names (prefer .js for Node compatibility)
65
61
  const filenames = [
66
- 'react-client.config.js',
67
- 'react-client.config.mjs',
68
62
  'react-client.config.ts',
63
+ 'react-client.config.mjs',
64
+ 'react-client.config.js',
69
65
  ];
70
66
  let configFile = null;
71
67
  for (const name of filenames) {
72
68
  const file = path_1.default.join(projectRoot, name);
73
- if (fs_extra_1.default.existsSync(file)) {
69
+ if (await fs_extra_1.default.pathExists(file)) {
74
70
  configFile = file;
75
71
  break;
76
72
  }
77
73
  }
78
74
  if (!configFile) {
79
- console.log(chalk_1.default.gray('ℹ️ No react-client.config.js found, using defaults.'));
75
+ console.log(chalk_1.default.gray('ℹ️ No react-client.config found, using defaults.'));
80
76
  return {};
81
77
  }
82
- // 🧩 Import dynamically using file://
83
- const fileUrl = (0, url_1.pathToFileURL)(configFile).href;
84
- // If TypeScript file, try to compile it temporarily using esbuild
85
- if (configFile.endsWith('.ts')) {
86
- const esbuild = await Promise.resolve().then(() => __importStar(require('esbuild')));
87
- const outFile = path_1.default.join(projectRoot, '.react-client.temp.config.js');
88
- await esbuild.build({
78
+ const ext = path_1.default.extname(configFile);
79
+ const tempFile = path_1.default.join(projectRoot, `.react-client.temp-${Date.now()}.mjs`);
80
+ // 🧠 Always compile .ts or .js β†’ .mjs for safe ESM import
81
+ if (ext === '.ts' || ext === '.js') {
82
+ await (0, esbuild_1.build)({
89
83
  entryPoints: [configFile],
90
- outfile: outFile,
91
- format: 'esm',
84
+ outfile: tempFile,
92
85
  platform: 'node',
86
+ format: 'esm',
87
+ target: 'node18',
93
88
  bundle: true,
94
89
  write: true,
90
+ logLevel: 'silent',
95
91
  });
96
- const mod = await Promise.resolve(`${(0, url_1.pathToFileURL)(outFile).href}`).then(s => __importStar(require(s)));
97
- await fs_extra_1.default.remove(outFile);
98
- console.log(chalk_1.default.green(`🧩 Loaded config from ${path_1.default.basename(configFile)}`));
99
- return mod.default || mod;
100
92
  }
101
- // Normal .js or .mjs import
93
+ else {
94
+ await fs_extra_1.default.copyFile(configFile, tempFile);
95
+ }
96
+ // Import via file:// URL
97
+ const fileUrl = (0, url_1.pathToFileURL)(tempFile).href;
102
98
  const mod = await Promise.resolve(`${fileUrl}`).then(s => __importStar(require(s)));
99
+ await fs_extra_1.default.remove(tempFile);
100
+ const config = mod.default || mod;
103
101
  console.log(chalk_1.default.green(`🧩 Loaded config from ${path_1.default.basename(configFile)}`));
104
- return mod.default || mod;
102
+ return config;
105
103
  }
106
104
  catch (err) {
107
105
  const msg = err instanceof Error ? err.message : String(err);
108
- console.error(chalk_1.default.red(`❌ Failed to load react-client.config: ${msg}`));
106
+ console.error(chalk_1.default.red(`❌ Could not load config (${path_1.default.join(cwd, 'react-client.config.js')}): ${msg}`));
109
107
  return {};
110
108
  }
111
109
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-client",
3
- "version": "1.0.8",
4
- "description": "react-client is a lightweight CLI and runtime for building React apps with fast iteration. Esbuild-based, Node-native, and modular like Vite/Next.js with SSR, HMR, Tailwind, CSS Modules, and generators.",
3
+ "version": "1.0.10",
4
+ "description": "react-client is a lightweight CLI and runtime for building React apps with fast iteration.",
5
5
  "license": "MIT",
6
6
  "author": "Venkatesh Sundaram",
7
7
  "repository": {
@@ -11,21 +11,22 @@
11
11
  "bugs": {
12
12
  "url": "https://github.com/venkateshsundaram/react-client/issues"
13
13
  },
14
- "main": "dist/index.js",
15
- "types": "dist/index.d.ts",
14
+ "homepage": "https://github.com/venkateshsundaram/react-client#readme",
16
15
  "bin": {
17
16
  "react-client": "dist/cli/index.js"
18
17
  },
18
+ "main": "dist/index.js",
19
+ "types": "dist/index.d.ts",
19
20
  "exports": {
20
21
  ".": {
21
- "import": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
22
23
  "require": "./dist/index.js",
23
- "types": "./dist/index.d.ts"
24
+ "import": "./dist/index.js"
24
25
  },
25
26
  "./config": {
26
- "import": "./dist/config.js",
27
+ "types": "./dist/config.d.ts",
27
28
  "require": "./dist/config.js",
28
- "types": "./dist/config.d.ts"
29
+ "import": "./dist/config.js"
29
30
  }
30
31
  },
31
32
  "typesVersions": {
@@ -50,29 +51,30 @@
50
51
  "react-cli",
51
52
  "framework",
52
53
  "hmr",
53
- "ssr",
54
54
  "esbuild",
55
55
  "tooling",
56
56
  "vite-alternative",
57
- "fast-refresh"
57
+ "fast-refresh",
58
+ "react-refresh",
59
+ "tailwind",
60
+ "developer-experience"
58
61
  ],
59
62
  "scripts": {
60
- "clean": "rm -rf dist",
63
+ "clean": "rm -rf dist .turbo .react-client.temp.config*",
61
64
  "compile": "tsc -p tsconfig.build.json",
62
65
  "build": "npm run clean && npm run compile",
63
66
  "build:cli": "node dist/cli/index.js build",
64
- "build:ssr": "node dist/cli/index.js build:ssr",
65
67
  "dev": "node dist/cli/index.js dev",
66
68
  "prepare": "npm run compile",
67
- "precommit": "lint-staged",
68
- "lint": "eslint . --ext .ts",
69
+ "lint": "eslint . --ext .ts --max-warnings 0",
69
70
  "format": "prettier --write \"src/**/*.ts\"",
70
71
  "format:check": "prettier --check \"src/**/*.ts\"",
71
72
  "release": "standard-version",
72
73
  "postrelease": "git push --follow-tags",
73
- "prepublishOnly": "npm run compile",
74
+ "prepublishOnly": "npm run lint && npm run format:check && npm run build && npm test",
74
75
  "test": "jest",
75
- "typecheck": "tsc --noEmit"
76
+ "typecheck": "tsc --noEmit",
77
+ "verify": "bash scripts/local-verify.sh"
76
78
  },
77
79
  "lint-staged": {
78
80
  "*.ts": [
@@ -82,7 +84,8 @@
82
84
  },
83
85
  "husky": {
84
86
  "hooks": {
85
- "pre-commit": "lint-staged"
87
+ "pre-commit": "lint-staged",
88
+ "pre-push": "npm run lint && npm run typecheck"
86
89
  }
87
90
  },
88
91
  "commitlint": {
@@ -130,5 +133,8 @@
130
133
  "standard-version": "^9.5.0",
131
134
  "ts-jest": "^29.0.0",
132
135
  "typescript": "^5.3.0"
136
+ },
137
+ "engines": {
138
+ "node": ">=18.0.0"
133
139
  }
134
140
  }
@@ -1 +1,13 @@
1
- <!doctype html><html><head><meta charset='utf-8'></head><body><div id='root'></div><script type='module' src='/client/bundle.js'></script></body></html>
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>React Client App</title>
7
+ <link rel="icon" type="image/x-icon" href="/favicon.ico" />
8
+ </head>
9
+ <body>
10
+ <div id='root'></div>
11
+ <script type="module" src="/src/main.jsx"></script>
12
+ </body>
13
+ </html>
@@ -1 +1 @@
1
- export default ()=> <div>Hello React</div>;
1
+ export default () => <div>Hello React</div>;
@@ -1 +1,6 @@
1
- import React from 'react';import { createRoot } from 'react-dom/client';import App from './App';const root = createRoot(document.getElementById('root'));root.render(<App/>);
1
+ import React from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import App from './App';
4
+
5
+ const root = createRoot(document.getElementById('root'));
6
+ root.render(<App />);
@@ -1 +1,13 @@
1
- <!doctype html><html><head><meta charset='utf-8'></head><body><div id='root'></div><script type='module' src='/client/bundle.js'></script></body></html>
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>React Client App</title>
7
+ <link rel="icon" type="image/x-icon" href="/favicon.ico" />
8
+ </head>
9
+ <body>
10
+ <div id='root'></div>
11
+ <script type="module" src="/src/main.jsx"></script>
12
+ </body>
13
+ </html>
@@ -1 +1,3 @@
1
- export default ()=> <div className='p-8'><h1 className='text-2xl'>Tailwind</h1></div>;
1
+ export default function App() {
2
+ return <div className='p-8'><h1 className='text-2xl'>Tailwind</h1><p>Welcome to react-tailwind template.</p></div>;
3
+ }
@@ -0,0 +1 @@
1
+ @tailwind base;@tailwind components;@tailwind utilities;
@@ -1 +1,9 @@
1
- import React from 'react';import { createRoot } from 'react-dom/client';import App from './App';import './index.css';const root = createRoot(document.getElementById('root'));root.render(<App/>);
1
+
2
+ import '/@react-refresh-shim';
3
+ import React from 'react';
4
+ import { createRoot } from 'react-dom/client';
5
+ import App from './App';
6
+ import './index.css';
7
+
8
+ const root = createRoot(document.getElementById('root'));
9
+ root.render(<App/>);
@@ -1 +1,13 @@
1
- <!doctype html><html><head><meta charset='utf-8'></head><body><div id='root'></div><script type='module' src='/client/bundle.js'></script></body></html>
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>React Client App</title>
7
+ <link rel="icon" type="image/x-icon" href="/favicon.ico" />
8
+ </head>
9
+ <body>
10
+ <div id='root'></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
@@ -1,2 +1,4 @@
1
1
 
2
- export default function App(){ return <div className='p-8'><h1 className='text-2xl font-bold'>Tailwind TS</h1><p>Welcome to react-tailwind-ts template.</p></div>; }
2
+ export default function App() {
3
+ return <div className='p-8'><h1 className='text-2xl font-bold'>Tailwind TS</h1><p>Welcome to react-tailwind-ts template.</p></div>;
4
+ }
@@ -4,5 +4,6 @@ import React from 'react';
4
4
  import { createRoot } from 'react-dom/client';
5
5
  import App from './App';
6
6
  import './index.css';
7
+
7
8
  const root = createRoot(document.getElementById('root')!);
8
9
  root.render(<App/>);
@@ -1 +1,13 @@
1
- <!doctype html><html><head><meta charset='utf-8'></head><body><div id='root'></div><script type='module' src='/client/bundle.js'></script></body></html>
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>React Client App</title>
7
+ <link rel="icon" type="image/x-icon" href="/favicon.ico" />
8
+ </head>
9
+ <body>
10
+ <div id='root'></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
@@ -1 +1,6 @@
1
- import React from 'react';import { createRoot } from 'react-dom/client';import App from './App';const root = createRoot(document.getElementById('root')!);root.render(<App/>);
1
+ import React from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import App from './App';
4
+
5
+ const root = createRoot(document.getElementById('root')!);
6
+ root.render(<App/>);
@@ -9,7 +9,6 @@
9
9
  "jsx": "react-jsx",
10
10
  "moduleResolution": "node",
11
11
  "strict": true,
12
- "esModuleInterop": true,
13
- "skipLibCheck": true
12
+ "esModuleInterop": true
14
13
  }
15
14
  }
@@ -1,46 +0,0 @@
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 chalk_1 = __importDefault(require("chalk"));
11
- const loadConfig_1 = require("../../utils/loadConfig");
12
- async function buildSsr() {
13
- const root = process.cwd();
14
- const config = await (0, loadConfig_1.loadReactClientConfig)(root);
15
- const appRoot = path_1.default.resolve(root, config.root || '.');
16
- const outDir = path_1.default.join(appRoot, config.build?.outDir || '.react-client/ssr');
17
- console.log(chalk_1.default.cyan(`\n🧱 Building SSR bundle...`));
18
- console.log(chalk_1.default.gray(`Root: ${appRoot}`));
19
- console.log(chalk_1.default.gray(`Output: ${outDir}\n`));
20
- const entry = path_1.default.join(appRoot, 'src', 'server.tsx');
21
- if (!fs_extra_1.default.existsSync(entry)) {
22
- console.error(chalk_1.default.red('❌ SSR entry not found: src/server.tsx'));
23
- process.exit(1);
24
- }
25
- await fs_extra_1.default.ensureDir(outDir);
26
- try {
27
- await esbuild_1.default.build({
28
- entryPoints: [entry],
29
- bundle: true,
30
- platform: 'node',
31
- format: 'esm',
32
- target: 'node18',
33
- external: ['react', 'react-dom'],
34
- outdir: outDir,
35
- define: { 'process.env.NODE_ENV': '"production"' },
36
- loader: { '.ts': 'ts', '.tsx': 'tsx' },
37
- });
38
- console.log(chalk_1.default.green(`βœ… SSR build completed successfully!`));
39
- console.log(chalk_1.default.gray(`Output directory: ${outDir}`));
40
- }
41
- catch (err) {
42
- const msg = err instanceof Error ? err.message : String(err);
43
- console.error('❌ SSR build failed:', msg);
44
- process.exit(1);
45
- }
46
- }
@@ -1,42 +0,0 @@
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
- }
@@ -1 +0,0 @@
1
- <!doctype html><html><head><meta charset='utf-8'></head><body><div id='root'></div><script type='module' src='/client/bundle.js'></script></body></html>
@@ -1,14 +0,0 @@
1
- {
2
- "name": "template-react-ssr",
3
- "version": "0.0.1",
4
- "private": true,
5
- "scripts": {
6
- "dev": "react-client dev",
7
- "build": "react-client build:ssr",
8
- "preview": "react-client preview"
9
- },
10
- "dependencies": {
11
- "react": "^18.2.0",
12
- "react-dom": "^18.2.0"
13
- }
14
- }
@@ -1 +0,0 @@
1
- import React from 'react';import { hydrateRoot } from 'react-dom/client';import Home from './pages/index';hydrateRoot(document.getElementById('root'), React.createElement(Home));
@@ -1 +0,0 @@
1
- import React from 'react';import { renderToString } from 'react-dom/server';import Home from './pages/index';exports.render = function(url){ const Page = Home; return Promise.resolve(renderToString(React.createElement(Page))); };
@@ -1 +0,0 @@
1
- import React from 'react';export default function Home(){ return <div>Home SSR</div>; }
@@ -1 +0,0 @@
1
- <!doctype html><html><head><meta charset='utf-8' /></head><body><div id='root'></div><script type='module' src='/client/bundle.js'></script></body></html>
@@ -1,21 +0,0 @@
1
- {
2
- "name": "my-react-ssr-ts-app",
3
- "version": "0.0.1",
4
- "private": true,
5
- "scripts": {
6
- "dev": "react-client dev",
7
- "build": "react-client build:ssr",
8
- "preview": "react-client preview"
9
- },
10
- "dependencies": {
11
- "react": "^18.2.0",
12
- "react-dom": "^18.2.0"
13
- },
14
- "devDependencies": {
15
- "@types/react": "^18.0.0",
16
- "@types/react-dom": "^18.0.0",
17
- "esbuild": "^0.25.12",
18
- "react-refresh": "^0.14.0",
19
- "typescript": "^5.0.0"
20
- }
21
- }
@@ -1,5 +0,0 @@
1
- import '/@react-refresh-shim';
2
- import React from 'react';
3
- import { hydrateRoot } from 'react-dom/client';
4
- import Home from './pages/index';
5
- hydrateRoot(document.getElementById('root'), React.createElement(Home));
@@ -1,6 +0,0 @@
1
-
2
- import '/@react-refresh-shim';
3
- import React from 'react';
4
- import { hydrateRoot } from 'react-dom/client';
5
- import Home from './pages/index';
6
- hydrateRoot(document.getElementById('root')!, React.createElement(Home));
@@ -1,4 +0,0 @@
1
- import React from 'react';
2
- import { renderToString } from 'react-dom/server';
3
- import Home from './pages/index';
4
- export async function render(url) { const Page = Home; return renderToString(React.createElement(Page)); }
@@ -1,5 +0,0 @@
1
-
2
- import React from 'react';
3
- import { renderToString } from 'react-dom/server';
4
- import Home from './pages/index';
5
- export async function render(url:string){ const Page = Home; return renderToString(React.createElement(Page)); }
@@ -1,2 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- export default function Home() { return _jsxs("div", { style: { padding: 20 }, children: [_jsx("h1", { children: "Home (SSR TS)" }), _jsx("p", { children: "Server-side rendered page." })] }); }
@@ -1,3 +0,0 @@
1
-
2
- import React from 'react';
3
- export default function Home(){ return <div style={{padding:20}}><h1>Home (SSR TS)</h1><p>Server-side rendered page.</p></div>; }
@@ -1,2 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- export default function App() { return _jsxs("div", { className: 'p-8', children: [_jsx("h1", { className: 'text-2xl font-bold', children: "Tailwind TS" }), _jsx("p", { children: "Welcome to react-tailwind-ts template." })] }); }
@@ -1,7 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import '/@react-refresh-shim';
3
- import { createRoot } from 'react-dom/client';
4
- import App from './App';
5
- import './index.css';
6
- const root = createRoot(document.getElementById('root'));
7
- root.render(_jsx(App, {}));