fix(FN-3888): resolve dependency-graph plugin from src in dashboard build
The dashboard dynamically imports `@fusion-plugin-examples/dependency-graph/dashboard-view`, which resolved through the plugin's package.json exports to `dist/`. When plugin source was edited without rebuilding, stale `dist/` (extensionless ESM imports) made the import throw and the UI surfaced "Bundled plugin view unavailable". Add vite/vitest aliases mapping the plugin (and its `/dashboard-view` subpath) to `src/` so the dashboard never depends on `dist/`. Mirrors the existing pattern for hermes/openclaw/paperclip runtimes. Also extends the runtime-plugin alias regression test, and emits `.js` extensions from the plugin source for the CLI-bundled path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { mkdtempSync } from "node:fs";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { existsSync, mkdtempSync } from "node:fs";
|
||||
import { rm } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, join } from "node:path";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { PluginLoader, PluginStore } from "@fusion/core";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import plugin from "../index";
|
||||
@@ -24,6 +25,7 @@ describe("dependency graph plugin index", () => {
|
||||
);
|
||||
});
|
||||
|
||||
// Vitest's resolver can mask extensionless-import issues in emitted dist files.
|
||||
it("is loadable through package exports", async () => {
|
||||
const entryModule = await import("@fusion-plugin-examples/dependency-graph");
|
||||
expect(entryModule.default?.manifest?.id).toBe("fusion-plugin-dependency-graph");
|
||||
@@ -35,6 +37,29 @@ describe("dependency graph plugin index", () => {
|
||||
expect(typeof viewModule.default).toBe("function");
|
||||
});
|
||||
|
||||
const hasNodeImportPrereqs =
|
||||
existsSync(join(process.cwd(), "dist/dashboard-view.js")) &&
|
||||
existsSync(join(process.cwd(), "node_modules/@fusion/plugin-sdk/dist/index.js"));
|
||||
const nodeImportTest = hasNodeImportPrereqs ? it : it.skip;
|
||||
nodeImportTest("keeps built entrypoint imports Node-ESM-safe for relative specifiers", () => {
|
||||
const script =
|
||||
"Promise.all([" +
|
||||
"import('./plugins/fusion-plugin-dependency-graph/dist/index.js')," +
|
||||
"import('node:fs/promises').then((fs) => fs.readFile('./plugins/fusion-plugin-dependency-graph/dist/dashboard-view.js', 'utf8'))" +
|
||||
"]).then(([root, dashboardViewSource]) => {" +
|
||||
"if (root.default?.manifest?.id !== 'fusion-plugin-dependency-graph') process.exit(2);" +
|
||||
"if (!dashboardViewSource.includes('from \\\"./DependencyGraph.js\\\"')) process.exit(3);" +
|
||||
"}).catch((e) => { console.error(e?.code, e?.message); process.exit(1); });";
|
||||
|
||||
const repoRoot = resolve(process.cwd(), "../..");
|
||||
const result = spawnSync(process.execPath, ["-e", script], {
|
||||
cwd: repoRoot,
|
||||
encoding: "utf8",
|
||||
});
|
||||
|
||||
expect(result.status, `Node import check failed: ${result.stderr || result.stdout}`).toBe(0);
|
||||
});
|
||||
|
||||
it("is loadable by PluginLoader without throwing", async () => {
|
||||
const rootDir = mkdtempSync(join(tmpdir(), "fn-3737-plugin-loader-"));
|
||||
testDirs.push(rootDir);
|
||||
|
||||
Reference in New Issue
Block a user