feat: add a portal plugin template, guidance and documentation #525
feat: add a portal plugin template, guidance and documentation #525
Conversation
…mework works, and how to create plugins
|
WalkthroughAdds comprehensive plugin guidelines and a complete portal-plugin template: docs, package config, build tooling, TypeScript APIs, utilities, a refine-config capability, a feature class, routes, UI pages, hooks, widget registration scaffolding, and Vite/tsdown/Tailwind/PostCSS configs. Changes
Sequence Diagram(s)sequenceDiagram
participant Framework
participant PluginModule
participant Capability as RefineConfigCapability
participant Feature
participant Router
Note over Framework,PluginModule: Plugin load & registration (dev/runtime)
Framework->>PluginModule: import plugin entry (exposed module)
PluginModule->>Framework: return Plugin { id, capabilities, features, routes, widgets }
Framework->>Capability: initialize(framework)
Framework->>Feature: initialize(framework)
Framework->>Router: register routes (from Plugin.routes)
Note right of Framework: On framework config merge
Framework->>Capability: getConfig(existingConfig)
Capability-->>Framework: mergedRefineConfig
Note over Framework,Router: UI routing uses registered routes -> Dashboard/Settings components loaded as needed
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (6)
🚧 Files skipped from review as they are similar to previous changes (4)
🔇 Additional comments (2)
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 |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (12)
libs/portal-plugin-template/src/ui/hooks/useTemplate.ts (1)
28-30: Consider wrappinginitializeinuseCallbackto satisfy React hooks dependencies.The
useEffectcallsinitializebut doesn't include it in the dependency array. While this works for the template's simple use case, it violates React's exhaustive-deps rule and could cause issues if the hook is extended.Apply this diff to fix the issue:
+import { useState, useEffect, useCallback } from "react"; -import { useState, useEffect } from "react"; import type { TemplateState, TemplateConfig } from "@/types"; export function useTemplate() { const [state, setState] = useState<TemplateState>({ isLoading: false, }); const [config, setConfig] = useState<TemplateConfig>({ enabled: true, }); // Add your hook logic here - const initialize = async () => { + const initialize = useCallback(async () => { setState(prev => ({ ...prev, isLoading: true })); try { // Initialize plugin logic setState(prev => ({ ...prev, isLoading: false })); } catch (error) { setState(prev => ({ ...prev, isLoading: false, error: error instanceof Error ? error.message : "Unknown error", })); } - }; + }, []); useEffect(() => { initialize(); - }, []); + }, [initialize]);Alternatively, if you prefer to keep the template simpler, add an ESLint disable comment:
useEffect(() => { initialize(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []);libs/portal-plugin-template/README.md (1)
1-455: Excellent comprehensive documentation! Consider minor markdown polish.This README provides thorough guidance for plugin developers, covering all essential topics from quick start to troubleshooting. The structure is logical and the examples are clear and practical.
For enhanced markdown compliance, consider these minor improvements:
- Line 70: Specify language for the code fence:
-``` +```plaintext lume-web/
- Line 258: Format the bare URL:
-- **URL**: http://localhost:6006 +- **URL**: <http://localhost:6006>These are purely cosmetic improvements and don't affect the documentation's value or usability.
README.md (1)
1-438: Excellent documentation expansion! The architecture overview significantly improves discoverability.The expanded README transforms this from a basic project overview into a comprehensive guide covering architecture patterns, plugin system details, development workflows, and best practices. This will greatly help new developers understand the monorepo structure and the Module Federation architecture.
For markdown compliance, consider these minor improvements:
- Line 70: Add language specifier to the code fence:
-``` +```plaintext lume-web/
- Line 258: Format the bare URL:
-- **URL**: http://localhost:6006 +- **URL**: <http://localhost:6006>These are cosmetic improvements that don't impact the documentation's effectiveness.
libs/portal-plugin-template/src/index.ts (2)
15-17: Replace console.log with framework logging.Since this is a template, consider demonstrating proper logging practices by using the framework's logging mechanism instead of
console.log, or add a comment indicating that users should replace this with their logging solution.Example:
async destroy(_framework: Framework) { - console.log("Plugin Template destroyed"); + // TODO: Replace with your logging solution + // framework.logger?.info("Plugin Template destroyed"); },
20-22: Replace console.log with framework logging.Same issue as the
destroymethod - consider demonstrating proper logging practices.libs/portal-plugin-template/src/ui/routes/dashboard.tsx (1)
52-54: Avoid hardcoding the plugin ID.The plugin ID
"core:template"is hardcoded here but also defined insrc/index.tsusingcreateNamespacedId("core", "template"). When developers copy this template and change the plugin ID, they may forget to update this display value, leading to inconsistency.Consider one of these approaches:
- Import the plugin ID from a shared constant
- Access it from framework context if available
- Add a clear TODO comment indicating this should be updated
Example approach with shared constant:
// In src/constants.ts export const PLUGIN_NAMESPACE = "core"; export const PLUGIN_NAME = "template"; // In src/index.ts import { PLUGIN_NAMESPACE, PLUGIN_NAME } from "./constants"; // ... id: createNamespacedId(PLUGIN_NAMESPACE, PLUGIN_NAME), // In src/ui/routes/dashboard.tsx import { PLUGIN_NAMESPACE, PLUGIN_NAME } from "../../constants"; // ... Plugin ID: {PLUGIN_NAMESPACE}:{PLUGIN_NAME}libs/portal-plugin-template/src/features/template/Feature.ts (1)
10-18: Consider using framework logging instead of console.log.The console.log statements are acceptable for a template, but production plugins should use the framework's logging facilities if available for better observability and log level control.
If the framework provides a logger, consider:
async initialize(framework: Framework): Promise<void> { // Initialize the template feature framework.logger?.info("Template feature initialized"); } async destroy(framework: Framework): Promise<void> { // Cleanup the template feature framework.logger?.info("Template feature destroyed"); }PLUGIN_GUIDELINES.md (2)
30-60: Add language identifier to fenced code block.The directory structure code block should specify a language for proper syntax highlighting and markdown compliance.
Apply this diff:
-``` +```text libs/portal-plugin-{name}/ ├── package.json # Plugin metadata and dependenciesAs per static analysis.
298-314: Add language identifier to fenced code block.The UI components structure code block should specify a language for proper syntax highlighting and markdown compliance.
Apply this diff:
-``` +```text src/ui/ ├── components/ # Reusable componentsAs per static analysis.
libs/portal-plugin-template/src/ui/util/templateHelpers.ts (1)
8-18: Consider consolidating utilities and adding string error handling.Two observations:
These utilities duplicate
src-lib/util/templateHelpers.tswith less robust implementations. Consider re-exporting from src-lib for consistency.
getTemplateErrorMessagedoesn't handle string errors (line 17 only handles Error instances). The src-lib version includes:if (typeof error === "string") { return error; }If consolidation isn't desired, apply this diff to add string handling:
export function getTemplateErrorMessage(error: unknown): string { if (error instanceof Error) { return error.message; } + if (typeof error === "string") { + return error; + } return "An unknown error occurred"; }libs/portal-plugin-template/src-lib/util/templateHelpers.ts (2)
42-56: Duplicate function with different implementations.The
formatTemplateDatafunction is implemented in both this file andsrc/ui/util/templateHelpers.ts:
- This version (lines 42-56): robust implementation with null checks, type checks, and error handling
- UI version: simple
JSON.stringify(data, null, 2)This implementation is more comprehensive and should likely be the canonical version.
Consolidate to a single implementation:
- If this version is the preferred implementation, remove or update the UI version to import from here
- Add a comment in the UI file redirecting to this implementation
- Ensure all consumers use the same version to maintain consistent behavior
61-71: Duplicate function across util modules.The
getTemplateErrorMessagefunction has identical implementations in bothsrc-lib/util/templateHelpers.tsandsrc/ui/util/templateHelpers.ts.Since the implementations are identical, extract this to a single shared location and import it where needed. This reduces maintenance burden and ensures consistency.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (27)
PLUGIN_GUIDELINES.md(1 hunks)README.md(1 hunks)libs/portal-plugin-template/README.md(1 hunks)libs/portal-plugin-template/package.json(1 hunks)libs/portal-plugin-template/plugin.config.ts(1 hunks)libs/portal-plugin-template/postcss.config.cjs(1 hunks)libs/portal-plugin-template/src-lib/index.ts(1 hunks)libs/portal-plugin-template/src-lib/types/index.ts(1 hunks)libs/portal-plugin-template/src-lib/types/template.ts(1 hunks)libs/portal-plugin-template/src-lib/util/index.ts(1 hunks)libs/portal-plugin-template/src-lib/util/templateHelpers.ts(1 hunks)libs/portal-plugin-template/src/capabilities/refineConfig.ts(1 hunks)libs/portal-plugin-template/src/features/template/Feature.ts(1 hunks)libs/portal-plugin-template/src/features/template/index.ts(1 hunks)libs/portal-plugin-template/src/index.ts(1 hunks)libs/portal-plugin-template/src/routes.tsx(1 hunks)libs/portal-plugin-template/src/types.ts(1 hunks)libs/portal-plugin-template/src/ui/components/index.ts(1 hunks)libs/portal-plugin-template/src/ui/hooks/useTemplate.ts(1 hunks)libs/portal-plugin-template/src/ui/routes/dashboard.tsx(1 hunks)libs/portal-plugin-template/src/ui/routes/settings.tsx(1 hunks)libs/portal-plugin-template/src/ui/util/templateHelpers.ts(1 hunks)libs/portal-plugin-template/src/widgetRegistrations.ts(1 hunks)libs/portal-plugin-template/tailwind.config.ts(1 hunks)libs/portal-plugin-template/tsconfig.json(1 hunks)libs/portal-plugin-template/tsdown.config.ts(1 hunks)libs/portal-plugin-template/vite.config.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
libs/portal-plugin-template/src/ui/hooks/useTemplate.ts (2)
libs/portal-plugin-template/src-lib/types/template.ts (2)
TemplateState(29-44)TemplateConfig(4-24)libs/portal-plugin-template/src/types.ts (2)
TemplateState(11-15)TemplateConfig(3-9)
libs/portal-plugin-template/src/routes.tsx (1)
libs/portal-plugin-template/src/ui/routes/settings.tsx (1)
Settings(3-39)
libs/portal-plugin-template/src/ui/util/templateHelpers.ts (1)
libs/portal-plugin-template/src-lib/util/templateHelpers.ts (3)
formatTemplateData(42-56)validateTemplateConfig(6-24)getTemplateErrorMessage(61-71)
libs/portal-plugin-template/src/types.ts (1)
libs/portal-plugin-template/src-lib/types/template.ts (2)
TemplateConfig(4-24)TemplateState(29-44)
libs/portal-plugin-template/src/capabilities/refineConfig.ts (1)
libs/portal-framework-core/src/util/refineConfig.ts (1)
mergeRefineConfig(32-59)
libs/portal-plugin-template/src-lib/types/template.ts (1)
libs/portal-plugin-template/src/types.ts (2)
TemplateConfig(3-9)TemplateState(11-15)
libs/portal-plugin-template/src-lib/util/templateHelpers.ts (2)
libs/portal-plugin-template/src/ui/util/templateHelpers.ts (3)
validateTemplateConfig(8-11)formatTemplateData(3-6)getTemplateErrorMessage(13-18)libs/portal-plugin-template/src-lib/types/template.ts (2)
TemplateConfig(4-24)TemplateState(29-44)
libs/portal-plugin-template/src/index.ts (1)
libs/portal-plugin-template/src-lib/types/template.ts (1)
TemplateFeature(74-99)
🪛 Biome (2.1.2)
libs/portal-plugin-template/postcss.config.cjs
[error] 1-6: Illegal use of an export declaration outside of a module
not allowed inside scripts
(parse)
🪛 LanguageTool
libs/portal-plugin-template/README.md
[grammar] ~354-~354: Use a hyphen to join words.
Context: ...s gracefully - Use the framework's error handling patterns ## Integration with A...
(QB_NEW_EN_HYPHEN)
[grammar] ~430-~430: Ensure spelling is correct
Context: ...s. Use unique route paths. ### Missing Exposes All route components must be properly ex...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
README.md
[uncategorized] ~359-~359: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...loading**: Load components and features on demand 2. Code splitting: Split large feat...
(EN_COMPOUND_ADJECTIVE_INTERNAL)
🪛 markdownlint-cli2 (0.18.1)
libs/portal-plugin-template/README.md
70-70: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
258-258: Bare URL used
(MD034, no-bare-urls)
PLUGIN_GUIDELINES.md
30-30: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
298-298: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
README.md
70-70: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
258-258: Bare URL used
(MD034, no-bare-urls)
🔇 Additional comments (18)
libs/portal-plugin-template/tailwind.config.ts (1)
1-9: LGTM! Clean Tailwind configuration for the plugin template.The configuration is minimal and appropriate for a template, with correct content paths that will process all relevant source files. The type-safe
satisfies Configassertion ensures configuration validity.libs/portal-plugin-template/src/ui/components/index.ts (1)
1-3: LGTM! Appropriate placeholder for component exports.This placeholder file provides clear guidance for template users on how to export reusable components, which aligns with the template's educational purpose.
libs/portal-plugin-template/src/ui/routes/settings.tsx (1)
1-39: LGTM! Well-structured settings page template.The component follows the framework's UI patterns, uses appropriate Card components, and provides clear placeholder guidance for plugin developers. The structure mirrors the dashboard route component, maintaining consistency across the template.
libs/portal-plugin-template/src-lib/types/index.ts (1)
1-2: LGTM! Clean barrel export for library types.This follows the standard pattern for aggregating and re-exporting types, providing a clean public API surface for the plugin template's library interface.
libs/portal-plugin-template/src-lib/index.ts (1)
1-2: LGTM!Clean barrel export pattern for the public library API surface.
libs/portal-plugin-template/tsconfig.json (1)
1-11: LGTM!Path aliases are properly configured and align with the plugin template structure.
libs/portal-plugin-template/src/features/template/index.ts (1)
1-1: LGTM!Standard barrel export pattern for the feature module.
libs/portal-plugin-template/src-lib/util/index.ts (1)
1-2: LGTM!Clear barrel export with helpful comment documenting the module's purpose.
libs/portal-plugin-template/src/index.ts (1)
12-26: LGTM!The plugin structure is well-organized with all required Plugin properties properly defined. The use of
satisfies Pluginprovides helpful type checking.libs/portal-plugin-template/package.json (2)
6-7: Verify "main" and "types" paths align with build output.The
mainfield points tolib-dist/index.jswhile theexportsfield useslib-dist/esm/index.js. Ensure this is intentional for legacy fallback and that your build process (tsdown) generates files at both locations.
1-39: LGTM!Package configuration properly supports dual ESM/CJS exports and includes all necessary dependencies for the plugin template.
libs/portal-plugin-template/src/routes.tsx (2)
17-17: Verify component reference matches plugin.config.ts exposes.Same concern as the dashboard route - ensure
"settings"matches an exposed module name inplugin.config.ts.
4-25: LGTM!Route definitions are well-structured with appropriate navigation metadata and use type-safe
satisfiesassertion.libs/portal-plugin-template/src/ui/routes/dashboard.tsx (1)
3-60: LGTM!The dashboard component provides a clear, well-structured template starting point with helpful placeholder content and proper use of the framework's UI components.
libs/portal-plugin-template/src/widgetRegistrations.ts (1)
1-15: LGTM! Clean widget registration template.The placeholder array with commented example provides clear guidance for developers to add widget registrations.
libs/portal-plugin-template/vite.config.ts (1)
1-14: LGTM! Standard Vite configuration.The configuration correctly uses the framework's Config helper and properly references the plugin configuration. Port 4177 is assigned for development.
libs/portal-plugin-template/plugin.config.ts (1)
1-16: LGTM! Well-structured plugin configuration.The configuration properly handles ESM
__dirnamederivation and defines appropriate module exposes for the plugin entry point and routes.libs/portal-plugin-template/src/features/template/Feature.ts (1)
20-26: LGTM! Appropriate placeholder for template.The empty configuration object with comment provides clear guidance for developers to add feature-specific configuration.
…lib directory exports and improve data formatting - Updated postcss config to use module.exports syntax - Enhanced formatTemplateData utility to handle circular references and BigInt values safely - Refactored routes to use relative component paths - Consolidated type definitions and utility functions by re-exporting from lib directory
… to use "esm" instead of "es"
Summary by CodeRabbit
New Features
Documentation
Packaging & Tooling