Nuxt is a free and open-source framework with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with Vue.js.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Server-side rendering utilities for hydration, request handling, and server-client data synchronization. Nuxt provides comprehensive SSR support with seamless client-side hydration and server-side utilities.
Note: This module uses H3 types for server-side request handling. H3Event and related types are available through Nuxt's server context or can be imported from 'h3'.
Handle client-side hydration of server-rendered content.
/**
* Handle client-side hydration of server state
* @param key - Key for the hydration data
* @param get - Function to get server value
* @param set - Function to set client value
*/
function useHydration<K, T>(key: K, get: () => T, set: (value: T) => void): void;
/**
* Run callback before hydration on specific element
* @param callback - Callback function receiving element
*/
function onPrehydrate(callback: (el: HTMLElement) => void): void;Usage Examples:
// Basic hydration
const serverTime = ref(new Date());
const clientTime = ref(new Date());
useHydration("time-sync",
() => serverTime.value,
(value) => { clientTime.value = value; }
);
// DOM element hydration
onPrehydrate((el) => {
// Initialize client-side only features
el.addEventListener("click", handleClick);
// Apply client-side styles
el.classList.add("hydrated");
});
// State hydration with validation
const serverData = ref<UserData | null>(null);
const clientData = ref<UserData | null>(null);
useHydration("user-data",
() => serverData.value,
(value) => {
// Validate before setting
if (value && isValidUserData(value)) {
clientData.value = value;
}
}
);
// Complex hydration example
const serverCart = useState<CartItem[]>("server-cart", () => []);
const clientCart = useState<CartItem[]>("client-cart", () => []);
useHydration("shopping-cart",
() => serverCart.value,
(items) => {
// Merge server cart with local storage
const localCart = JSON.parse(localStorage.getItem("cart") || "[]");
clientCart.value = [...items, ...localCart];
}
);Access server-side request information and modify responses.
/**
* Access request headers (server-side only)
* @param include - Optional array of headers to include
* @returns Headers object
*/
function useRequestHeaders(include?: string[]): Record<string, string>;
/**
* Get the current H3 request event (server-side only)
* @returns H3Event object with request/response utilities
*/
function useRequestEvent(): H3Event;
/**
* Get server-side fetch function with request context
* @returns Fetch function configured with current request context
*/
function useRequestFetch(): $Fetch;
/**
* Set response status code and message (server-side only)
* @param code - HTTP status code
* @param message - Optional status message
*/
function setResponseStatus(code: number, message?: string): void;
/**
* Get/set response header (server-side only)
* @param name - Header name
* @returns Header value reference
*/
function useResponseHeader(name: string): { value?: string };Usage Examples:
// Access request headers
const headers = useRequestHeaders();
console.log("User-Agent:", headers["user-agent"]);
// Get specific headers
const authHeaders = useRequestHeaders(["authorization", "x-api-key"]);
// Get request event
const event = useRequestEvent();
console.log("Request method:", event.node.req.method);
console.log("Request URL:", event.node.req.url);
// Server-side fetch with context
const requestFetch = useRequestFetch();
const data = await requestFetch("/api/internal/data");
// Set response status
setResponseStatus(201, "Created");
// Set response headers
const cacheHeader = useResponseHeader("cache-control");
cacheHeader.value = "public, max-age=3600";
// Authentication example
const authHeader = useRequestHeaders(["authorization"]);
const token = authHeader.authorization?.replace("Bearer ", "");
if (!token) {
setResponseStatus(401, "Unauthorized");
throw createError({
statusCode: 401,
statusMessage: "Missing authentication token"
});
}
// CORS handling
const corsHeader = useResponseHeader("access-control-allow-origin");
corsHeader.value = "*";
// API rate limiting
const rateLimitHeader = useResponseHeader("x-ratelimit-remaining");
rateLimitHeader.value = "99";Configure routes for static generation and prerendering.
/**
* Add routes for prerendering during build
* @param routes - Route or array of routes to prerender
*/
function prerenderRoutes(routes: string | string[]): void;Usage Examples:
// Add single route
prerenderRoutes("/sitemap.xml");
// Add multiple routes
prerenderRoutes([
"/about",
"/contact",
"/privacy-policy"
]);
// Dynamic route prerendering
const { data: products } = await useFetch("/api/products");
const productRoutes = products.value?.map(p => `/products/${p.slug}`) || [];
prerenderRoutes(productRoutes);
// Conditional prerendering
if (process.env.PRERENDER_BLOG === "true") {
const { data: posts } = await useFetch("/api/posts");
const postRoutes = posts.value?.map(p => `/blog/${p.slug}`) || [];
prerenderRoutes(postRoutes);
}Advanced patterns for server-side data fetching and caching.
// Server-only data fetching
const { data: serverSecrets } = await useAsyncData("secrets", async () => {
// This only runs on server
return {
apiKey: process.env.API_KEY,
dbUrl: process.env.DATABASE_URL
};
}, {
server: true,
client: false
});
// Request-specific caching
const event = useRequestEvent();
const userId = getCookie(event, "user-id");
const { data: userData } = await useAsyncData(`user-${userId}`, () =>
$fetch(`/api/users/${userId}`)
);
// Server-side authentication
const event = useRequestEvent();
const token = getCookie(event, "auth-token");
if (!token) {
setResponseStatus(401);
throw createError({
statusCode: 401,
statusMessage: "Authentication required"
});
}
// Validate token server-side
try {
const user = await verifyToken(token);
event.context.user = user;
} catch (error) {
setResponseStatus(401);
throw createError({
statusCode: 401,
statusMessage: "Invalid token"
});
}// Access request context
const event = useRequestEvent();
// Set context data
event.context.startTime = Date.now();
event.context.requestId = generateId();
// Logging middleware
export default defineEventHandler(async (event) => {
const start = Date.now();
// Add request ID
event.context.requestId = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
// Set response header
setHeader(event, "x-request-id", event.context.requestId);
// Continue with request
const response = await next(event);
// Log completion
const duration = Date.now() - start;
console.log(`[${event.context.requestId}] ${event.node.req.method} ${event.node.req.url} - ${duration}ms`);
return response;
});
// Authentication middleware
export default defineEventHandler(async (event) => {
// Skip auth for public routes
if (event.node.req.url?.startsWith("/api/public/")) {
return;
}
const token = getCookie(event, "auth-token") || getHeader(event, "authorization")?.replace("Bearer ", "");
if (!token) {
setResponseStatus(event, 401);
return { error: "Authentication required" };
}
try {
const user = await validateToken(token);
event.context.user = user;
} catch (error) {
setResponseStatus(event, 401);
return { error: "Invalid token" };
}
});// Conditional SSR
const { $device } = useNuxtApp();
// Disable SSR for mobile devices
if (process.server && $device.isMobile) {
// Redirect to SPA version
await navigateTo("/spa" + useRoute().fullPath);
}
// Server-side environment detection
const isServer = process.server;
const isClient = process.client;
const isDev = process.dev;
// Server-only operations
if (process.server) {
// Database connections, file system access, etc.
const dbConnection = await connectToDatabase();
// Server-side analytics
await trackServerSideEvent({
event: "page_view",
url: event.node.req.url,
userAgent: getHeader(event, "user-agent")
});
}
// Client-only operations
if (process.client) {
// Browser APIs, DOM manipulation, etc.
const analytics = await import("~/plugins/analytics.client");
analytics.track("page_view");
}// Server-side error handling
try {
const data = await fetchServerData();
} catch (error) {
if (process.server) {
// Log server errors
console.error("Server error:", error);
// Set appropriate status
setResponseStatus(500);
}
throw createError({
statusCode: 500,
statusMessage: "Internal server error",
data: process.dev ? error.stack : undefined
});
}
// Hydration error handling
try {
useHydration("sensitive-data",
() => serverData.value,
(value) => { clientData.value = value; }
);
} catch (error) {
// Handle hydration mismatch
console.warn("Hydration mismatch:", error);
// Fallback to client-side data
clientData.value = await fetchClientData();
}
// Request timeout handling
const event = useRequestEvent();
const timeout = setTimeout(() => {
setResponseStatus(408);
throw createError({
statusCode: 408,
statusMessage: "Request timeout"
});
}, 30000); // 30 second timeout
try {
const result = await longRunningOperation();
clearTimeout(timeout);
return result;
} catch (error) {
clearTimeout(timeout);
throw error;
}// Progressive hydration
const shouldHydrate = ref(false);
onMounted(() => {
// Delay hydration until critical resources load
requestIdleCallback(() => {
shouldHydrate.value = true;
});
});
// Selective hydration based on user interaction
const hasInteracted = ref(false);
useHydration("interactive-component",
() => serverComponent.value,
(value) => {
if (hasInteracted.value) {
clientComponent.value = value;
}
}
);
// Server-side caching
const cacheKey = `page:${route.path}:${JSON.stringify(route.query)}`;
const cachedData = await redis.get(cacheKey);
if (cachedData) {
return JSON.parse(cachedData);
} else {
const data = await fetchFreshData();
await redis.setex(cacheKey, 300, JSON.stringify(data)); // Cache for 5 minutes
return data;
}
// Server-side A/B testing
const event = useRequestEvent();
const variant = getCookie(event, "ab-test-variant") ||
(Math.random() > 0.5 ? "A" : "B");
setCookie(event, "ab-test-variant", variant, {
maxAge: 60 * 60 * 24 * 30 // 30 days
});
const pageConfig = variant === "A" ? configA : configB;interface H3Event {
node: {
req: IncomingMessage;
res: ServerResponse;
};
context: Record<string, any>;
headers: Record<string, string>;
method: string;
path: string;
body?: any;
}
interface $Fetch {
<T = any>(request: string, opts?: FetchOptions): Promise<T>;
create(defaults: FetchOptions): $Fetch;
}
interface FetchOptions {
method?: string;
headers?: Record<string, string>;
body?: any;
query?: Record<string, any>;
timeout?: number;
retry?: number;
onRequest?: (context: { request: string; options: FetchOptions }) => void;
onResponse?: (context: { request: string; response: Response }) => void;
onRequestError?: (context: { request: string; error: Error }) => void;
onResponseError?: (context: { request: string; response: Response }) => void;
}
interface UserData {
id: number;
name: string;
email: string;
preferences: Record<string, any>;
}
interface CartItem {
id: number;
name: string;
price: number;
quantity: number;
}Advanced server-side utilities for request context, configuration, and rendering optimization.
/**
* Get the full request URL (server-side only)
* @returns URL object representing the request URL
*/
function useRequestURL(): URL;
/**
* Access app configuration (reactive)
* @returns Reactive app configuration object
*/
function useAppConfig<T = AppConfig>(): T;
/**
* Update app configuration reactively
* @param config - Configuration updates to merge
*/
function updateAppConfig<T = AppConfig>(config: Partial<T>): void;
/**
* Check if in preview mode
* @returns Object with enabled state and preview data
*/
function usePreviewMode(): { enabled: boolean };
/**
* Prerender additional routes (server-side only)
* @param routes - Routes to prerender
*/
function prerenderRoutes(routes: string | string[]): void;Usage Examples:
// Get request URL server-side
const requestURL = useRequestURL();
console.log('Full URL:', requestURL.href);
console.log('Origin:', requestURL.origin);
// Access app configuration
const appConfig = useAppConfig();
console.log('App theme:', appConfig.theme);
// Update app config reactively
updateAppConfig({
theme: 'dark',
apiUrl: 'https://api.example.com'
});
// Check preview mode
const { enabled } = usePreviewMode();
if (enabled) {
console.log('Running in preview mode');
}
// Prerender additional routes
prerenderRoutes(['/sitemap.xml', '/robots.txt']);interface AppConfig {
[key: string]: any;
}Install with Tessl CLI
npx tessl i tessl/npm-nuxt