fix(dashboard): Filter dashboard extensions to plugins active in runtime config#4732
Conversation
The dashboard's Vite plugin discovery walks the import graph from `vendure-config.ts` and additionally expands `package.json` dependencies of every imported package. Dashboard extensions, translations and Tailwind sources were therefore bundled for plugins that were only statically reachable but not actually present in the runtime `VendureConfig.plugins` array (e.g. when plugins are conditionally included based on options, env vars or feature flags, or come in via wrapper/meta-packages). Add a shared `filterActivePluginInfo` helper that intersects the statically discovered `PluginInfo[]` with the plugin classes in `vendureConfig.plugins`, and apply it in all four consumers: `vite-plugin-dashboard-metadata`, `vite-plugin-translations`, `vite-plugin-tailwind-source`, `vite-plugin-lingui-babel`. Fixes vendurehq#4706
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR implements runtime plugin filtering to ensure only explicitly configured plugins contribute bundled resources. A new Possibly related issues
Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Hey @grolmus — the fix looks solid (filter is applied consistently, tests are thorough, the class-name-matching trade-off is well documented). One thing worth thinking about before/after merge: the current shape of Not blocking — just worth either documenting or guarding against. Cases I can think of: Silent false-negatives (plugin active at runtime, extension stripped from bundle)
Silent false-positives (rare)
Environmental
Suggestion (one-liner, non-blocking)The cheapest mitigation for cases 1–4 is a single warning log next to the silent drop: const name = pluginClass?.name;
if (name) {
names.add(name);
} else {
// Don't have access to Vite's logger here, but even a console.warn
// converts \"silent broken UI\" into \"check the build log\".
console.warn(
'[dashboard] Could not derive a class name for a plugins[] entry; ' +
'its dashboard extension (if any) will not be bundled. ' +
'Ensure plugin entries are named classes or DynamicModules with a named .module.'
);
}Or even better, plumb a Vite logger through Either way, none of this blocks the merge — it's a real improvement over the status quo. Mostly flagging it so the failure modes are documented somewhere durable if you don't want to add the warning right now. Cheers! |
Summary
The dashboard's Vite plugin discovery walks the import graph from
vendure-config.tsand additionally expandspackage.jsondependenciesof every imported package. Any plugin reachable through these channels has its dashboard extension bundled and registered in the dashboard runtime — even when the plugin is not present in the actualpluginsarray passed tobootstrap().This breaks any pattern where plugins are conditionally added to the runtime
pluginsarray (env-driven, feature-flagged, wrapper/meta-package orchestrators, multi-tenant setups with a shared bundle). The dashboard ends up loading nav items, routes and page blocks for plugins whose server-side resolvers, GraphQL types and services are absent at runtime — causing broken nav items and extension code that crashes on load.Solution
Add a shared
filterActivePluginInfo(pluginInfo, vendureConfig)helper inpackages/dashboard/vite/utils/get-active-plugin-info.tsthat intersects the statically discoveredPluginInfo[]againstVendureConfig.plugins[]. Apply it before every consumer that emits dashboard artefacts:vite-plugin-dashboard-metadata.tsrunDashboardExtensions()virtual modulevite-plugin-translations.ts(load + generateBundle).pocatalogsvite-plugin-tailwind-source.ts@sourcedirectives for Tailwind v4 scanningvite-plugin-lingui-babel.tsThe helper handles both forms a
VendureConfig.plugins[]entry can take:@VendurePlugin(including the return value ofSomePlugin.init(opts), which by convention returns the class itself)DynamicModuleof shape{ module: SomePluginClass, ... }Matching is done by class name because the runtime config and static discovery load plugin modules through different import paths and therefore see distinct class objects. The discovery step already keys on
name, so this filter introduces no new ambiguity — the limitation is documented in the helper's doc comment together with a note about how to upgrade to(pluginPath, name)matching if needed.The discovery log in
vite-plugin-config-loader.tsis intentionally left untouched — it still reports what discovery found, which is the right thing for users debugging why their plugin is or isn't picked up.Fixes #4706
Test plan
filterActivePluginInfoinpackages/dashboard/vite/tests/plugin-hooks.spec.ts— 5 new tests covering: class-name match, emptypluginsarray, missingpluginskey, NestJSDynamicModuleunwrap, ignoring entries without resolvable class name.dashboardMetadataPluginanddashboardTailwindSourcePlugindescribe blocks, asserting that only the active plugin's extension path appears in the generatedrunDashboardExtensions()and@source '...'lines respectively. The existing tests in those blocks were preserved unchanged by updating the fake config loader factory to auto-build a matchingVendureConfig.pluginsarray from the suppliedpluginInfo.packages/dashboard/vite/tests/meta-package.spec.ts— exercises the realcompile()pipeline against the existing meta-package fixture (MetaPlugin.init()returns[ChildPluginA, ChildPluginB], while transitivepackage.jsondependency expansion also discoversChildPluginC). Asserts that discovery still finds all 3 (no regression) butfilterActivePluginInfodropsChildPluginC— i.e. the exact bug scenario from Dashboard discovers and bundles extensions for plugins not present in runtime config #4706 is now caught.npm testfrompackages/dashboard— 357 tests pass (53 in plugin-hooks.spec.ts, 3 in meta-package.spec.ts).npm run check-types— clean.npm run build:vite— clean.lint-stagedon the changed files) — clean.Notes for reviewers
Need help on this PR? Tag
@codesmithwith what you need.