A powerful Vite plugin that automatically decorates SvelteKit functions with customizable wrappers for logging, analytics, error handling, and more.
Experience the plugin in action with a live, interactive demo. No installation required!
SvelteKit lacks a built-in way to execute common code across multiple functions (load functions, actions, API routes). This plugin solves that by providing a decorator pattern that allows you to:
Install the plugin
npm install vite-plugin-sveltekit-decorators
Add to your Vite configuration
// vite.config.js
import { sveltekit } from '@sveltejs/kit/vite';
import { svelteKitDecorators } from 'vite-plugin-sveltekit-decorators';
export default {
plugins: [
sveltekit(),
svelteKitDecorators({
enabled: true,
debug: false
})
]
};
Create your decorator functions
// src/+decorators.server.ts
import type {
ServerLoadDecorator,
ActionsDecorator,
ApiDecorator
} from 'vite-plugin-sveltekit-decorators';
export const loadDecorator: ServerLoadDecorator = (originalFunction, metadata) => {
return async (event) => {
console.log(`Loading ${metadata.functionName}...`);
const result = await originalFunction(event);
console.log(`Loaded ${metadata.functionName} successfully`);
return result;
};
};
export const actionsDecorator: ActionsDecorator = (originalFunction, metadata) => {
return async (event) => {
console.log(`Executing action ${metadata.action}...`);
return await originalFunction(event);
};
};
export const apiDecorator: ApiDecorator = (originalFunction, metadata) => {
return async (event) => {
console.log(`API ${metadata.method} request to ${metadata.functionName}`);
return await originalFunction(event);
};
};
That's it! Your existing SvelteKit code will automatically be decorated without any modifications.
Check out our complete working example which demonstrates all features including:
Decorator | Purpose | File Location | Applies To |
---|---|---|---|
loadDecorator |
Client-side load functions | src/+decorators.ts |
Page/layout load functions |
loadDecorator |
Server-side load functions | src/+decorators.server.ts |
Page/layout load functions on server |
actionsDecorator |
Form actions | src/+decorators.server.ts |
Page actions (default, named) |
apiDecorator |
API route handlers | src/+decorators.server.ts |
API routes (GET , POST , etc.) |
Option | Type | Default | Description |
---|---|---|---|
enabled |
boolean | 'dev' | 'build' |
true |
Enable/disable the plugin |
debug |
boolean |
false |
Enable debug logging |
serverWrapperFile |
string |
'./src/+decorators.server.ts' |
Path to server decorators file |
clientWrapperFile |
string |
'./src/+decorators.ts' |
Path to client decorators file |
You can configure decorators per page using the decorators
configuration, following SvelteKit's convention:
// +page.server.ts - Just like other SvelteKit config exports!
export const config = {
decorators: {
load: true, // Enable load decoration
actions: ['create'], // Only decorate 'create' action
api: false // Disable API decoration
}
};
export const load = async () => { /* automatically decorated */ };
export const actions = {
create: async () => { /* decorated */ },
update: async () => { /* decorated */ },
delete: async () => { /* NOT decorated */ }
};
Configuration options:
true
: Enable for all functionsfalse
: Disable completely string[]
: Enable only for specific actions/HTTP methodsThis follows the exact same pattern as SvelteKit's built-in configuration - no new concepts to learn!
This plugin is fully type-safe and provides:
The plugin works by transforming your code at build time. You don't need to:
Your existing code remains untouched and clean.
This plugin follows SvelteKit's established patterns for a familiar developer experience:
+
file conventions (+decorators.ts
, +decorators.server.ts
)export const config
, just like SvelteKit's own patterns// Debugging works exactly as you'd expect
export const loadDecorator: ServerLoadDecorator = (originalFunction, metadata) => {
return async (event) => {
debugger; // ā
Works perfectly!
console.log(`Loading ${metadata.functionName}...`);
const result = await originalFunction(event);
return result;
};
};
This plugin has zero performance impact on your application because:
ā ļø Performance depends on your decorator implementation - avoid heavy computations or blocking operations in your decorators.
Each decorator receives metadata about the function:
interface BaseDecoratorMetadata {
functionName: string; // Name of the original function
isAsync: boolean; // Whether the function is async
}
// Server decorators also include:
interface ServerDecoratorMetadata extends BaseDecoratorMetadata {
filePath: string; // File path (server-side only)
startLine: number; // Line number where function starts
endLine: number; // Line number where function ends
}
// Action decorators include:
interface ActionsDecoratorMetadata extends ServerDecoratorMetadata {
functionType: 'actions';
action: string; // Action name ('default' for default action)
}
// API decorators include:
interface ApiDecoratorMetadata extends ServerDecoratorMetadata {
functionType: 'api';
method: string; // HTTP method (GET, POST, etc.)
}
export const loadDecorator: ServerLoadDecorator = (originalFunction, metadata) => {
return async (event) => {
// Only log in development
if (import.meta.env.DEV) {
console.log(`Loading ${metadata.functionName}...`);
}
const start = Date.now();
const result = await originalFunction(event);
// Performance monitoring
const duration = Date.now() - start;
if (duration > 1000) {
console.warn(`Slow load function: ${metadata.functionName} (${duration}ms)`);
}
return result;
};
};
export const apiDecorator: ApiDecorator = (originalFunction, metadata) => {
return async (event) => {
try {
return await originalFunction(event);
} catch (error) {
console.error(`API error in ${metadata.functionName}:`, error);
return new Response(
JSON.stringify({ error: 'Internal server error' }),
{
status: 500,
headers: { 'Content-Type': 'application/json' }
}
);
}
};
};
MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit issues and pull requests.