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.
- package/dist/cli/commands/dev.js +109 -26
- package/package.json +1 -1
package/dist/cli/commands/dev.js
CHANGED
|
@@ -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
|
-
// 🧠
|
|
187
|
-
let
|
|
185
|
+
// 🧠 Smart module resolver: handles subpaths like react-dom/client, react/jsx-runtime, etc.
|
|
186
|
+
let entryFile = null;
|
|
188
187
|
try {
|
|
189
|
-
|
|
188
|
+
// Try direct require.resolve first (works for most)
|
|
189
|
+
entryFile = require.resolve(id, { paths: [appRoot] });
|
|
190
190
|
}
|
|
191
191
|
catch {
|
|
192
|
-
//
|
|
192
|
+
// Handle subpath imports
|
|
193
193
|
const parts = id.split('/');
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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 (!
|
|
209
|
-
throw new Error(`
|
|
211
|
+
if (!entryFile)
|
|
212
|
+
throw new Error(`Cannot resolve module: ${id}`);
|
|
210
213
|
const result = await esbuild_1.default.build({
|
|
211
|
-
entryPoints: [
|
|
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(
|
|
320
|
+
return res.end(OVERLAY_RUNTIME);
|
|
238
321
|
}
|
|
239
322
|
next();
|
|
240
323
|
});
|