CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-nuxt

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.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

ssr.mddocs/

SSR & Hydration

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'.

Capabilities

Client-Side Hydration

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];
  }
);

Server-Side Request Handling

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";

Prerendering

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);
}

Server-Side Data Fetching

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"
  });
}

Request Context & Middleware

// 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" };
  }
});

SSR Configuration Patterns

// 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");
}

Error Handling in SSR

// 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;
}

Advanced SSR Patterns

// 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;

Types

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;
}

Additional Server Context APIs

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']);

Additional Types

interface AppConfig {
  [key: string]: any;
}

Install with Tessl CLI

npx tessl i tessl/npm-nuxt

docs

app-lifecycle.md

configuration.md

core.md

data-fetching.md

head.md

index.md

module-dev.md

navigation.md

performance.md

ssr.md

state.md

tile.json