FN-6085: avoid dashboard CSS import in plugin entry

Prevent the Compound Engineering plugin from pulling dashboard CSS into Node-side plugin loading.

- remove the dashboard view re-export from the Compound Engineering plugin server entry
- document the CSS-import failure mode caused by server-side index re-exports of dashboard views
- update bundled plugin registration guidance to keep dashboard view loading client-only

Files changed:
 docs/solutions/integration-issues/bundled-plugin-registration-drift.md |  4 ++--
 docs/solutions/integration-issues/bundled-plugin-vite-alias-missing.md | 13 ++++++++++++-
 plugins/fusion-plugin-compound-engineering/src/index.ts     |  1 -
 3 files changed, 14 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-6085

Fusion-Task-Lineage: 38e6d4de-18ff-4f7b-9ea4-39b0653b4cce
This commit is contained in:
gsxdsm
2026-06-09 09:45:55 -07:00
parent 8d7fc1a6c5
commit 81c5bfeb27
3 changed files with 14 additions and 4 deletions

View File

@@ -29,7 +29,7 @@ The four registration points:
3. **CLI startup** — `BUNDLED_PLUGIN_IDS` in `packages/cli/src/plugins/bundled-plugin-install.ts` (auto-install/upgrade of bundled plugins)
4. **Build staging** — `packages/cli/tsup.config.ts` (`bundlePluginEntry` or a copy block staging the plugin into `dist/plugins/<id>/` so packaged installs have a copy at all)
A plugin with a dashboard view additionally needs client-side view registration in `packages/dashboard/app/plugins/registerBundledPluginViews.ts`.
A plugin with a dashboard view additionally needs client-side view registration in `packages/dashboard/app/plugins/registerBundledPluginViews.ts`. Its dashboard view component must **not** be re-exported from the plugin's server-side `src/index.ts`; keep only the `dashboardViews` manifest metadata there so Node-side plugin loading does not chase React/CSS imports.
## Symptoms
@@ -78,7 +78,7 @@ The Settings card sends a relative `./plugins/<id>` path. The server resolves it
## Prevention
- **When adding a bundled plugin, grep for an existing one** (e.g. `rg -l "fusion-plugin-roadmap" packages/` ) and mirror every hit — that surfaces all four lists plus view registration.
- **When adding a bundled plugin, grep for an existing one** (e.g. `rg -l "fusion-plugin-roadmap" packages/` ) and mirror every hit — that surfaces all four lists plus view registration. If the plugin has a dashboard view, keep the view load path client-only and do not re-export the view component from the server entry.
- Route tests must force the fallback: mock fs so the cwd-relative path **misses** and only `dist/plugins/<id>` exists (see "installs bundled compound engineering plugin when relative path misses cwd" in `packages/dashboard/src/__tests__/plugin-routes.test.ts`). A mock that matches any path containing the plugin id tests nothing.
- **Pin assertions to the exact contract, not substring containment.** `stringContaining(pluginId)` passed for both the correct entry-file path and the buggy directory path — when a mock or matcher can satisfy both the correct and the buggy value, the test proves nothing. Route tests now assert the registered path ends in an entry-file suffix, cover the `dist/index.js` and `src/index.ts` fallbacks, and the 400 no-entry branch.
- When duplicating a helper is forced by test infrastructure (fs mocks vs externalized deps), add a real-fs drift-guard test that runs every copy against the same on-disk fixtures and asserts identical output.

View File

@@ -76,12 +76,23 @@ const mod = await import(/* @vite-ignore */ moduleId);
Vite's static analysis cannot trace these imports, so it relies on `resolve.alias` to map the module ID to a filesystem path. Without the alias, Vite falls through to default resolution, which fails because the plugin package is in a sibling `plugins/` directory outside the dashboard's root. The error surfaces through the CSS loader because Vite's fallback resolution path misattributes the failure.
## Related root cause: CSS import via index re-export
The same `Unknown file extension ".css"` symptom can also happen when a plugin's **server-side entry** (`src/index.ts` / `dist/index.js`) re-exports its dashboard view component:
```ts
export { SomeDashboardView } from "./dashboard-view.js";
```
Server-side plugin loading uses Node.js `import()` against the plugin entry. If that entry re-exports a React dashboard view, Node follows the chain into the view and any imported `.css` files before Vite is involved, then crashes because the Node ESM loader does not handle CSS. The fix is to keep dashboard view components out of the server entry: preserve the `dashboardViews` manifest metadata (`componentPath: "./dashboard-view"`) and load the view client-side through `registerBundledPluginViews.ts` plus the Vite alias.
## Prevention
- **When adding a bundled plugin with a dashboard view, grep for an existing plugin alias** in `packages/dashboard/vite.config.ts` and mirror the pattern for the new plugin
- **Do not re-export dashboard view components from the plugin's server-side `index.ts`** — the server entry must stay free of React/CSS view imports; `dashboardViews` metadata is enough for registration
- **Verify the alias in both dev and production builds** — the alias must resolve correctly for Vite's dev server and its production bundler
- **Consider a consistency test** that asserts every plugin registered in `registerBundledPluginViews.ts` has a corresponding Vite alias (similar to the existing `lazy-loaded-views-docs.test.ts` that keeps the AGENTS.md view inventory in sync)
- **Watch for the misleading `.css` error** — when Vite reports an unknown file extension for a file that clearly exists, suspect module resolution failure before investigating loaders
- **Watch for the misleading `.css` error** — when Vite reports an unknown file extension for a file that clearly exists, suspect module resolution failure before investigating loaders; when Node reports it while enabling a plugin, suspect a server-entry re-export of the dashboard view
## Related Issues

View File

@@ -9,7 +9,6 @@ import { reconcileCePipelines } from "./sync/reconciler.js";
import { settingsSchema } from "./settings.js";
import { getReconcileOnHooks } from "./settings.js";
export { CompoundEngineeringDashboardView } from "./dashboard-view.js";
export { COMPOUND_ENGINEERING_SKILLS } from "./skills.js";
export {
installBundledCeSkills,