- Architecture: Federated P## ๐ Getting Started
The project uses a dual-server architecture for optimal development experience:
- Plugin Server (Port 3006): Serves the federated plugin with hot-reload
- Dev Environment (Port 3005): Loads and showcases the plugin dynamically
# Install dependencies
pnpm install
# Start both servers simultaneously (recommended)
pnpm dev:full
# Or start individually:
# Terminal 1: Plugin server with hot-reload
pnpm dev:plugin
# Terminal 2: Dev environment
pnpm dev
Development URLs:
- Dev Environment: http://localhost:3005 (main development interface)
- Plugin Server: http://localhost:3006 (federated plugin with hot-reload)
- Plugin URL: http://localhost:3006/plugin.js (federation endpoint)
- โ Instant Updates: Changes to plugin code hot-reload automatically
- โ Federation Testing: Real federated module loading during development
- โ Component Isolation: Test plugin components independently
- โ Environment Separation: Clear separation between dev tools and plugin logicironment Separation
- Last Updated: January 2025
- Maturity: Active Development
The Link Plugin enables users to share and organize links within TopLocs spheres. It features a modern decoupled architecture with separate development and plugin environments, using Module Federa### Core Plugin Registration
src/config.ts
: Plugin configuration using the SDK's fluent APIsrc/gun.ts
: Gun.js instance configurationsrc/plugin/index.ts
: Main plugin entry point using SDK directly
dev/composables/usePluginDev.ts
: Development composable using SDK directlydev/App.vue
: Development interface with plugin preview and registration controls
- Direct SDK Usage: No wrapper services or composables, uses SDK directly
- Simplified Structure: Removed redundant types and wrapper servicesamic loading and configurable plugin registration.
The plugin URL is computed based on the environment:
// Development: http://localhost:3005/assets/plugin.js
// Production: configurable via VITE_PLUGIN_URL environment variable
Configure the plugin URL using environment variables:
# Development (default)
VITE_DEV=true VITE_PORT=3005 VITE_HOST=localhost
# Custom development port
VITE_DEV=true VITE_PORT=3005 VITE_HOST=localhost
# Production deployment
VITE_PLUGIN_URL=https://your-domain.com/plugins/link-plugin/plugin.js
The dev environment (/dev
) provides:
- Registration Status Display: Shows current plugin registration info
- Auto-Registration: Automatically registers the plugin if not found
- Plugin Discovery: Lists all registered plugins for debugging
- Manual Controls: Buttons to refresh or re-register the plugin
- Component Testing: Live preview of federated components
# Quick start (recommended) - Uses startup script
./dev-start.sh
# Standard development environment only
pnpm dev
# Production build
pnpm build
# Start plugin server (after build)
pnpm run dev:serve
# Run both dev environment and plugin server
pnpm run dev:full
link-plugin/
โโโ dev/ # ๐ง Development Environment
โ โโโ index.html # Dev HTML entry point
โ โโโ main.ts # Dev bootstrap (no plugin logic)
โ โโโ App.vue # Dev showcase with federation loading
โโโ src/ # ๐งฉ Plugin Source Code
โ โโโ plugin/ # Federation entry points
โ โ โโโ index.ts # Plugin registration
โ โ โโโ Sidebar.ts # Sidebar component export
โ โ โโโ Settings.ts # Settings component export
โ โโโ views/ # Plugin components
โ โโโ main.ts # Plugin standalone entry
โ โโโ ... # Core plugin code
โโโ vite.config.ts # Federation configuration
- Frontend: Vue 3, TypeScript, Tailwind CSS
- P2P Data: Gun.js (distributed graph database)
- Federation: Module Federation for dynamic plugin loading
- Build: Vite with federation plugin
- Package Manager: pnpm
Start the development environment that loads the plugin dynamically:
# Install dependencies
pnpm install
# Start development with federation
pnpm dev
This starts the Vite dev server on http://localhost:3005
with:
- Development showcase environment using PluginComponent
- Plugin registration monitoring and controls
- Component federation testing via the plugin server
- Live plugin status information
Two-Server Development Setup:
- Dev Environment:
http://localhost:3005
- Serves the development interface - Plugin Server:
http://localhost:3006/assets/plugin.js
- Serves the built federated plugin
The development environment uses PluginComponent
to dynamically load the federated plugin from the plugin server, simulating how it would work in production.
-
Start Hot-Reload Development:
pnpm dev:full
This starts both the plugin server (3006) and dev environment (3005)
-
Edit Plugin Code:
- Modify files in
src/
- Changes hot-reload automatically in the plugin server
- Dev environment updates via federation
- Modify files in
-
Monitor Plugin Registration:
- Open
http://localhost:3005
in your browser - Check the "Plugin Registration Information" section
- View current registration status and URL
- See all registered plugins in the system
- Open
-
Plugin Status Indicators:
- โ Registered: Plugin is properly registered and available
โ ๏ธ Not Found: Plugin needs registration (auto-triggered)- โ Error: Registration failed (manual retry available)
-
Manual Controls:
- Refresh Info: Reload registration status
- Re-register Plugin: Force re-registration
- Register Plugin Now: Initial registration if not found
-
Component Testing:
- Test federated components in the showcase area
- Verify plugin loading from registration URL
- Debug component interactions with hot-reload
Work directly with the plugin components:
# Build the plugin for federation
pnpm build
# Preview the built plugin
pnpm preview
The built plugin exposes federated modules that can be consumed by other applications.
The plugin exposes these federated modules:
// vite.config.ts federation setup
exposes: {
'./Sidebar': './src/plugin/Sidebar.ts', // Link navigation sidebar
'./Settings': './src/plugin/Settings.ts', // Plugin settings dialog
'./Plugin': './src/plugin/index.ts', // Plugin registration
}
The dev environment loads plugins dynamically:
// dev/App.vue - Federation loading with fallback
try {
// Try to load as federated modules
const sidebarModule = await import('link-plugin/Sidebar');
const settingsModule = await import('link-plugin/Settings');
SidebarComponent.value = sidebarModule.default;
SettingsComponent.value = settingsModule.default;
} catch (error) {
// Fallback to local components for development
const { default: SidebarView } = await import('../src/views/SidebarView.vue');
const { default: SettingsView } = await import('../src/views/SettingsView.vue');
SidebarComponent.value = SidebarView;
SettingsComponent.value = SettingsView;
}
- File:
src/plugin/index.ts
- Purpose: Main plugin registration and federation exports
- Build: Configured in
vite.config.ts
โbuild.lib.entry
- Federation: Exposes components via
./Plugin
,./Sidebar
,./Settings
- File:
dev/main.ts
- Purpose: Development environment for testing and debugging
- HTML:
dev/index.html
- Server: Configured in
vite.config.ts
โroot: './dev'
(dev mode)
# Start development environment
pnpm dev
# Edit plugin components in src/
# Changes auto-reload in dev environment
# Test federation loading
# Check browser console for federation status
# Build plugin for integration
pnpm build
# Test in host application
# Plugin available at http://localhost:3005/assets/plugin.js
# Build plugin for production
pnpm build
# Plugin assets output to dist/
# Deploy dist/ to CDN or static hosting
dist/
โโโ assets/
โ โโโ plugin.js # Federation entry point
โ โโโ Sidebar-[hash].js # Sidebar component
โ โโโ Settings-[hash].js # Settings component
โ โโโ ... # Other assets
โโโ index.html # Plugin standalone page
# Build for production
pnpm build
# Upload dist/ to CDN
# Update plugin URL in host application
# Build for production
pnpm build
# Deploy to static hosting (Netlify, Vercel, etc.)
# Use dist/ as deployment directory
// Host application loads plugin
const pluginUrl = 'https://your-cdn.com/link-plugin/assets/plugin.js';
// Dynamic import
const linkPlugin = await import(pluginUrl);
// Links stored in Gun.js distributed graph
gun.get('links').get(sphereId).get(linkId)
// Link categories
gun.get('links').get(sphereId).get('categories')
// User link collections
gun.user().get('links').get(collectionId)
// Real-time link updates
gun.get('links').get(sphereId).on(data => {
// Update link list
})
// src/plugin/index.ts - Automatic registration
const registerPlugin = () => {
const chain = gun.get('link_plugin');
chain.once(data => {
if (!data) {
const node = chain.put({
id: 'link_plugin',
name: 'Link',
url: 'http://localhost:3005/assets/plugin.js',
});
const slots = gun.get('link_plugin/slots');
slots.set({ slot: 'InfoView', component: 'Sidebar' });
slots.set({ slot: 'Settings', component: 'Settings' });
node.get('slots').put(slots);
gun.get('plugins').set(node);
}
});
};
- Development environment (
dev/
) is purely for showcasing and testing - Plugin code (
src/
) contains only business logic and components - No mixing of dev tooling with plugin functionality
- Dynamic loading of plugin components
- Shared dependencies (Vue, TailwindCSS) for optimal bundle size
- Runtime integration with host applications
- Rapid iteration with hot reload in dev environment
- Isolated testing of plugin components
- Multiple deployment targets (standalone, federated, embedded)
- Optimized builds with proper code splitting
- CDN-friendly static assets
- Version management through federation
// Check browser console for federation errors
// Verify plugin URL is accessible
// Check CORS configuration for cross-origin loading
# Clear pnpm cache
pnpm store prune
# Remove node_modules and reinstall
rm -rf node_modules
pnpm install
# Check port conflicts (default: 3005)
# Type check
pnpm type-check
# Lint code
pnpm lint
# Clean build
rm -rf dist && pnpm build
- Client-side link preview generation
- Distributed link metadata cache
- IPFS integration for preview images
- Offline-first link management
- Plugin hot-swapping in host applications
- Version compatibility checks
- Automatic plugin updates
- Plugin dependency management
# Clone repository
git clone <repository-url>
cd link-plugin
# Install dependencies
pnpm install
# Start development
pnpm dev
- Keep dev and plugin code separate - don't mix development tooling with plugin logic
- Test federation loading - ensure components load properly as federated modules
- Follow TypeScript patterns - maintain type safety throughout
- Update documentation - keep README and comments current
- Enhanced link preview generation
- Better categorization and tagging
- Improved collaborative features
- Performance optimizations
- Mobile-responsive design improvements
MIT License - See the main TopLocs project for details.
src/composables/usePluginRegistration.ts
: Production-ready plugin registration functionalitysrc/services/PluginManager.ts
: Core registration service handling Gun.js interactionssrc/config/plugin.ts
: Environment-aware configuration and URL computation
dev/composables/usePluginDev.ts
: Development-specific debugging and management featuresdev/App.vue
: Development interface with plugin preview and registration controls
- Production composable (
usePluginRegistration
): Lightweight, essential registration functions only - Development composable (
usePluginDev
): Full debugging features, reactive state, UI integration
src/config.ts
: Plugin configuration using SDK's fluent APIsrc/gun.ts
: Gun.js instance for decentralized storagesrc/plugin/index.ts
: Main plugin entry point
src/plugin-sdk/
: Complete SDK for plugin developmenttypes.ts
- Core type definitionsBasePluginManager.ts
- Abstract plugin managerGunPluginManager.ts
- Gun.js implementationenvironment.ts
- Environment utilitiescomposables.ts
- Vue composablesutils.ts
- Development utilities
dev/composables/usePluginDev.ts
: Dev composable using SDKdev/App.vue
: Development interface
- โ Removed: Custom types (use SDK types)
- โ Removed: Wrapper services (use SDK directly)
- โ Removed: Wrapper composables (use SDK directly)
- โ Direct SDK Usage: Cleaner, less boilerplate
- โ Reusable SDK: Can be extracted for other plugins
This project includes a complete TopLocs Plugin SDK that can be reused across multiple plugins:
src/plugin-sdk/types.ts
: Core plugin type definitionssrc/plugin-sdk/BasePluginManager.ts
: Abstract plugin manager base classsrc/plugin-sdk/GunPluginManager.ts
: Gun.js implementationsrc/plugin-sdk/environment.ts
: Environment detection utilitiessrc/plugin-sdk/composables.ts
: Vue composables for plugin developmentsrc/plugin-sdk/utils.ts
: Plugin development utilitiessrc/plugin-sdk/index.ts
: Main SDK exports
- โ Standardized Types: Common interfaces across all plugins
- โ Reusable Managers: Abstract base class with concrete implementations
- โ Environment Helpers: URL generation and validation utilities
- โ Vue Integration: Ready-to-use composables for registration
- โ Development Tools: Debugging and validation utilities
- โ Configuration Builder: Fluent API for plugin setup
import {
createPluginConfig,
GunPluginManager,
usePluginRegistration
} from './plugin-sdk';
// Create plugin configuration
const config = createPluginConfig()
.setId('my_plugin')
.setName('My Plugin')
.addSlot('Settings', 'MyComponent')
.build();
// Create manager and register
const manager = new GunPluginManager(gun, config);
const { ensureRegistration } = usePluginRegistration(manager);
See src/plugin-sdk/README.md
for complete SDK documentation.