react-client 1.0.18 → 1.0.19

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.
@@ -25,7 +25,7 @@ async function dev() {
25
25
  const cacheDir = path_1.default.join(appRoot, '.react-client', 'deps');
26
26
  const pkgFile = path_1.default.join(appRoot, 'package.json');
27
27
  await fs_extra_1.default.ensureDir(cacheDir);
28
- // Detect entry
28
+ // Detect entry file
29
29
  const possibleEntries = ['src/main.tsx', 'src/main.jsx'];
30
30
  const entry = possibleEntries.map((p) => path_1.default.join(appRoot, p)).find((p) => fs_extra_1.default.existsSync(p));
31
31
  if (!entry) {
@@ -33,7 +33,7 @@ async function dev() {
33
33
  process.exit(1);
34
34
  }
35
35
  const indexHtml = path_1.default.join(appRoot, 'index.html');
36
- // Detect port
36
+ // Detect open port
37
37
  const availablePort = await (0, detect_port_1.default)(defaultPort);
38
38
  const port = availablePort;
39
39
  if (availablePort !== defaultPort) {
@@ -60,7 +60,7 @@ async function dev() {
60
60
  });
61
61
  console.log(chalk_1.default.green('✅ react-refresh installed successfully.'));
62
62
  }
63
- // Core plugin: CSS HMR
63
+ // --- Plugins
64
64
  const corePlugins = [
65
65
  {
66
66
  name: 'css-hmr',
@@ -81,26 +81,38 @@ async function dev() {
81
81
  ];
82
82
  const userPlugins = Array.isArray(userConfig.plugins) ? userConfig.plugins : [];
83
83
  const plugins = [...corePlugins, ...userPlugins];
84
- // Connect app
85
84
  const app = (0, connect_1.default)();
86
85
  const transformCache = new Map();
87
- // 🧠 Prewarm: analyze imports before first run
88
- async function analyzeImports(entryFile) {
89
- const entryCode = await fs_extra_1.default.readFile(entryFile, 'utf8');
90
- const importMatches = [
91
- ...entryCode.matchAll(/\bfrom\s+['"]([^'".\/][^'"]*)['"]/g),
92
- ...entryCode.matchAll(/\bimport\(['"]([^'".\/][^'"]*)['"]\)/g),
86
+ // 🧠 Deep dependency graph analyzer
87
+ async function analyzeGraph(file, seen = new Set()) {
88
+ if (seen.has(file))
89
+ return seen;
90
+ seen.add(file);
91
+ const code = await fs_extra_1.default.readFile(file, 'utf8');
92
+ const matches = [
93
+ ...code.matchAll(/\bfrom\s+['"]([^'".\/][^'"]*)['"]/g),
94
+ ...code.matchAll(/\bimport\(['"]([^'".\/][^'"]*)['"]\)/g),
93
95
  ];
94
- const deps = [...new Set(importMatches.map((m) => m[1]))];
95
- console.log(chalk_1.default.gray(`🧩 Found ${deps.length} direct imports:`), deps.join(', '));
96
- return deps;
96
+ for (const m of matches) {
97
+ const dep = m[1];
98
+ if (!dep || dep.startsWith('.') || dep.startsWith('/'))
99
+ continue;
100
+ try {
101
+ const resolved = require.resolve(dep, { paths: [appRoot] });
102
+ await analyzeGraph(resolved, seen);
103
+ }
104
+ catch {
105
+ seen.add(dep); // bare dependency
106
+ }
107
+ }
108
+ return seen;
97
109
  }
98
- // 📦 Smart prebundle cache
110
+ // 📦 Smart prebundle cache (parallelized)
99
111
  async function prebundleDeps(deps) {
100
- if (!deps.length)
112
+ if (!deps.size)
101
113
  return;
102
114
  const cached = (await fs_extra_1.default.readdir(cacheDir)).map((f) => f.replace('.js', ''));
103
- const missing = deps.filter((d) => !cached.includes(d));
115
+ const missing = [...deps].filter((d) => !cached.includes(d));
104
116
  if (!missing.length) {
105
117
  console.log(chalk_1.default.green('✅ All dependencies already prebundled.'));
106
118
  return;
@@ -127,16 +139,16 @@ async function dev() {
127
139
  }
128
140
  }));
129
141
  }
130
- // 🧩 Smart rebuild trigger when package.json changes
142
+ // 🧩 Prewarm Graph
143
+ const deps = await analyzeGraph(entry);
144
+ await prebundleDeps(deps);
145
+ // Auto rebuild on package.json change
131
146
  chokidar_1.default.watch(pkgFile).on('change', async () => {
132
- console.log(chalk_1.default.yellow('📦 Detected package.json change — rebuilding prebundles...'));
133
- const deps = await analyzeImports(entry);
134
- await prebundleDeps(deps);
147
+ console.log(chalk_1.default.yellow('📦 package.json changed — rebuilding prebundle cache...'));
148
+ const newDeps = await analyzeGraph(entry);
149
+ await prebundleDeps(newDeps);
135
150
  });
136
- // Initial prewarm
137
- const initialDeps = await analyzeImports(entry);
138
- await prebundleDeps(initialDeps);
139
- // --- Serve prebundled / node_modules
151
+ // --- Serve /@modules/
140
152
  app.use('/@modules/', async (req, res, next) => {
141
153
  const id = req.url?.replace(/^\/(@modules\/)?/, '');
142
154
  if (!id)
@@ -149,7 +161,7 @@ async function dev() {
149
161
  }
150
162
  let entryPath = null;
151
163
  try {
152
- entryPath = require.resolve(id, { paths: [path_1.default.join(appRoot, 'node_modules')] });
164
+ entryPath = require.resolve(id, { paths: [appRoot] });
153
165
  }
154
166
  catch {
155
167
  if (id === 'react')
@@ -168,12 +180,19 @@ async function dev() {
168
180
  write: false,
169
181
  });
170
182
  let code = result.outputFiles[0].text;
171
- // Fix for react-dom/client exports
183
+ // 🩹 Fixed react-dom/client shim (no duplicate export)
172
184
  if (id === 'react-dom/client') {
173
185
  code += `
186
+ // React Client auto-shim for React 18+
174
187
  import * as ReactDOMClient from '/@modules/react-dom';
175
- export const createRoot = ReactDOMClient.createRoot || ReactDOMClient.default?.createRoot;
176
- export default ReactDOMClient.default || ReactDOMClient;
188
+ if (!('createRoot' in ReactDOMClient) && ReactDOMClient.default) {
189
+ Object.assign(ReactDOMClient, ReactDOMClient.default);
190
+ }
191
+ export const createRoot =
192
+ ReactDOMClient.createRoot ||
193
+ ReactDOMClient.default?.createRoot ||
194
+ (() => { throw new Error('ReactDOM.createRoot not found'); });
195
+ export default ReactDOMClient;
177
196
  `;
178
197
  }
179
198
  await fs_extra_1.default.writeFile(cacheFile, code, 'utf8');
@@ -187,7 +206,7 @@ async function dev() {
187
206
  res.end(`// Failed to resolve module ${id}: ${e.message}`);
188
207
  }
189
208
  });
190
- // --- Serve src files + HMR
209
+ // --- Serve /src files dynamically
191
210
  app.use(async (req, res, next) => {
192
211
  if (!req.url || (!req.url.startsWith('/src/') && !req.url.endsWith('.css')))
193
212
  return next();
@@ -204,6 +223,7 @@ async function dev() {
204
223
  return next();
205
224
  try {
206
225
  let code = await fs_extra_1.default.readFile(filePath, 'utf8');
226
+ // Rewrite bare imports → /@modules/*
207
227
  code = code
208
228
  .replace(/\bfrom\s+['"]([^'".\/][^'"]*)['"]/g, (_match, dep) => `from "/@modules/${dep}"`)
209
229
  .replace(/\bimport\(['"]([^'".\/][^'"]*)['"]\)/g, (_match, dep) => `import("/@modules/${dep}")`);
@@ -234,7 +254,7 @@ async function dev() {
234
254
  res.end(`// Error: ${e.message}`);
235
255
  }
236
256
  });
237
- // --- index.html + overlay
257
+ // --- Serve index.html + overlay + HMR
238
258
  app.use(async (req, res, next) => {
239
259
  if (req.url !== '/' && req.url !== '/index.html')
240
260
  return next();
@@ -16,10 +16,8 @@ class BroadcastManager {
16
16
  this.wss = new ws_1.WebSocketServer({ server });
17
17
  this.wss.on('connection', (ws) => {
18
18
  this.clients.add(ws);
19
- console.log(chalk_1.default.gray('🔌 Client connected'));
20
19
  ws.on('close', () => {
21
20
  this.clients.delete(ws);
22
- console.log(chalk_1.default.gray('❎ Client disconnected'));
23
21
  });
24
22
  ws.on('error', (err) => {
25
23
  console.error(chalk_1.default.red('⚠️ WebSocket error:'), err.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-client",
3
- "version": "1.0.18",
3
+ "version": "1.0.19",
4
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",