Plugin System
v5.2.0+Extend your Dinou application, register custom Express middlewares or endpoints, and propagate context variables without ejecting.
Dinou's lightweight plugin architecture provides a modular way to plug in third-party integrations (like Clerk, Stripe, or custom i18n routing) while preserving the ability to update the underlying framework engine.
🔌 Overview
Before this feature, adding middlewares or customizing the React Server Components context required running npm run eject to directly modify the core Express server.js file.
With the new plugin system, you can package Express routing, global request interceptors, and context propagation logic in standard, isolated plugin objects declared inside dinou.config.js.
⚙️ Configuration File
To register plugins, create a dinou.config.js file at the root of your project using CommonJS (module.exports). The server dynamically loads this configuration file during startup:
// dinou.config.js
module.exports = {
plugins: [
// Register your plugins here
]
};⚓ Plugin Hooks
A plugin is a standard JavaScript object containing a name and one or more lifecycle hooks:
1. onServerInit(app)
Triggers immediately after the Express app and cookie-parser are initialized, but before other default body-parsers or routing handlers.
Use this hook to mount standard Express middlewares, register custom REST endpoints, or handle raw Webhooks (such as Stripe or Clerk) before they hit the main page routing engine.
const customLoggingPlugin = {
name: "request-logger",
onServerInit(app) {
app.use((req, res, next) => {
console.log(`[${req.method}] ${req.path}`);
next();
});
}
};2. onRequestContext(req, res, context)
Triggers whenever Dinou creates the execution context for React Server Components. This hook executes across three distinct environments:
- Standard Page Routing: during dynamic request-time rendering in the main Express process.
- Server Actions: during execution of Server Functions (Actions).
- SSR Child Process: inside the child process spawned by Dinou to render the React tree to HTML (handling both static path pre-compilation during server startup and initial HTML loads/reloads).
Modify the context.req object to expose custom variables (like session details or localized language dictionaries) to your page layouts and server functions.
const customContextPlugin = {
name: "custom-context-inject",
onRequestContext(req, res, context) {
// Expose a custom variable in RSC context
context.req.customVal = "hello-from-plugin";
}
};Consuming Context in Your Application
Once a custom property is injected into the context via a plugin, it becomes accessible in any server-side file (including Server Components, getProps inside page_functions.ts, or Server Functions) by calling getContext():
// src/actions.ts (Server Functions)
"use server";
import { getContext } from "dinou";
export async function myServerAction() {
const context = getContext();
const customVal = context?.req?.customVal; // Returns "hello-from-plugin"
if (customVal === "hello-from-plugin") {
// Perform localized or session-specific logic...
}
}🛡️ Try-Catch & Fault Isolation
Dinou provides built-in try-catch wrappers around all plugin hook calls. This ensures high robustness and keeps your production site alive:
name field. During startup, Dinou logs each active plugin name. If a hook crashes, Dinou logs a diagnostic error referencing the specific plugin name.