FN-6111: alias bundled plugin views to source entries

Keep bundled plugin dashboard views loading from source so Compound Engineering no longer falls back to the unavailable placeholder.

- switch bundled dependency graph, roadmap, and compound engineering dashboard view loaders to static literal imports
- add vitest aliases for dependency graph and compound engineering dashboard view source entrypoints and cover the alias contract with regression tests
- document the missing-alias failure mode and the static-import requirement for bundled dashboard views

Files changed:
 .../bundled-plugin-vite-alias-missing.md            | 20 +++++++++++---------
 .../__tests__/registerBundledPluginViews.test.tsx   | 10 +++++++--
 .../app/plugins/registerBundledPluginViews.ts       | 19 +++++-------------
 .../runtime-plugin-alias-regression.test.ts         | 21 ++++++++++++++------
 packages/dashboard/vitest.config.ts                 |  8 ++++++++
 5 files changed, 49 insertions(+), 29 deletions(-)

Fusion-Task-Id: FN-6111

Fusion-Task-Lineage: a41b893c-4c14-4a2d-b0c9-47e1dbd0e1ef
This commit is contained in:
gsxdsm
2026-06-09 12:00:45 -07:00
parent d1996a9899
commit 7cfc2168a2
5 changed files with 49 additions and 29 deletions

View File

