react-client 1.0.9 β 1.0.11
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/README.md +0 -22
- package/dist/cli/commands/dev.js +79 -71
- package/dist/cli/index.js +1 -27
- package/package.json +2 -5
- package/templates/react/index.html +13 -1
- package/templates/react/public/favicon.ico +0 -0
- package/templates/react/src/App.jsx +1 -1
- package/templates/react/src/main.jsx +6 -1
- package/templates/react-tailwind/index.html +13 -1
- package/templates/react-tailwind/public/favicon.ico +0 -0
- package/templates/react-tailwind/src/App.jsx +3 -1
- package/templates/react-tailwind/src/index.css +1 -0
- package/templates/react-tailwind/src/main.jsx +9 -1
- package/templates/react-tailwind-ts/index.html +13 -1
- package/templates/react-tailwind-ts/public/favicon.ico +0 -0
- package/templates/react-tailwind-ts/src/App.tsx +3 -1
- package/templates/react-tailwind-ts/src/main.tsx +1 -0
- package/templates/react-ts/index.html +13 -1
- package/templates/react-ts/public/favicon.ico +0 -0
- package/templates/react-ts/src/main.tsx +6 -1
- package/templates/{react-ssr-ts β react-ts}/tsconfig.json +1 -2
- package/dist/cli/commands/build.ssr.js +0 -46
- package/dist/cli/commands/generate.js +0 -42
- package/templates/react-ssr/index.html +0 -1
- package/templates/react-ssr/package.json +0 -14
- package/templates/react-ssr/src/entry-client.jsx +0 -1
- package/templates/react-ssr/src/entry-server.jsx +0 -1
- package/templates/react-ssr/src/pages/index.jsx +0 -1
- package/templates/react-ssr-ts/index.html +0 -1
- package/templates/react-ssr-ts/package.json +0 -21
- package/templates/react-ssr-ts/src/entry-client.js +0 -5
- package/templates/react-ssr-ts/src/entry-client.tsx +0 -6
- package/templates/react-ssr-ts/src/entry-server.js +0 -4
- package/templates/react-ssr-ts/src/entry-server.tsx +0 -5
- package/templates/react-ssr-ts/src/pages/index.js +0 -2
- package/templates/react-ssr-ts/src/pages/index.tsx +0 -3
- package/templates/react-tailwind-ts/src/App.js +0 -2
- 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
|
-
```
|
package/dist/cli/commands/dev.js
CHANGED
|
@@ -13,7 +13,6 @@ const detect_port_1 = __importDefault(require("detect-port"));
|
|
|
13
13
|
const prompts_1 = __importDefault(require("prompts"));
|
|
14
14
|
const path_1 = __importDefault(require("path"));
|
|
15
15
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
16
|
-
const trace_mapping_1 = require("@jridgewell/trace-mapping");
|
|
17
16
|
const loadConfig_1 = require("../../utils/loadConfig");
|
|
18
17
|
const open_1 = __importDefault(require("open"));
|
|
19
18
|
const child_process_1 = require("child_process");
|
|
@@ -25,12 +24,14 @@ async function dev() {
|
|
|
25
24
|
const appRoot = path_1.default.resolve(root, userConfig.root || '.');
|
|
26
25
|
const defaultPort = userConfig.server?.port || 5173;
|
|
27
26
|
const outDir = path_1.default.join(appRoot, userConfig.build?.outDir || '.react-client/dev');
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
// β
Dynamically detect entry (main.tsx or main.jsx)
|
|
28
|
+
const possibleEntries = ['src/main.tsx', 'src/main.jsx'];
|
|
29
|
+
const entry = possibleEntries.map((p) => path_1.default.join(appRoot, p)).find((p) => fs_extra_1.default.existsSync(p));
|
|
30
|
+
if (!entry) {
|
|
31
|
+
console.error(chalk_1.default.red('β No entry found: src/main.tsx or src/main.jsx'));
|
|
32
32
|
process.exit(1);
|
|
33
33
|
}
|
|
34
|
+
const indexHtml = path_1.default.join(appRoot, 'index.html');
|
|
34
35
|
await fs_extra_1.default.ensureDir(outDir);
|
|
35
36
|
// π§ Detect open port
|
|
36
37
|
const availablePort = await (0, detect_port_1.default)(defaultPort);
|
|
@@ -80,8 +81,13 @@ async function dev() {
|
|
|
80
81
|
outdir: outDir,
|
|
81
82
|
define: { 'process.env.NODE_ENV': '"development"' },
|
|
82
83
|
loader: { '.ts': 'ts', '.tsx': 'tsx', '.js': 'jsx', '.jsx': 'jsx' },
|
|
84
|
+
entryNames: '[name]',
|
|
85
|
+
assetNames: 'assets/[name]',
|
|
83
86
|
});
|
|
84
87
|
await ctx.watch();
|
|
88
|
+
console.log(chalk_1.default.gray('π¦ Watching and building dev bundle...'));
|
|
89
|
+
console.log(chalk_1.default.gray(' Output dir:'), chalk_1.default.blue(outDir));
|
|
90
|
+
console.log(chalk_1.default.gray(' Entry file:'), chalk_1.default.yellow(entry));
|
|
85
91
|
// π connect server
|
|
86
92
|
const app = (0, connect_1.default)();
|
|
87
93
|
// π‘ Security headers
|
|
@@ -90,82 +96,79 @@ async function dev() {
|
|
|
90
96
|
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
|
|
91
97
|
next();
|
|
92
98
|
});
|
|
93
|
-
// 1οΈβ£ Serve react-refresh runtime with
|
|
99
|
+
// 1οΈβ£ Serve react-refresh runtime with safe browser shim
|
|
94
100
|
app.use('/@react-refresh', async (_req, res) => {
|
|
95
101
|
const runtime = await fs_extra_1.default.readFile(reactRefreshRuntime, 'utf8');
|
|
96
102
|
const shim = `
|
|
97
103
|
// React Refresh browser shims
|
|
98
104
|
window.process = window.process || { env: { NODE_ENV: 'development' } };
|
|
99
105
|
window.module = { exports: {} };
|
|
100
|
-
window.global = window;
|
|
106
|
+
window.global = window;
|
|
107
|
+
window.require = () => window.module.exports;
|
|
101
108
|
`;
|
|
102
109
|
res.setHeader('Content-Type', 'application/javascript');
|
|
103
110
|
res.end(shim + '\n' + runtime);
|
|
104
111
|
});
|
|
105
|
-
// 2οΈβ£
|
|
106
|
-
app.use('/@
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const url = new URL(req.url ?? '', `http://localhost:${port}`);
|
|
123
|
-
const file = url.searchParams.get('file');
|
|
124
|
-
const line = Number(url.searchParams.get('line'));
|
|
125
|
-
const column = Number(url.searchParams.get('column'));
|
|
126
|
-
if (!file) {
|
|
127
|
-
res.writeHead(400);
|
|
128
|
-
res.end('Missing ?file parameter');
|
|
129
|
-
return;
|
|
112
|
+
// 2οΈβ£ Minimal bare import resolver (/@modules/)
|
|
113
|
+
app.use('/@modules/', async (req, res, next) => {
|
|
114
|
+
const id = req.url?.replace(/^\/@modules\//, '');
|
|
115
|
+
if (!id)
|
|
116
|
+
return next();
|
|
117
|
+
try {
|
|
118
|
+
const entry = require.resolve(id, { paths: [appRoot] });
|
|
119
|
+
const out = await esbuild_1.default.build({
|
|
120
|
+
entryPoints: [entry],
|
|
121
|
+
bundle: true,
|
|
122
|
+
write: false,
|
|
123
|
+
platform: 'browser',
|
|
124
|
+
format: 'esm',
|
|
125
|
+
target: 'es2020',
|
|
126
|
+
});
|
|
127
|
+
res.setHeader('Content-Type', 'application/javascript');
|
|
128
|
+
res.end(out.outputFiles[0].text);
|
|
130
129
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
res.writeHead(
|
|
134
|
-
res.end(
|
|
135
|
-
return;
|
|
130
|
+
catch (err) {
|
|
131
|
+
console.error('Failed to resolve module', id, err);
|
|
132
|
+
res.writeHead(500);
|
|
133
|
+
res.end(`// Could not resolve module ${id}`);
|
|
136
134
|
}
|
|
135
|
+
});
|
|
136
|
+
// 3οΈβ£ Serve /src/* files (on-the-fly transform)
|
|
137
|
+
app.use(async (req, res, next) => {
|
|
138
|
+
if (!req.url || !req.url.startsWith('/src/'))
|
|
139
|
+
return next();
|
|
137
140
|
try {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
res.
|
|
160
|
-
res.end(JSON.stringify({ ...pos, snippet }));
|
|
141
|
+
const filePath = path_1.default.join(appRoot, decodeURIComponent(req.url.split('?')[0]));
|
|
142
|
+
if (!(await fs_extra_1.default.pathExists(filePath)))
|
|
143
|
+
return next();
|
|
144
|
+
const code = await fs_extra_1.default.readFile(filePath, 'utf8');
|
|
145
|
+
const ext = path_1.default.extname(filePath).toLowerCase();
|
|
146
|
+
let loader = 'js';
|
|
147
|
+
if (ext === '.ts')
|
|
148
|
+
loader = 'ts';
|
|
149
|
+
else if (ext === '.tsx')
|
|
150
|
+
loader = 'tsx';
|
|
151
|
+
else if (ext === '.jsx')
|
|
152
|
+
loader = 'jsx';
|
|
153
|
+
const transformed = await esbuild_1.default.transform(code, {
|
|
154
|
+
loader,
|
|
155
|
+
sourcemap: 'inline',
|
|
156
|
+
sourcefile: req.url,
|
|
157
|
+
target: 'es2020',
|
|
158
|
+
jsxFactory: 'React.createElement',
|
|
159
|
+
jsxFragment: 'React.Fragment',
|
|
160
|
+
});
|
|
161
|
+
res.setHeader('Content-Type', 'application/javascript');
|
|
162
|
+
res.end(transformed.code);
|
|
161
163
|
}
|
|
162
164
|
catch (err) {
|
|
163
165
|
const msg = err instanceof Error ? err.message : String(err);
|
|
166
|
+
console.error('Error serving src file:', msg);
|
|
164
167
|
res.writeHead(500);
|
|
165
|
-
res.end(
|
|
168
|
+
res.end(`// Error: ${msg}`);
|
|
166
169
|
}
|
|
167
170
|
});
|
|
168
|
-
// 4οΈβ£ Serve
|
|
171
|
+
// 4οΈβ£ Serve index.html with injected refresh + HMR
|
|
169
172
|
app.use(async (req, res, next) => {
|
|
170
173
|
if (req.url === '/' || req.url === '/index.html') {
|
|
171
174
|
if (!fs_extra_1.default.existsSync(indexHtml)) {
|
|
@@ -174,13 +177,9 @@ async function dev() {
|
|
|
174
177
|
return;
|
|
175
178
|
}
|
|
176
179
|
let html = await fs_extra_1.default.readFile(indexHtml, 'utf8');
|
|
177
|
-
// Ensure main entry reference
|
|
178
|
-
html = html.replace(/<script[^>]*src="\/bundle\.js"[^>]*><\/script>/, '');
|
|
179
180
|
html = html.replace('</body>', `
|
|
180
|
-
<script type="module" src="/main.js"></script>
|
|
181
181
|
<script type="module">
|
|
182
182
|
import "/@react-refresh";
|
|
183
|
-
import "/@prismjs";
|
|
184
183
|
const ws = new WebSocket("ws://" + location.host);
|
|
185
184
|
ws.onmessage = async (e) => {
|
|
186
185
|
const msg = JSON.parse(e.data);
|
|
@@ -204,9 +203,18 @@ async function dev() {
|
|
|
204
203
|
res.setHeader('Content-Type', 'text/html');
|
|
205
204
|
res.end(html);
|
|
206
205
|
}
|
|
207
|
-
else
|
|
208
|
-
|
|
206
|
+
else {
|
|
207
|
+
const filePath = path_1.default.join(outDir, req.url || '');
|
|
208
|
+
if (await fs_extra_1.default.pathExists(filePath)) {
|
|
209
|
+
const content = await fs_extra_1.default.readFile(filePath);
|
|
210
|
+
res.setHeader('Content-Type', 'application/javascript');
|
|
211
|
+
res.end(content);
|
|
212
|
+
}
|
|
213
|
+
else
|
|
214
|
+
next();
|
|
215
|
+
}
|
|
209
216
|
});
|
|
217
|
+
// π HMR via WebSocket
|
|
210
218
|
const server = http_1.default.createServer(app);
|
|
211
219
|
const wss = new ws_1.WebSocketServer({ server });
|
|
212
220
|
const broadcast = (data) => {
|
|
@@ -230,9 +238,9 @@ async function dev() {
|
|
|
230
238
|
});
|
|
231
239
|
server.listen(port, async () => {
|
|
232
240
|
const url = `http://localhost:${port}`;
|
|
233
|
-
console.log(chalk_1.default.
|
|
234
|
-
|
|
235
|
-
|
|
241
|
+
console.log(chalk_1.default.cyan.bold(`\nπ React Client Dev Server`));
|
|
242
|
+
console.log(chalk_1.default.gray('βββββββββββββββββββββββββββββββ'));
|
|
243
|
+
console.log(chalk_1.default.green(`β‘ Running at: ${url}`));
|
|
236
244
|
await (0, open_1.default)(url, { newInstance: true });
|
|
237
245
|
});
|
|
238
246
|
process.on('SIGINT', async () => {
|
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
|
|
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')
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-client",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "react-client is a lightweight CLI and runtime for building React apps with fast iteration.
|
|
3
|
+
"version": "1.0.11",
|
|
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": {
|
|
@@ -51,7 +51,6 @@
|
|
|
51
51
|
"react-cli",
|
|
52
52
|
"framework",
|
|
53
53
|
"hmr",
|
|
54
|
-
"ssr",
|
|
55
54
|
"esbuild",
|
|
56
55
|
"tooling",
|
|
57
56
|
"vite-alternative",
|
|
@@ -65,7 +64,6 @@
|
|
|
65
64
|
"compile": "tsc -p tsconfig.build.json",
|
|
66
65
|
"build": "npm run clean && npm run compile",
|
|
67
66
|
"build:cli": "node dist/cli/index.js build",
|
|
68
|
-
"build:ssr": "node dist/cli/index.js build:ssr",
|
|
69
67
|
"dev": "node dist/cli/index.js dev",
|
|
70
68
|
"prepare": "npm run compile",
|
|
71
69
|
"lint": "eslint . --ext .ts --max-warnings 0",
|
|
@@ -96,7 +94,6 @@
|
|
|
96
94
|
]
|
|
97
95
|
},
|
|
98
96
|
"dependencies": {
|
|
99
|
-
"@jridgewell/trace-mapping": "^0.3.31",
|
|
100
97
|
"chalk": "^4.1.2",
|
|
101
98
|
"chokidar": "^4.0.3",
|
|
102
99
|
"commander": "^14.0.2",
|
|
@@ -1 +1,13 @@
|
|
|
1
|
-
<!
|
|
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>
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export default ()=> <div>Hello React</div>;
|
|
1
|
+
export default () => <div>Hello React</div>;
|
|
@@ -1 +1,6 @@
|
|
|
1
|
-
import React from 'react';
|
|
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
|
-
<!
|
|
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>
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@tailwind base;@tailwind components;@tailwind utilities;
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
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
|
-
<!
|
|
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>
|
|
Binary file
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
|
|
2
|
-
export default function App(){
|
|
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
|
+
}
|
|
@@ -1 +1,13 @@
|
|
|
1
|
-
<!
|
|
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>
|
|
Binary file
|
|
@@ -1 +1,6 @@
|
|
|
1
|
-
import React from 'react';
|
|
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,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='/main.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='/main.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,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, {}));
|