create-interview-cockpit 0.9.0 → 0.11.0
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/package.json +1 -1
- package/template/client/src/App.tsx +1 -0
- package/template/client/src/components/CodeContextPanel.tsx +853 -850
- package/template/client/src/components/CodeRunnerModal.tsx +2273 -7
- package/template/client/src/reactLab.ts +418 -49
- package/template/client/tsconfig.tsbuildinfo +1 -30
- package/template/cockpit.json +1 -1
- package/template/server/src/index.ts +4 -0
|
@@ -216,10 +216,12 @@ This lab uses real webpack 5 + webpack-dev-server + Module Federation.
|
|
|
216
216
|
|
|
217
217
|
## What is here
|
|
218
218
|
|
|
219
|
-
- package.json
|
|
219
|
+
- the root package.json orchestrates three npm workspaces: a host plus two remotes
|
|
220
|
+
- each app owns its own dependencies in its local package.json
|
|
220
221
|
- apps/host consumes federated modules from the remotes
|
|
221
222
|
- apps/profile exposes a profile widget
|
|
222
223
|
- apps/checkout exposes a checkout widget
|
|
224
|
+
- react-router-dom is declared in each app package.json so routing experiments work across apps
|
|
223
225
|
|
|
224
226
|
## Good experiments
|
|
225
227
|
|
|
@@ -231,33 +233,29 @@ This lab uses real webpack 5 + webpack-dev-server + Module Federation.
|
|
|
231
233
|
## Notes
|
|
232
234
|
|
|
233
235
|
- Ports are injected by the lab runner through environment variables.
|
|
234
|
-
-
|
|
236
|
+
- Each webpack config builds its shared dependency list from that app's runtime dependencies.
|
|
237
|
+
- If you add or remove dependencies in an app package.json, restart the webpack lab so npm workspaces reinstall them.
|
|
235
238
|
`,
|
|
236
239
|
"package.json": `{
|
|
237
240
|
"name": "webpack-module-federation-lab",
|
|
238
241
|
"private": true,
|
|
242
|
+
"workspaces": [
|
|
243
|
+
"apps/host",
|
|
244
|
+
"apps/profile",
|
|
245
|
+
"apps/checkout"
|
|
246
|
+
],
|
|
239
247
|
"scripts": {
|
|
240
|
-
"dev": "concurrently -k -n host,profile,checkout -c cyan,magenta,yellow 'npm --
|
|
241
|
-
"dev:host": "npm --
|
|
242
|
-
"dev:profile": "npm --
|
|
243
|
-
"dev:checkout": "npm --
|
|
244
|
-
"build": "npm --
|
|
245
|
-
"build:host": "npm --
|
|
246
|
-
"build:profile": "npm --
|
|
247
|
-
"build:checkout": "npm --
|
|
248
|
-
},
|
|
249
|
-
"dependencies": {
|
|
250
|
-
"react": "^19.0.0",
|
|
251
|
-
"react-dom": "^19.0.0"
|
|
248
|
+
"dev": "concurrently -k -n host,profile,checkout -c cyan,magenta,yellow 'npm run dev --workspace=@mf-lab/host' 'npm run dev --workspace=@mf-lab/profile' 'npm run dev --workspace=@mf-lab/checkout'",
|
|
249
|
+
"dev:host": "npm run dev --workspace=@mf-lab/host",
|
|
250
|
+
"dev:profile": "npm run dev --workspace=@mf-lab/profile",
|
|
251
|
+
"dev:checkout": "npm run dev --workspace=@mf-lab/checkout",
|
|
252
|
+
"build": "npm run build --workspace=@mf-lab/host && npm run build --workspace=@mf-lab/profile && npm run build --workspace=@mf-lab/checkout",
|
|
253
|
+
"build:host": "npm run build --workspace=@mf-lab/host",
|
|
254
|
+
"build:profile": "npm run build --workspace=@mf-lab/profile",
|
|
255
|
+
"build:checkout": "npm run build --workspace=@mf-lab/checkout"
|
|
252
256
|
},
|
|
253
257
|
"devDependencies": {
|
|
254
|
-
"concurrently": "^9.2.1"
|
|
255
|
-
"esbuild": "^0.28.0",
|
|
256
|
-
"esbuild-loader": "^4.4.3",
|
|
257
|
-
"html-webpack-plugin": "^5.6.7",
|
|
258
|
-
"webpack": "^5.106.2",
|
|
259
|
-
"webpack-cli": "^7.0.2",
|
|
260
|
-
"webpack-dev-server": "^5.2.3"
|
|
258
|
+
"concurrently": "^9.2.1"
|
|
261
259
|
}
|
|
262
260
|
}
|
|
263
261
|
`,
|
|
@@ -279,14 +277,288 @@ This lab uses real webpack 5 + webpack-dev-server + Module Federation.
|
|
|
279
277
|
"scripts": {
|
|
280
278
|
"dev": "webpack serve --config webpack.config.js",
|
|
281
279
|
"build": "webpack --config webpack.config.js"
|
|
280
|
+
},
|
|
281
|
+
"dependencies": {
|
|
282
|
+
"react": "^19.0.0",
|
|
283
|
+
"react-dom": "^19.0.0",
|
|
284
|
+
"react-router-dom": "^7.6.1"
|
|
285
|
+
},
|
|
286
|
+
"devDependencies": {
|
|
287
|
+
"esbuild": "^0.28.0",
|
|
288
|
+
"esbuild-loader": "^4.4.3",
|
|
289
|
+
"html-webpack-plugin": "^5.6.7",
|
|
290
|
+
"webpack": "^5.106.2",
|
|
291
|
+
"webpack-cli": "^7.0.2",
|
|
292
|
+
"webpack-dev-server": "^5.2.3"
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
`,
|
|
296
|
+
"apps/shared/mfInspector.js": `import React from "react";
|
|
297
|
+
import ReactDOM from "react-dom";
|
|
298
|
+
// NOTE: default import (not namespace import) is intentional — namespace objects
|
|
299
|
+
// are never reference-equal across MF consumers even when the singleton is shared,
|
|
300
|
+
// so comparing the default export is the only way to prove same-instance.
|
|
301
|
+
|
|
302
|
+
const app =
|
|
303
|
+
typeof __MF_INSPECTOR_APP__ === "string" ? __MF_INSPECTOR_APP__ : "unknown";
|
|
304
|
+
const sandboxId =
|
|
305
|
+
typeof __MF_INSPECTOR_SANDBOX_ID__ === "string"
|
|
306
|
+
? __MF_INSPECTOR_SANDBOX_ID__
|
|
307
|
+
: "";
|
|
308
|
+
const declaredConfig =
|
|
309
|
+
typeof __MF_INSPECTOR_DECLARED_CONFIG__ !== "undefined"
|
|
310
|
+
? __MF_INSPECTOR_DECLARED_CONFIG__
|
|
311
|
+
: null;
|
|
312
|
+
const runtimeId =
|
|
313
|
+
typeof crypto !== "undefined" && typeof crypto.randomUUID === "function"
|
|
314
|
+
? crypto.randomUUID()
|
|
315
|
+
: app + "-" + Date.now() + "-" + Math.random().toString(36).slice(2);
|
|
316
|
+
|
|
317
|
+
let attachedRouteListeners = false;
|
|
318
|
+
|
|
319
|
+
function getRoute() {
|
|
320
|
+
if (typeof window === "undefined" || !window.location) return "/";
|
|
321
|
+
const route =
|
|
322
|
+
window.location.pathname +
|
|
323
|
+
window.location.search +
|
|
324
|
+
window.location.hash;
|
|
325
|
+
return route || "/";
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function cloneJsonSafe(value) {
|
|
329
|
+
if (value == null) return value;
|
|
330
|
+
try {
|
|
331
|
+
return JSON.parse(JSON.stringify(value));
|
|
332
|
+
} catch {
|
|
333
|
+
return value;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export async function ensureShareScopeReady() {
|
|
338
|
+
try {
|
|
339
|
+
if (typeof __webpack_init_sharing__ === "function") {
|
|
340
|
+
await __webpack_init_sharing__("default");
|
|
341
|
+
}
|
|
342
|
+
} catch (error) {
|
|
343
|
+
emitInspectorEvent("share-init-error", {
|
|
344
|
+
message: error instanceof Error ? error.message : String(error),
|
|
345
|
+
});
|
|
282
346
|
}
|
|
283
347
|
}
|
|
348
|
+
|
|
349
|
+
export function snapshotShareScopes() {
|
|
350
|
+
try {
|
|
351
|
+
if (typeof __webpack_share_scopes__ === "undefined") return {};
|
|
352
|
+
return Object.fromEntries(
|
|
353
|
+
Object.entries(__webpack_share_scopes__).map(([scopeName, scopeValue]) => [
|
|
354
|
+
scopeName,
|
|
355
|
+
Object.fromEntries(
|
|
356
|
+
Object.entries(scopeValue || {}).map(([packageName, versions]) => [
|
|
357
|
+
packageName,
|
|
358
|
+
Object.entries(versions || {}).map(([version, entry]) => ({
|
|
359
|
+
version,
|
|
360
|
+
from: entry && typeof entry.from === "string" ? entry.from : null,
|
|
361
|
+
eager: Boolean(entry && entry.eager),
|
|
362
|
+
loaded: Boolean(entry && entry.loaded),
|
|
363
|
+
hasGet: Boolean(entry && typeof entry.get === "function"),
|
|
364
|
+
})),
|
|
365
|
+
]),
|
|
366
|
+
),
|
|
367
|
+
]),
|
|
368
|
+
);
|
|
369
|
+
} catch (error) {
|
|
370
|
+
return {
|
|
371
|
+
__error: error instanceof Error ? error.message : String(error),
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export function emitInspectorEvent(kind, payload) {
|
|
377
|
+
if (!sandboxId || typeof window === "undefined" || !window.parent) return;
|
|
378
|
+
window.parent.postMessage(
|
|
379
|
+
{
|
|
380
|
+
type: "mf-inspector-event",
|
|
381
|
+
sandboxId,
|
|
382
|
+
app,
|
|
383
|
+
runtimeId,
|
|
384
|
+
kind,
|
|
385
|
+
route: getRoute(),
|
|
386
|
+
timestamp: Date.now(),
|
|
387
|
+
payload: cloneJsonSafe(payload),
|
|
388
|
+
},
|
|
389
|
+
"*",
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function attachRouteListeners() {
|
|
394
|
+
if (attachedRouteListeners || typeof window === "undefined") return;
|
|
395
|
+
attachedRouteListeners = true;
|
|
396
|
+
window.addEventListener("popstate", () => {
|
|
397
|
+
void emitRouteSnapshot("popstate");
|
|
398
|
+
});
|
|
399
|
+
window.addEventListener("hashchange", () => {
|
|
400
|
+
void emitRouteSnapshot("hashchange");
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export function emitDeclaredConfig() {
|
|
405
|
+
emitInspectorEvent("declared-config", {
|
|
406
|
+
declaredConfig: cloneJsonSafe(declaredConfig),
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export async function emitRuntimeBoot(label) {
|
|
411
|
+
attachRouteListeners();
|
|
412
|
+
await ensureShareScopeReady();
|
|
413
|
+
emitDeclaredConfig();
|
|
414
|
+
emitInspectorEvent("runtime-boot", {
|
|
415
|
+
label: label || "boot",
|
|
416
|
+
reactVersion: React.version || null,
|
|
417
|
+
reactDomVersion: ReactDOM.version || null,
|
|
418
|
+
declaredConfig: cloneJsonSafe(declaredConfig),
|
|
419
|
+
});
|
|
420
|
+
emitInspectorEvent("share-snapshot", {
|
|
421
|
+
label: (label || "boot") + ":share-snapshot",
|
|
422
|
+
shareScopes: snapshotShareScopes(),
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export async function emitRouteSnapshot(label) {
|
|
427
|
+
await ensureShareScopeReady();
|
|
428
|
+
emitInspectorEvent("route-change", {
|
|
429
|
+
label: label || "route",
|
|
430
|
+
shareScopes: snapshotShareScopes(),
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export function getRemoteInspectorBridge() {
|
|
435
|
+
return {
|
|
436
|
+
app,
|
|
437
|
+
reactVersion: React.version || null,
|
|
438
|
+
reactDomVersion: ReactDOM.version || null,
|
|
439
|
+
reactObject: React,
|
|
440
|
+
reactDomObject: ReactDOM,
|
|
441
|
+
declaredConfig: cloneJsonSafe(declaredConfig),
|
|
442
|
+
shareScopes: snapshotShareScopes(),
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export function makeInspectableLazy(remoteKey, componentLoad, debugLoad) {
|
|
447
|
+
return async () => {
|
|
448
|
+
await ensureShareScopeReady();
|
|
449
|
+
emitInspectorEvent("remote-load-start", {
|
|
450
|
+
remoteKey,
|
|
451
|
+
shareScopes: snapshotShareScopes(),
|
|
452
|
+
});
|
|
453
|
+
const startedAt =
|
|
454
|
+
typeof performance !== "undefined" && typeof performance.now === "function"
|
|
455
|
+
? performance.now()
|
|
456
|
+
: Date.now();
|
|
457
|
+
|
|
458
|
+
try {
|
|
459
|
+
const componentModule = await componentLoad();
|
|
460
|
+
const finishedAt =
|
|
461
|
+
typeof performance !== "undefined" && typeof performance.now === "function"
|
|
462
|
+
? performance.now()
|
|
463
|
+
: Date.now();
|
|
464
|
+
|
|
465
|
+
emitInspectorEvent("remote-load-success", {
|
|
466
|
+
remoteKey,
|
|
467
|
+
durationMs: Number((finishedAt - startedAt).toFixed(2)),
|
|
468
|
+
exportKeys: Object.keys(componentModule || {}),
|
|
469
|
+
shareScopes: snapshotShareScopes(),
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
if (debugLoad) {
|
|
473
|
+
try {
|
|
474
|
+
const debugModule = await debugLoad();
|
|
475
|
+
const bridgeValue =
|
|
476
|
+
typeof debugModule.getRemoteInspectorBridge === "function"
|
|
477
|
+
? debugModule.getRemoteInspectorBridge()
|
|
478
|
+
: typeof debugModule.default === "function"
|
|
479
|
+
? debugModule.default()
|
|
480
|
+
: debugModule.default || debugModule;
|
|
481
|
+
|
|
482
|
+
if (bridgeValue) {
|
|
483
|
+
emitInspectorEvent("identity-check", {
|
|
484
|
+
remoteKey,
|
|
485
|
+
remoteApp:
|
|
486
|
+
typeof bridgeValue.app === "string"
|
|
487
|
+
? bridgeValue.app
|
|
488
|
+
: remoteKey.split("/")[0],
|
|
489
|
+
reactVersion: bridgeValue.reactVersion || null,
|
|
490
|
+
reactDomVersion: bridgeValue.reactDomVersion || null,
|
|
491
|
+
sameReactInstance: bridgeValue.reactObject === React,
|
|
492
|
+
sameReactDomInstance: bridgeValue.reactDomObject === ReactDOM,
|
|
493
|
+
declaredConfig: cloneJsonSafe(bridgeValue.declaredConfig),
|
|
494
|
+
shareScopes: cloneJsonSafe(bridgeValue.shareScopes),
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
} catch (error) {
|
|
498
|
+
emitInspectorEvent("identity-check-error", {
|
|
499
|
+
remoteKey,
|
|
500
|
+
message: error instanceof Error ? error.message : String(error),
|
|
501
|
+
shareScopes: snapshotShareScopes(),
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return componentModule;
|
|
507
|
+
} catch (error) {
|
|
508
|
+
emitInspectorEvent("remote-load-error", {
|
|
509
|
+
remoteKey,
|
|
510
|
+
message: error instanceof Error ? error.message : String(error),
|
|
511
|
+
shareScopes: snapshotShareScopes(),
|
|
512
|
+
});
|
|
513
|
+
throw error;
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
`,
|
|
518
|
+
"apps/shared/buildSharedConfig.js": `function createSharedConfig(packageJson) {
|
|
519
|
+
const dependencyVersions =
|
|
520
|
+
packageJson && typeof packageJson === "object"
|
|
521
|
+
? packageJson.dependencies || {}
|
|
522
|
+
: {};
|
|
523
|
+
|
|
524
|
+
const sharedOverrides = {
|
|
525
|
+
react: {
|
|
526
|
+
singleton: true,
|
|
527
|
+
requiredVersion: dependencyVersions.react || false,
|
|
528
|
+
},
|
|
529
|
+
"react-dom": {
|
|
530
|
+
singleton: true,
|
|
531
|
+
requiredVersion: dependencyVersions["react-dom"] || false,
|
|
532
|
+
},
|
|
533
|
+
"react-router-dom": {
|
|
534
|
+
singleton: true,
|
|
535
|
+
requiredVersion: dependencyVersions["react-router-dom"] || false,
|
|
536
|
+
},
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
// Add package names here if you want them installed but NOT shared.
|
|
540
|
+
const unsharedPackages = new Set([]);
|
|
541
|
+
|
|
542
|
+
return Object.fromEntries(
|
|
543
|
+
Object.keys(dependencyVersions)
|
|
544
|
+
.filter((packageName) => !unsharedPackages.has(packageName))
|
|
545
|
+
.map((packageName) => [
|
|
546
|
+
packageName,
|
|
547
|
+
sharedOverrides[packageName] ?? {
|
|
548
|
+
requiredVersion: dependencyVersions[packageName] || false,
|
|
549
|
+
},
|
|
550
|
+
]),
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
module.exports = { createSharedConfig };
|
|
284
555
|
`,
|
|
285
556
|
"apps/host/src/index.jsx": `import("./bootstrap");
|
|
286
557
|
`,
|
|
287
558
|
"apps/host/src/bootstrap.jsx": `import React from "react";
|
|
288
559
|
import { createRoot } from "react-dom/client";
|
|
289
560
|
import App from "./App";
|
|
561
|
+
import { emitRuntimeBoot } from "../../shared/mfInspector";
|
|
290
562
|
|
|
291
563
|
const root = createRoot(document.getElementById("root"));
|
|
292
564
|
|
|
@@ -295,11 +567,26 @@ root.render(
|
|
|
295
567
|
<App />
|
|
296
568
|
</React.StrictMode>,
|
|
297
569
|
);
|
|
570
|
+
|
|
571
|
+
void emitRuntimeBoot("host-bootstrap");
|
|
298
572
|
`,
|
|
299
573
|
"apps/host/src/App.jsx": `import React, { Suspense } from "react";
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
const
|
|
574
|
+
import { makeInspectableLazy } from "../../shared/mfInspector";
|
|
575
|
+
|
|
576
|
+
const ProfileCard = React.lazy(
|
|
577
|
+
makeInspectableLazy(
|
|
578
|
+
"profile/ProfileCard",
|
|
579
|
+
() => import("profile/ProfileCard"),
|
|
580
|
+
() => import("profile/InspectorBridge"),
|
|
581
|
+
),
|
|
582
|
+
);
|
|
583
|
+
const CheckoutPanel = React.lazy(
|
|
584
|
+
makeInspectableLazy(
|
|
585
|
+
"checkout/CheckoutPanel",
|
|
586
|
+
() => import("checkout/CheckoutPanel"),
|
|
587
|
+
() => import("checkout/InspectorBridge"),
|
|
588
|
+
),
|
|
589
|
+
);
|
|
303
590
|
|
|
304
591
|
function RemoteBoundary({ title, children }) {
|
|
305
592
|
return (
|
|
@@ -366,12 +653,25 @@ export default function App() {
|
|
|
366
653
|
}
|
|
367
654
|
`,
|
|
368
655
|
"apps/host/webpack.config.js": `const path = require("path");
|
|
656
|
+
const webpack = require("webpack");
|
|
369
657
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
|
370
|
-
const { ModuleFederationPlugin } =
|
|
658
|
+
const { ModuleFederationPlugin } = webpack.container;
|
|
659
|
+
const packageJson = require("./package.json");
|
|
660
|
+
const { createSharedConfig } = require("../shared/buildSharedConfig");
|
|
371
661
|
|
|
372
662
|
const hostPort = Number(process.env.HOST_PORT || 3100);
|
|
373
663
|
const profilePort = Number(process.env.PROFILE_PORT || 3101);
|
|
374
664
|
const checkoutPort = Number(process.env.CHECKOUT_PORT || 3102);
|
|
665
|
+
const sharedConfig = createSharedConfig(packageJson);
|
|
666
|
+
const remoteConfig = {
|
|
667
|
+
profile: "profile@http://localhost:" + profilePort + "/remoteEntry.js",
|
|
668
|
+
checkout: "checkout@http://localhost:" + checkoutPort + "/remoteEntry.js",
|
|
669
|
+
};
|
|
670
|
+
const inspectorConfig = {
|
|
671
|
+
app: "host",
|
|
672
|
+
remotes: remoteConfig,
|
|
673
|
+
shared: sharedConfig,
|
|
674
|
+
};
|
|
375
675
|
|
|
376
676
|
module.exports = {
|
|
377
677
|
mode: "development",
|
|
@@ -409,16 +709,15 @@ module.exports = {
|
|
|
409
709
|
},
|
|
410
710
|
},
|
|
411
711
|
plugins: [
|
|
712
|
+
new webpack.DefinePlugin({
|
|
713
|
+
__MF_INSPECTOR_APP__: JSON.stringify("host"),
|
|
714
|
+
__MF_INSPECTOR_SANDBOX_ID__: JSON.stringify(process.env.MF_SANDBOX_ID || ""),
|
|
715
|
+
__MF_INSPECTOR_DECLARED_CONFIG__: JSON.stringify(inspectorConfig),
|
|
716
|
+
}),
|
|
412
717
|
new ModuleFederationPlugin({
|
|
413
718
|
name: "host",
|
|
414
|
-
remotes:
|
|
415
|
-
|
|
416
|
-
checkout: "checkout@http://localhost:" + checkoutPort + "/remoteEntry.js",
|
|
417
|
-
},
|
|
418
|
-
shared: {
|
|
419
|
-
react: { singleton: true, requiredVersion: false },
|
|
420
|
-
"react-dom": { singleton: true, requiredVersion: false },
|
|
421
|
-
},
|
|
719
|
+
remotes: remoteConfig,
|
|
720
|
+
shared: sharedConfig,
|
|
422
721
|
}),
|
|
423
722
|
new HtmlWebpackPlugin({
|
|
424
723
|
template: path.resolve(__dirname, "./public/index.html"),
|
|
@@ -444,14 +743,33 @@ module.exports = {
|
|
|
444
743
|
"scripts": {
|
|
445
744
|
"dev": "webpack serve --config webpack.config.js",
|
|
446
745
|
"build": "webpack --config webpack.config.js"
|
|
746
|
+
},
|
|
747
|
+
"dependencies": {
|
|
748
|
+
"react": "^19.0.0",
|
|
749
|
+
"react-dom": "^19.0.0",
|
|
750
|
+
"react-router-dom": "^7.6.1"
|
|
751
|
+
},
|
|
752
|
+
"devDependencies": {
|
|
753
|
+
"esbuild": "^0.28.0",
|
|
754
|
+
"esbuild-loader": "^4.4.3",
|
|
755
|
+
"html-webpack-plugin": "^5.6.7",
|
|
756
|
+
"webpack": "^5.106.2",
|
|
757
|
+
"webpack-cli": "^7.0.2",
|
|
758
|
+
"webpack-dev-server": "^5.2.3"
|
|
447
759
|
}
|
|
448
760
|
}
|
|
761
|
+
`,
|
|
762
|
+
"apps/profile/src/inspectorBridge.js": `import { getRemoteInspectorBridge } from "../../shared/mfInspector";
|
|
763
|
+
|
|
764
|
+
export { getRemoteInspectorBridge };
|
|
765
|
+
export default getRemoteInspectorBridge;
|
|
449
766
|
`,
|
|
450
767
|
"apps/profile/src/index.jsx": `import("./bootstrap");
|
|
451
768
|
`,
|
|
452
769
|
"apps/profile/src/bootstrap.jsx": `import React from "react";
|
|
453
770
|
import { createRoot } from "react-dom/client";
|
|
454
771
|
import App from "./App";
|
|
772
|
+
import { emitRuntimeBoot } from "../../shared/mfInspector";
|
|
455
773
|
|
|
456
774
|
const root = createRoot(document.getElementById("root"));
|
|
457
775
|
|
|
@@ -460,6 +778,8 @@ root.render(
|
|
|
460
778
|
<App />
|
|
461
779
|
</React.StrictMode>,
|
|
462
780
|
);
|
|
781
|
+
|
|
782
|
+
void emitRuntimeBoot("profile-bootstrap");
|
|
463
783
|
`,
|
|
464
784
|
"apps/profile/src/App.jsx": `import React from "react";
|
|
465
785
|
import ProfileCard from "./ProfileCard";
|
|
@@ -496,10 +816,23 @@ export default function ProfileCard() {
|
|
|
496
816
|
}
|
|
497
817
|
`,
|
|
498
818
|
"apps/profile/webpack.config.js": `const path = require("path");
|
|
819
|
+
const webpack = require("webpack");
|
|
499
820
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
|
500
|
-
const { ModuleFederationPlugin } =
|
|
821
|
+
const { ModuleFederationPlugin } = webpack.container;
|
|
822
|
+
const packageJson = require("./package.json");
|
|
823
|
+
const { createSharedConfig } = require("../shared/buildSharedConfig");
|
|
501
824
|
|
|
502
825
|
const profilePort = Number(process.env.PROFILE_PORT || 3101);
|
|
826
|
+
const sharedConfig = createSharedConfig(packageJson);
|
|
827
|
+
const exposeConfig = {
|
|
828
|
+
"./ProfileCard": path.resolve(__dirname, "./src/ProfileCard.jsx"),
|
|
829
|
+
"./InspectorBridge": path.resolve(__dirname, "./src/inspectorBridge.js"),
|
|
830
|
+
};
|
|
831
|
+
const inspectorConfig = {
|
|
832
|
+
app: "profile",
|
|
833
|
+
exposes: Object.keys(exposeConfig),
|
|
834
|
+
shared: sharedConfig,
|
|
835
|
+
};
|
|
503
836
|
|
|
504
837
|
module.exports = {
|
|
505
838
|
mode: "development",
|
|
@@ -530,22 +863,23 @@ module.exports = {
|
|
|
530
863
|
},
|
|
531
864
|
devServer: {
|
|
532
865
|
port: profilePort,
|
|
866
|
+
historyApiFallback: true,
|
|
533
867
|
hot: true,
|
|
534
868
|
headers: {
|
|
535
869
|
"Access-Control-Allow-Origin": "*",
|
|
536
870
|
},
|
|
537
871
|
},
|
|
538
872
|
plugins: [
|
|
873
|
+
new webpack.DefinePlugin({
|
|
874
|
+
__MF_INSPECTOR_APP__: JSON.stringify("profile"),
|
|
875
|
+
__MF_INSPECTOR_SANDBOX_ID__: JSON.stringify(process.env.MF_SANDBOX_ID || ""),
|
|
876
|
+
__MF_INSPECTOR_DECLARED_CONFIG__: JSON.stringify(inspectorConfig),
|
|
877
|
+
}),
|
|
539
878
|
new ModuleFederationPlugin({
|
|
540
879
|
name: "profile",
|
|
541
880
|
filename: "remoteEntry.js",
|
|
542
|
-
exposes:
|
|
543
|
-
|
|
544
|
-
},
|
|
545
|
-
shared: {
|
|
546
|
-
react: { singleton: true, requiredVersion: false },
|
|
547
|
-
"react-dom": { singleton: true, requiredVersion: false },
|
|
548
|
-
},
|
|
881
|
+
exposes: exposeConfig,
|
|
882
|
+
shared: sharedConfig,
|
|
549
883
|
}),
|
|
550
884
|
new HtmlWebpackPlugin({
|
|
551
885
|
template: path.resolve(__dirname, "./public/index.html"),
|
|
@@ -571,14 +905,33 @@ module.exports = {
|
|
|
571
905
|
"scripts": {
|
|
572
906
|
"dev": "webpack serve --config webpack.config.js",
|
|
573
907
|
"build": "webpack --config webpack.config.js"
|
|
908
|
+
},
|
|
909
|
+
"dependencies": {
|
|
910
|
+
"react": "^19.0.0",
|
|
911
|
+
"react-dom": "^19.0.0",
|
|
912
|
+
"react-router-dom": "^7.6.1"
|
|
913
|
+
},
|
|
914
|
+
"devDependencies": {
|
|
915
|
+
"esbuild": "^0.28.0",
|
|
916
|
+
"esbuild-loader": "^4.4.3",
|
|
917
|
+
"html-webpack-plugin": "^5.6.7",
|
|
918
|
+
"webpack": "^5.106.2",
|
|
919
|
+
"webpack-cli": "^7.0.2",
|
|
920
|
+
"webpack-dev-server": "^5.2.3"
|
|
574
921
|
}
|
|
575
922
|
}
|
|
923
|
+
`,
|
|
924
|
+
"apps/checkout/src/inspectorBridge.js": `import { getRemoteInspectorBridge } from "../../shared/mfInspector";
|
|
925
|
+
|
|
926
|
+
export { getRemoteInspectorBridge };
|
|
927
|
+
export default getRemoteInspectorBridge;
|
|
576
928
|
`,
|
|
577
929
|
"apps/checkout/src/index.jsx": `import("./bootstrap");
|
|
578
930
|
`,
|
|
579
931
|
"apps/checkout/src/bootstrap.jsx": `import React from "react";
|
|
580
932
|
import { createRoot } from "react-dom/client";
|
|
581
933
|
import App from "./App";
|
|
934
|
+
import { emitRuntimeBoot } from "../../shared/mfInspector";
|
|
582
935
|
|
|
583
936
|
const root = createRoot(document.getElementById("root"));
|
|
584
937
|
|
|
@@ -587,6 +940,8 @@ root.render(
|
|
|
587
940
|
<App />
|
|
588
941
|
</React.StrictMode>,
|
|
589
942
|
);
|
|
943
|
+
|
|
944
|
+
void emitRuntimeBoot("checkout-bootstrap");
|
|
590
945
|
`,
|
|
591
946
|
"apps/checkout/src/App.jsx": `import React from "react";
|
|
592
947
|
import CheckoutPanel from "./CheckoutPanel";
|
|
@@ -631,10 +986,23 @@ export default function CheckoutPanel() {
|
|
|
631
986
|
}
|
|
632
987
|
`,
|
|
633
988
|
"apps/checkout/webpack.config.js": `const path = require("path");
|
|
989
|
+
const webpack = require("webpack");
|
|
634
990
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
|
635
|
-
const { ModuleFederationPlugin } =
|
|
991
|
+
const { ModuleFederationPlugin } = webpack.container;
|
|
992
|
+
const packageJson = require("./package.json");
|
|
993
|
+
const { createSharedConfig } = require("../shared/buildSharedConfig");
|
|
636
994
|
|
|
637
995
|
const checkoutPort = Number(process.env.CHECKOUT_PORT || 3102);
|
|
996
|
+
const sharedConfig = createSharedConfig(packageJson);
|
|
997
|
+
const exposeConfig = {
|
|
998
|
+
"./CheckoutPanel": path.resolve(__dirname, "./src/CheckoutPanel.jsx"),
|
|
999
|
+
"./InspectorBridge": path.resolve(__dirname, "./src/inspectorBridge.js"),
|
|
1000
|
+
};
|
|
1001
|
+
const inspectorConfig = {
|
|
1002
|
+
app: "checkout",
|
|
1003
|
+
exposes: Object.keys(exposeConfig),
|
|
1004
|
+
shared: sharedConfig,
|
|
1005
|
+
};
|
|
638
1006
|
|
|
639
1007
|
module.exports = {
|
|
640
1008
|
mode: "development",
|
|
@@ -665,22 +1033,23 @@ module.exports = {
|
|
|
665
1033
|
},
|
|
666
1034
|
devServer: {
|
|
667
1035
|
port: checkoutPort,
|
|
1036
|
+
historyApiFallback: true,
|
|
668
1037
|
hot: true,
|
|
669
1038
|
headers: {
|
|
670
1039
|
"Access-Control-Allow-Origin": "*",
|
|
671
1040
|
},
|
|
672
1041
|
},
|
|
673
1042
|
plugins: [
|
|
1043
|
+
new webpack.DefinePlugin({
|
|
1044
|
+
__MF_INSPECTOR_APP__: JSON.stringify("checkout"),
|
|
1045
|
+
__MF_INSPECTOR_SANDBOX_ID__: JSON.stringify(process.env.MF_SANDBOX_ID || ""),
|
|
1046
|
+
__MF_INSPECTOR_DECLARED_CONFIG__: JSON.stringify(inspectorConfig),
|
|
1047
|
+
}),
|
|
674
1048
|
new ModuleFederationPlugin({
|
|
675
1049
|
name: "checkout",
|
|
676
1050
|
filename: "remoteEntry.js",
|
|
677
|
-
exposes:
|
|
678
|
-
|
|
679
|
-
},
|
|
680
|
-
shared: {
|
|
681
|
-
react: { singleton: true, requiredVersion: false },
|
|
682
|
-
"react-dom": { singleton: true, requiredVersion: false },
|
|
683
|
-
},
|
|
1051
|
+
exposes: exposeConfig,
|
|
1052
|
+
shared: sharedConfig,
|
|
684
1053
|
}),
|
|
685
1054
|
new HtmlWebpackPlugin({
|
|
686
1055
|
template: path.resolve(__dirname, "./public/index.html"),
|
|
@@ -1,30 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"root": [
|
|
3
|
-
"./src/app.tsx",
|
|
4
|
-
"./src/api.ts",
|
|
5
|
-
"./src/main.tsx",
|
|
6
|
-
"./src/store.ts",
|
|
7
|
-
"./src/types.ts",
|
|
8
|
-
"./src/vite-env.d.ts",
|
|
9
|
-
"./src/components/aisettingsmodal.tsx",
|
|
10
|
-
"./src/components/annotationdialog.tsx",
|
|
11
|
-
"./src/components/chatmessage.tsx",
|
|
12
|
-
"./src/components/chatview.tsx",
|
|
13
|
-
"./src/components/codecontextpanel.tsx",
|
|
14
|
-
"./src/components/codelineannotationpopup.tsx",
|
|
15
|
-
"./src/components/coderunnermodal.tsx",
|
|
16
|
-
"./src/components/docrefmodal.tsx",
|
|
17
|
-
"./src/components/fileattachments.tsx",
|
|
18
|
-
"./src/components/filepickermodal.tsx",
|
|
19
|
-
"./src/components/fileviewermodal.tsx",
|
|
20
|
-
"./src/components/linkedconvospicker.tsx",
|
|
21
|
-
"./src/components/markdownrenderer.tsx",
|
|
22
|
-
"./src/components/mermaiddiagram.tsx",
|
|
23
|
-
"./src/components/plotembed.tsx",
|
|
24
|
-
"./src/components/sidebar.tsx",
|
|
25
|
-
"./src/components/textannotator.tsx",
|
|
26
|
-
"./src/components/vizcraftembed.tsx",
|
|
27
|
-
"./src/components/workspaceswitcher.tsx"
|
|
28
|
-
],
|
|
29
|
-
"version": "5.9.3"
|
|
30
|
-
}
|
|
1
|
+
{"root":["./src/app.tsx","./src/api.ts","./src/infralab.ts","./src/main.tsx","./src/reactlab.ts","./src/store.ts","./src/types.ts","./src/vite-env.d.ts","./src/components/aisettingsmodal.tsx","./src/components/annotationdialog.tsx","./src/components/chatmessage.tsx","./src/components/chatview.tsx","./src/components/codecontextpanel.tsx","./src/components/codelineannotationpopup.tsx","./src/components/coderunnermodal.tsx","./src/components/docrefmodal.tsx","./src/components/fileattachments.tsx","./src/components/filepickermodal.tsx","./src/components/fileviewermodal.tsx","./src/components/infralabmodal.tsx","./src/components/linkedconvospicker.tsx","./src/components/markdownrenderer.tsx","./src/components/mermaiddiagram.tsx","./src/components/notesmodal.tsx","./src/components/plotembed.tsx","./src/components/sidebar.tsx","./src/components/textannotator.tsx","./src/components/vizcraftembed.tsx","./src/components/workspaceswitcher.tsx"],"errors":true,"version":"5.9.3"}
|
package/template/cockpit.json
CHANGED