@@ -7,6 +7,7 @@ import {
} from "../registerBundledPluginViews";
const MockDependencyGraphDashboardView = () => createElement("div", { "data-testid": "dep-graph-view" });
const MockCompoundEngineeringDashboardView = () => createElement("div", { "data-testid": "ce-view" });
const MockRoadmapDashboardView = () => createElement("div", { "data-testid": "roadmap-view" });
const MockCliPrintingPressWizardView = () => createElement("div", { "data-testid": "cli-printing-press-view" });
const MockCliPrintingPressManageView = () => createElement("div", { "data-testid": "cli-printing-press-manage-view" });
@@ -15,6 +16,10 @@ vi.mock("@fusion-plugin-examples/dependency-graph/dashboard-view", () => ({
DependencyGraphDashboardView: (...args: unknown[]) => MockDependencyGraphDashboardView(...args),
}));
vi.mock("@fusion-plugin-examples/compound-engineering/dashboard-view", () => ({
CompoundEngineeringDashboardView: (...args: unknown[]) => MockCompoundEngineeringDashboardView(...args),
}));
vi.mock("@fusion-plugin-examples/fusion-plugin-roadmap/dashboard-view", () => ({
RoadmapDashboardView: (...args: unknown[]) => MockRoadmapDashboardView(...args),
}));
@@ -36,13 +41,15 @@ describe("registerBundledPluginViews", () => {
__test_resetBundledPluginViewRegistration();
});
it("registers dependency graph, roadmap, and cli printing press bundled views", () => {
it("registers dependency graph, compound engineering, roadmap, and cli printing press bundled views", () => {
registerBundledPluginViews();
// This registration is independent of engine-side plugin load success; the
// dashboard can still render the Graph view while the plugin install row is errored.
expect(isPluginViewRegistered("fusion-plugin-dependency-graph", "graph")).toBe(true);
expect(getPluginViewComponent("fusion-plugin-dependency-graph", "graph")).toBeTruthy();
expect(isPluginViewRegistered("fusion-plugin-compound-engineering", "compound-engineering")).toBe(true);
expect(getPluginViewComponent("fusion-plugin-compound-engineering", "compound-engineering")).toBeTruthy();
expect(getPluginViewComponent("fusion-plugin-roadmap", "roadmaps")).toBeTruthy();
expect(getPluginViewComponent("fusion-plugin-cli-printing-press", "wizard")).toBeTruthy();
expect(getPluginViewComponent("fusion-plugin-cli-printing-press", "manage")).toBeTruthy();
@@ -62,6 +69,7 @@ describe("registerBundledPluginViews", () => {
registerBundledPluginViews();
expect(isPluginViewRegistered("fusion-plugin-dependency-graph", "graph")).toBe(true);
expect(isPluginViewRegistered("fusion-plugin-compound-engineering", "compound-engineering")).toBe(true);
expect(isPluginViewRegistered("fusion-plugin-roadmap", "roadmaps")).toBe(true);
expect(isPluginViewRegistered("fusion-plugin-cli-printing-press", "wizard")).toBe(true);
expect(isPluginViewRegistered("fusion-plugin-cli-printing-press", "manage")).toBe(true);

View File

@@ -38,24 +38,15 @@ async function loadRoadmapView(): Promise<{ default: PluginViewComponent }> {
}
async function loadCompoundEngineeringView(): Promise<{ default: PluginViewComponent }> {
// @vite-ignore + moduleId variable so tsc does NOT statically resolve/compile
// the plugin's source here. The plugin must not depend on @fusion/dashboard
// (workspace-acyclicity invariant), so its type-only dashboard import only
// resolves in the plugin's own build; a literal import would make the
// dashboard typecheck the plugin file and fail to resolve that import.
const moduleId = "@fusion-plugin-examples/compound-engineering/dashboard-view";
const exportName = "CompoundEngineeringDashboardView";
try {
const mod = await import(/* @vite-ignore */ moduleId) as unknown as Record<string, ComponentType<{ context?: PluginDashboardViewContext }>>;
const component = mod[exportName];
if (!component) {
console.warn(`[plugin-views] Missing export ${exportName} from ${moduleId}`);
return { default: createMissingPluginView(moduleId, exportName) };
}
return { default: component as PluginViewComponent };
} catch {
const mod = await import("@fusion-plugin-examples/compound-engineering/dashboard-view") as unknown as Record<string, ComponentType<{ context?: PluginDashboardViewContext }>>;
const component = mod[exportName];
if (!component) {
console.warn(`[plugin-views] Missing export ${exportName} from ${moduleId}`);
return { default: createMissingPluginView(moduleId, exportName) };
}
return { default: component as PluginViewComponent };
}
async function loadCliPrintingPressWizardView(): Promise<{ default: PluginViewComponent }> {

View File

@@ -23,11 +23,10 @@ describe("FN-3298 regression: dashboard vitest runtime plugins resolve from sour
expect(config).not.toContain('fusion-plugin-paperclip-runtime/dist/index.js');
});
// FN-3888 regression: bundled dependency-graph dashboard view must not depend
// on plugins/fusion-plugin-dependency-graph/dist/, which goes stale when the
// plugin source is edited without a manual rebuild and surfaces in the UI as
// "Bundled plugin view unavailable: @fusion-plugin-examples/dependency-graph/dashboard-view".
it("aliases dependency-graph plugin imports to src in vite and vitest configs", () => {
// FN-3888/FN-6111 regression: bundled dashboard views must not depend on
// plugins/*/dist/, which goes stale when plugin source is edited without a
// manual rebuild and surfaces in the UI as "Bundled plugin view unavailable".
it("aliases bundled dashboard view plugin imports to src in vite and vitest configs", () => {
const testDir = dirname(fileURLToPath(import.meta.url));
const dashboardDir = join(testDir, "..", "..");
@@ -41,6 +40,18 @@ describe("FN-3298 regression: dashboard vitest runtime plugins resolve from sour
'"../../plugins/fusion-plugin-dependency-graph/src/dashboard-view.tsx"',
);
expect(config).not.toContain("fusion-plugin-dependency-graph/dist/");
expect(
config,
`${configFile} must alias the compound-engineering dashboard-view to src`,
).toContain('"@fusion-plugin-examples/compound-engineering/dashboard-view": resolve(');
expect(config).toContain(
'"../../plugins/fusion-plugin-compound-engineering/src/dashboard-view.tsx"',
);
expect(config).toContain('"@fusion-plugin-examples/compound-engineering": resolve(');
expect(config).toContain(
'"../../plugins/fusion-plugin-compound-engineering/src/index.ts"',
);
expect(config).not.toContain("fusion-plugin-compound-engineering/dist/");
}
});
});

View File

@@ -302,6 +302,14 @@ export default defineConfig({
__dirname,
"../../plugins/fusion-plugin-dependency-graph/src/index.ts",
),
"@fusion-plugin-examples/compound-engineering/dashboard-view": resolve(
__dirname,
"../../plugins/fusion-plugin-compound-engineering/src/dashboard-view.tsx",
),
"@fusion-plugin-examples/compound-engineering": resolve(
__dirname,
"../../plugins/fusion-plugin-compound-engineering/src/index.ts",
),
},
},
test: {