Plugins Overview
Introduction to the DeesseJS Plugin System
Plugins Overview
The DeesseJS Plugin System allows you to extend the functionality of your CMS with custom features, integrations, and enhancements. Plugins can add new admin pages, extend collections, integrate with external services, and modify dashboard behavior.
What are Plugins?
Plugins are reusable packages that extend DeesseJS functionality. They can:
- Add new admin dashboard pages
- Extend collections with additional fields
- Integrate third-party services
- Create custom API endpoints
- Modify admin UI behavior
- Add new content types
- Implement custom workflows
Plugin Types
1. Admin Plugins
Extend the admin dashboard interface:
- Custom pages and routes
- Dashboard widgets
- Custom field types
- UI components
- Navigation items
2. Collection Plugins
Extend content management:
- Custom field types
- Collection hooks
- Validation rules
- Default values
- Computed fields
3. Integration Plugins
Connect with external services:
- Authentication providers
- Payment gateways
- Email services
- Analytics platforms
- CDNs and storage
4. API Plugins
Extend API capabilities:
- Custom endpoints
- Middleware
- Authentication strategies
- Rate limiting
- Caching strategies
Installing Plugins
Using the CLI
npx deessejs plugin add <plugin-name>Using npm/yarn
# npm
npm install @deessejs/plugin-<name>
# yarn
yarn add @deessejs/plugin-<name>
# pnpm
pnpm add @deessejs/plugin-<name>Registering Plugins
// deesse.config.ts
import { defineConfig } from '@deessejs/core'
import { myPlugin } from '@deessejs/plugin-example'
export const config = defineConfig({
plugins: [
myPlugin({
// Plugin options
option1: 'value',
option2: true,
}),
],
})Plugin Dependencies on Extensions
Plugins can declare dependencies on extensions to access common infrastructure features. This allows plugins to use standardized interfaces for caching, logging, queues, and more.
Declaring Extension Dependencies
export const cachePlugin = definePlugin({
name: 'cache-plugin',
extensions: {
// Require cache extension
cache: true,
// Optional logger extension
logger: false,
},
activate(options, { extensions }) {
// Extensions are available here
const { cache, logger } = extensions
return {
hooks: {
afterCreate: async ({ item }) => {
// Use cache extension
await cache.set(`item:${item.id}`, item, 3600)
// Use logger extension if available
if (logger) {
logger.info('Item cached', { id: item.id })
}
},
},
}
},
})Required vs Optional Extensions
export const advancedPlugin = definePlugin({
name: 'advanced-plugin',
extensions: {
// Required extensions - plugin won't load without them
cache: true, // Required
logger: true, // Required
queue: true, // Required
// Optional extensions - plugin can work without them
search: false, // Optional
events: false, // Optional
},
activate(options, { extensions }) {
const { cache, logger, queue } = extensions
const { search, events } = extensions
return {
hooks: {
afterCreate: async ({ item }) => {
// These are guaranteed to be available
await cache.set(`item:${item.id}`, item)
logger.info('Created', { id: item.id })
await queue.add('process', { itemId: item.id })
// Check availability before using optional extensions
if (search) {
await search.index('items').addDocuments([item])
}
if (events) {
await events.publish('item.created', item)
}
},
},
}
},
})Checking Extension Availability
export const flexiblePlugin = definePlugin({
name: 'flexible-plugin',
extensions: {
cache: false, // Optional
logger: false, // Optional
},
activate(options, { extensions }) {
return {
hooks: {
afterCreate: async ({ item }) => {
// Gracefully handle missing extensions
if (extensions.cache) {
await extensions.cache.set(`item:${item.id}`, item, 3600)
} else {
console.warn('Cache not available, skipping')
}
if (extensions.logger) {
extensions.logger.info('Item created', { id: item.id })
}
},
},
}
},
})Common Extension Usage Patterns
Cache Extension
export const seoPlugin = definePlugin({
name: 'seo-plugin',
extensions: {
cache: true,
},
activate(options, { extensions }) {
const { cache } = extensions
return {
api: {
routes: [
{
method: 'GET',
path: '/api/seo/score',
handler: async (req) => {
const url = new URL(req.url).searchParams.get('url')
// Try cache first
const cached = await cache.get(`seo:${url}`)
if (cached) {
return Response.json(cached)
}
// Calculate score
const score = await calculateSEOScore(url)
// Cache result
await cache.set(`seo:${url}`, score, 3600)
return Response.json(score)
},
},
],
},
}
},
})Queue Extension
export const newsletterPlugin = definePlugin({
name: 'newsletter-plugin',
extensions: {
queue: true,
},
activate(options, { extensions }) {
const { queue } = extensions
// Register queue worker
queue.process('send-newsletter', async (job) => {
const { email, subject, content } = job.data
await sendEmail(email, subject, content)
})
return {
hooks: {
afterCreate: async ({ collection, item }) => {
if (collection === 'posts') {
// Add job to queue
await queue.add('send-newsletter', {
email: 'subscribers@example.com',
subject: `New Post: ${item.title}`,
content: item.excerpt,
})
}
},
},
}
},
})Logger Extension
export const auditPlugin = definePlugin({
name: 'audit-plugin',
extensions: {
logger: true,
},
activate(options, { extensions }) {
const { logger } = extensions
return {
hooks: {
beforeCreate: async ({ collection, data }) => {
logger.info('Creating item', { collection, data: sanitize(data) })
},
afterCreate: async ({ collection, item }) => {
logger.info('Item created', { collection, id: item.id })
},
beforeUpdate: async ({ collection, id, data }) => {
logger.info('Updating item', { collection, id, data: sanitize(data) })
},
afterDelete: async ({ collection, id }) => {
logger.info('Item deleted', { collection, id })
},
},
}
},
})Storage Extension
export const mediaPlugin = definePlugin({
name: 'media-plugin',
extensions: {
storage: true,
},
activate(options, { extensions }) {
const { storage } = extensions
return {
hooks: {
afterCreate: async ({ collection, item }) => {
if (collection === 'media' && item.file) {
// Upload to storage
const url = await storage.upload(`media/${item.id}`, item.file)
// Update with URL
await db.media.update({
where: { id: item.id },
data: { url },
})
}
},
},
}
},
})Multiple Extension Providers
Plugins can work with any provider implementation:
// This plugin works with any cache provider (Redis, Memory, etc.)
export const cachingPlugin = definePlugin({
name: 'caching-plugin',
extensions: {
cache: true,
},
activate(options, { extensions }) {
// The plugin doesn't care which provider is used
// It could be Redis, Memcached, or in-memory
const { cache } = extensions
return {
// ... implementation
}
},
})
// Configuration with Redis
export const config = defineConfig({
extensions: {
cache: {
provider: new RedisCacheProvider(redisClient),
},
},
plugins: [cachingPlugin()],
})Extension Version Compatibility
Plugins can specify minimum extension versions:
export const myPlugin = definePlugin({
name: 'my-plugin',
extensions: {
cache: {
version: '^2.0.0', // Require cache extension v2 or higher
},
},
activate(options, { extensions }) {
const { cache } = extensions
// Cache is guaranteed to have v2+ features
return {
// ... implementation
}
},
})Official Plugins
Content Plugins
- @deessejs/plugin-blog: Complete blog with posts, categories, and tags
- @deessejs/plugin-changelog: Version history and release notes management
- @deessejs/plugin-seo: Advanced SEO for technical articles and tutorials
- @deessejs/plugin-richtext: Advanced rich text editor
- @deessejs/plugin-media: Enhanced media management
- @deessejs/plugin-sitemap: Automatic sitemap generation
- @deessejs/plugin-rss: RSS feed generation
Management Plugins
- @deessejs/plugin-students: Student and course management
- @deessejs/plugin-affiliates: Affiliate and partnership management
Integration Plugins
- @deessejs/plugin-auth-nextauth: NextAuth.js integration
- @deessejs/plugin-storage-s3: AWS S3 storage
- @deessejs/plugin-storage-cloudinary: Cloudinary integration
- @deessejs/plugin-webhook: Webhook notifications
Analytics & Monitoring
- @deessejs/plugin-analytics: Analytics tracking and reporting
Utility Plugins
- @deessejs/plugin-i18n: Multi-language support
- @deessejs/plugin-scheduler: Scheduled tasks
- @deessejs/plugin-cache: Advanced caching
- @deessejs/plugin-logger: Enhanced logging
- @deessejs/plugin-backup: Database backups
Creating Your Own Plugin
Basic Plugin Structure
// my-plugin/index.ts
import { definePlugin } from '@deessejs/core'
export const myPlugin = definePlugin({
name: 'my-plugin',
version: '1.0.0',
activate(options) {
// Plugin initialization logic
console.log('Plugin activated with options:', options)
return {
// Extend collections
collections: {
extend: {
posts: {
fields: [
{
name: 'customField',
type: 'string',
},
],
},
},
},
// Add admin pages
admin: {
pages: [
{
id: 'my-page',
title: 'My Page',
path: '/my-page',
component: './pages/MyPage',
},
],
},
// Add API routes
api: {
routes: [
{
path: '/api/my-endpoint',
handler: './handlers/myEndpoint',
},
],
},
}
},
})Plugin Package Structure
my-plugin/
├── index.ts # Main plugin file
├── client/ # Client-side code
│ ├── components/
│ └── hooks/
├── server/ # Server-side code
│ ├── routes/
│ └── middleware/
├── admin/ # Admin components
│ ├── pages/
│ └── widgets/
├── types.ts # TypeScript types
└── package.jsonPlugin Configuration
Plugin Options
export const config = defineConfig({
plugins: [
myPlugin({
enabled: true,
apiKey: process.env.API_KEY,
// Plugin-specific options
}),
],
})Conditional Plugin Activation
export const config = defineConfig({
plugins: [
...(process.env.FEATURE_FLAG === 'enabled'
? [myPlugin()]
: []
),
],
})Plugin Hooks
Plugins can hook into various DeesseJS events:
Collection Hooks
export const myPlugin = definePlugin({
activate(options) {
return {
hooks: {
beforeCreate: async ({ collection, data }) => {
console.log('Creating item in', collection)
return data
},
afterCreate: async ({ collection, item }) => {
console.log('Created item', item)
},
beforeUpdate: async ({ collection, id, data }) => {
return data
},
afterUpdate: async ({ collection, id, item }) => {
// Trigger webhook, clear cache, etc.
},
beforeDelete: async ({ collection, id }) => {
// Check permissions, etc.
},
afterDelete: async ({ collection, id }) => {
// Cleanup related resources
},
},
}
},
})Server Hooks
export const myPlugin = definePlugin({
activate(options) {
return {
hooks: {
serverInit: async ({ app, config }) => {
// Runs when server starts
},
request: async ({ req, res }) => {
// Runs on each request
},
},
}
},
})Plugin Discovery
Finding Plugins
- Official Plugins: Browse the
@deessejsorg on npm - Community Plugins: Search npm for
deessejs-plugin - GitHub: Search GitHub for
deessejs-plugin
Evaluating Plugins
Before installing a plugin, check:
- Maintenance: Last update date
- Downloads: Popularity and adoption
- License: Compatibility with your project
- Documentation: Quality of docs
- Issues: Open issues and PRs
Plugin Best Practices
Development
- Follow TypeScript best practices
- Provide comprehensive documentation
- Include example configurations
- Write tests for your plugin
- Use semantic versioning
Performance
- Minimize bundle size
- Lazy load components when possible
- Cache expensive operations
- Avoid blocking the main thread
Security
- Validate all inputs
- Sanitize user data
- Use secure defaults
- Document security considerations
- Keep dependencies updated
Compatibility
- Support multiple Next.js versions
- Test across different environments
- Provide migration guides for breaking changes
- Maintain backward compatibility when possible
Next Steps
- Learn how to Create Plugins
- Explore Plugin API Reference
- View Plugin Examples