react-client 1.0.25 → 1.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,6 @@
5
5
  * - prebundles deps into .react-client/deps
6
6
  * - serves /@modules/<dep>
7
7
  * - serves /src/* with esbuild transform & inline sourcemap
8
- * - serves /@runtime/overlay -> src/runtime/overlay-runtime.js
9
8
  * - /@source-map returns a snippet for overlay mapping
10
9
  * - HMR broadcast via BroadcastManager (ws)
11
10
  *
@@ -183,32 +182,36 @@ async function dev() {
183
182
  res.setHeader('Content-Type', 'application/javascript');
184
183
  return res.end(await fs_extra_1.default.readFile(cacheFile, 'utf8'));
185
184
  }
186
- // 🧠 Handle subpaths correctly: react-dom/client, react/jsx-runtime, etc.
187
- let entryPath = null;
185
+ // 🧠 Smart module resolver: handles subpaths like react-dom/client, react/jsx-runtime, etc.
186
+ let entryFile = null;
188
187
  try {
189
- entryPath = require.resolve(id, { paths: [appRoot] });
188
+ // Try direct require.resolve first (works for most)
189
+ entryFile = require.resolve(id, { paths: [appRoot] });
190
190
  }
191
191
  catch {
192
- // Fallback: handle packages with subpaths dynamically
192
+ // Handle subpath imports
193
193
  const parts = id.split('/');
194
- if (parts.length > 1) {
195
- const pkgRoot = parts[0].startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
196
- const subPath = parts.slice(pkgRoot.startsWith('@') ? 2 : 1).join('/');
197
- const pkgDir = path_1.default.dirname(require.resolve(`${pkgRoot}/package.json`, { paths: [appRoot] }));
198
- // resolve full subpath from package root
199
- const tryPath = path_1.default.join(pkgDir, subPath);
200
- if (await fs_extra_1.default.pathExists(tryPath + '.js'))
201
- entryPath = tryPath + '.js';
202
- else if (await fs_extra_1.default.pathExists(tryPath + '.mjs'))
203
- entryPath = tryPath + '.mjs';
204
- else if (await fs_extra_1.default.pathExists(tryPath + '/index.js'))
205
- entryPath = tryPath + '/index.js';
194
+ const pkgRoot = parts[0].startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
195
+ const subPath = parts.slice(pkgRoot.startsWith('@') ? 2 : 1).join('/');
196
+ const pkgJson = require.resolve(`${pkgRoot}/package.json`, { paths: [appRoot] });
197
+ const pkgDir = path_1.default.dirname(pkgJson);
198
+ const tryFiles = [
199
+ path_1.default.join(pkgDir, subPath),
200
+ path_1.default.join(pkgDir, subPath, 'index.js'),
201
+ path_1.default.join(pkgDir, subPath + '.js'),
202
+ path_1.default.join(pkgDir, subPath + '.mjs'),
203
+ ];
204
+ for (const f of tryFiles) {
205
+ if (await fs_extra_1.default.pathExists(f)) {
206
+ entryFile = f;
207
+ break;
208
+ }
206
209
  }
207
210
  }
208
- if (!entryPath)
209
- throw new Error(`Could not resolve ${id}`);
211
+ if (!entryFile)
212
+ throw new Error(`Cannot resolve module: ${id}`);
210
213
  const result = await esbuild_1.default.build({
211
- entryPoints: [entryPath],
214
+ entryPoints: [entryFile],
212
215
  bundle: true,
213
216
  platform: 'browser',
214
217
  format: 'esm',
@@ -226,15 +229,95 @@ async function dev() {
226
229
  }
227
230
  });
228
231
  // --- Serve runtime overlay (local file) so overlay-runtime.js is loaded automatically
232
+ // --- Serve runtime overlay (inline in dev server)
233
+ const OVERLAY_RUNTIME = `
234
+ import "/@prismjs";
235
+
236
+ const overlayId = "__rc_error_overlay__";
237
+
238
+ const style = document.createElement("style");
239
+ style.textContent = \`
240
+ #\${overlayId} {
241
+ position: fixed;
242
+ inset: 0;
243
+ background: rgba(0, 0, 0, 0.9);
244
+ color: #fff;
245
+ font-family: Menlo, Consolas, monospace;
246
+ font-size: 14px;
247
+ z-index: 999999;
248
+ overflow: auto;
249
+ padding: 24px;
250
+ animation: fadeIn 0.2s ease-out;
251
+ }
252
+ @keyframes fadeIn { from {opacity: 0;} to {opacity: 1;} }
253
+ #\${overlayId} h2 { color: #ff6b6b; margin-bottom: 16px; }
254
+ #\${overlayId} pre { background: rgba(255,255,255,0.1); padding: 12px; border-radius: 6px; }
255
+ #\${overlayId} a { color: #9cf; text-decoration: underline; }
256
+ #\${overlayId} .frame { margin: 12px 0; }
257
+ #\${overlayId} .frame-file { color: #ffa500; cursor: pointer; font-weight: bold; margin-bottom: 4px; }
258
+ .line-number { opacity: 0.5; margin-right: 10px; }
259
+ \`;
260
+ document.head.appendChild(style);
261
+
262
+ async function mapStackFrame(frame) {
263
+ const m = frame.match(/(\\/src\\/[^\s:]+):(\\d+):(\\d+)/);
264
+ if (!m) return frame;
265
+ const [, file, line, col] = m;
266
+ const resp = await fetch(\`/@source-map?file=\${file}&line=\${line}&column=\${col}\`);
267
+ if (!resp.ok) return frame;
268
+ const pos = await resp.json();
269
+ if (pos.source) {
270
+ return {
271
+ file: pos.source,
272
+ line: pos.line,
273
+ column: pos.column,
274
+ snippet: pos.snippet || ""
275
+ };
276
+ }
277
+ return frame;
278
+ }
279
+
280
+ async function renderOverlay(err) {
281
+ const overlay =
282
+ document.getElementById(overlayId) ||
283
+ document.body.appendChild(Object.assign(document.createElement("div"), { id: overlayId }));
284
+ overlay.innerHTML = "";
285
+ const title = document.createElement("h2");
286
+ title.textContent = "🔥 " + (err.message || "Error");
287
+ overlay.appendChild(title);
288
+
289
+ const frames = (err.stack || "").split("\\n").filter(l => /src\\//.test(l));
290
+ for (const frame of frames) {
291
+ const mapped = await mapStackFrame(frame);
292
+ if (typeof mapped === "string") continue;
293
+ const frameEl = document.createElement("div");
294
+ frameEl.className = "frame";
295
+
296
+ const link = document.createElement("div");
297
+ link.className = "frame-file";
298
+ link.textContent = \`\${mapped.file}:\${mapped.line}:\${mapped.column}\`;
299
+ link.onclick = () =>
300
+ window.open("vscode://file/" + location.origin.replace("http://", "") + mapped.file + ":" + mapped.line);
301
+ frameEl.appendChild(link);
302
+
303
+ if (mapped.snippet) {
304
+ const pre = document.createElement("pre");
305
+ pre.classList.add("language-jsx");
306
+ pre.innerHTML = Prism.highlight(mapped.snippet, Prism.languages.jsx, "jsx");
307
+ frameEl.appendChild(pre);
308
+ }
309
+
310
+ overlay.appendChild(frameEl);
311
+ }
312
+ }
313
+
314
+ window.showErrorOverlay = (err) => renderOverlay(err);
315
+ window.clearErrorOverlay = () => document.getElementById(overlayId)?.remove();
316
+ `;
229
317
  app.use(async (req, res, next) => {
230
318
  if (req.url === '/@runtime/overlay') {
231
- const overlayPath = path_1.default.join(appRoot, 'src/runtime/overlay-runtime.js');
232
- if (!(await fs_extra_1.default.pathExists(overlayPath))) {
233
- res.writeHead(404);
234
- return res.end('// overlay-runtime.js not found');
235
- }
236
319
  res.setHeader('Content-Type', 'application/javascript');
237
- return res.end(await fs_extra_1.default.readFile(overlayPath, 'utf8'));
320
+ return res.end(OVERLAY_RUNTIME);
238
321
  }
239
322
  next();
240
323
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-client",
3
- "version": "1.0.25",
3
+ "version": "1.0.26",
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",