Elysia Tools

Parcourez outils, exemples, explications visuelles et guides thématiques dans un espace clair.

Catégories populaires

Dossiers

Langue
ZHDERUPTENFRES

Elysia Tools

Navigation mobile

Informatique en périphérie

Exemples Netlify Edge Functions

Exemples complets de Netlify Edge Functions couvrant middleware, authentification, A/B testing, géolocalisation et patterns avancés d'edge computing

Exemples

Entrées de cette collection

Code sourcejavascriptSimple

Middleware Edge de Base

Patterns essentiels de middleware edge pour le traitement des requêtes, modification des réponses et routage de base

Difficulté

3/10

Temps estimé

15 min

Étiquettes

netlify, edge functions, middleware

Prérequis

JavaScript ES6+, HTTP basics, Netlify edge functions

javascript
// Basic Edge Middleware Examples
// File: edge-functions/middleware.js

// 1. Request logging and analytics middleware
const edgeFunction1 = async (request, context) => {
  const start = Date.now()
  const url = new URL(request.url)

  // Log request details
  console.log({
    method: request.method,
    url: url.pathname,
    userAgent: request.headers.get('user-agent'),
    ip: getClientIP(request),
    timestamp: new Date().toISOString()
  })

  // Continue to next middleware or page
  const response = await context.next()

  // Add response headers
  const duration = Date.now() - start
  response.headers.set('x-response-time', `${duration}ms`)
  response.headers.set('x-edge-function', 'middleware')

  return response
}

function getClientIP(request) {
  return request.headers.get('x-nf-client-connection-ip') ||
         request.headers.get('x-forwarded-for') ||
         '0.0.0.0'
}

// 2. CORS middleware
// File: edge-functions/cors.js
const edgeFunction2 = async (request, context) => {
  const response = await context.next()

  // Set CORS headers
  response.headers.set('Access-Control-Allow-Origin', '*')
  response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
  response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With')
  response.headers.set('Access-Control-Max-Age', '86400')

  // Handle preflight requests
  if (request.method === 'OPTIONS') {
    return new Response(null, { status: 200, headers: response.headers })
  }

  return response
}

// 3. Security headers middleware
// File: edge-functions/security.js
const edgeFunction3 = async (request, context) => {
  const response = await context.next()

  // Set security headers
  response.headers.set('X-Frame-Options', 'DENY')
  response.headers.set('X-Content-Type-Options', 'nosniff')
  response.headers.set('X-XSS-Protection', '1; mode=block')
  response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
  response.headers.set('Permissions-Policy', 'camera=(), microphone=(), geolocation=()')

  // Content Security Policy
  const csp = [
    "default-src 'self'",
    "script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net",
    "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
    "font-src 'self' https://fonts.gstatic.com",
    "img-src 'self' data: https:",
    "connect-src 'self' https://api.example.com"
  ].join('; ')

  response.headers.set('Content-Security-Policy', csp)

  return response
}

// 4. Path-based routing middleware
// File: edge-functions/router.js
const edgeFunction4 = async (request, context) => {
  const url = new URL(request.url)
  const pathname = url.pathname

  // API routes
  if (pathname.startsWith('/api/')) {
    return handleAPIRoute(request, pathname)
  }

  // Admin routes
  if (pathname.startsWith('/admin/')) {
    return handleAdminRoute(request, context)
  }

  // Static assets with custom headers
  if (pathname.startsWith('/static/') || pathname.startsWith('/_next/static/')) {
    const response = await context.next()
    response.headers.set('Cache-Control', 'public, max-age=31536000, immutable')
    return response
  }

  // Default handling
  return context.next()
}

async function handleAPIRoute(request, pathname) {
  // Route API requests to different handlers
  if (pathname.includes('/users')) {
    return new Response(JSON.stringify({ users: [] }), {
      headers: { 'Content-Type': 'application/json' }
    })
  }

  if (pathname.includes('/products')) {
    return new Response(JSON.stringify({ products: [] }), {
      headers: { 'Content-Type': 'application/json' }
    })
  }

  return new Response('API endpoint not found', { status: 404 })
}

async function handleAdminRoute(request, context) {
  // Check authentication for admin routes
  const authHeader = request.headers.get('authorization')

  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return new Response('Unauthorized', { status: 401 })
  }

  // Validate token (simplified)
  const token = authHeader.slice(7)
  if (!isValidAdminToken(token)) {
    return new Response('Invalid token', { status: 401 })
  }

  return context.next()
}

function isValidAdminToken(token) {
  // Implement proper token validation
  return token.length > 10
}
Code sourcejavascriptIntermédiaire

Géolocalisation et Localisation

Routage basé sur la géolocalisation, localisation de contenu et fonctionnalité spécifique à la région

Difficulté

6/10

Temps estimé

25 min

Étiquettes

netlify, edge functions, geolocation

Prérequis

JavaScript, Geolocation APIs, Content localization

javascript
// Geolocation and Localization Examples
// File: edge-functions/geolocation.js

const edgeFunction5 = async (request, context) => {
  const url = new URL(request.url)
  const geo = request.geo || {}

  // Extract location data
  const location = {
    country: geo.country?.code?.toLowerCase() || 'unknown',
    countryName: geo.country?.name || 'Unknown',
    city: geo.city || 'Unknown',
    region: geo.subdivision?.name || 'Unknown',
    timezone: geo.timezone || 'UTC',
    latitude: geo.latitude,
    longitude: geo.longitude
  }

  console.log('User location:', location)

  // Skip API routes
  if (url.pathname.startsWith('/api/')) {
    return context.next()
  }

  // Handle localized routes
  if (url.pathname === '/' || url.pathname === '/home') {
    return handleLocalizedHome(request, location, context)
  }

  // Handle product localization
  if (url.pathname.startsWith('/products/')) {
    return handleLocalizedProducts(request, location, context)
  }

  // Add location headers to all responses
  const response = await context.next()
  response.headers.set('x-user-country', location.country)
  response.headers.set('x-user-city', location.city)
  response.headers.set('x-user-timezone', location.timezone)

  return response
}

async function handleLocalizedHome(request, location, context) {
  const url = new URL(request.url)

  // Redirect to localized version based on country
  const localizedPaths = {
    'us': '/us',
    'gb': '/uk',
    'de': '/de',
    'fr': '/fr',
    'es': '/es',
    'it': '/it',
    'jp': '/ja',
    'cn': '/zh',
    'br': '/pt-br'
  }

  const localizedPath = localizedPaths[location.country]

  if (localizedPath && !url.pathname.startsWith(`/${location.country}`)) {
    const localizedUrl = new URL(localizedPath, url)
    return Response.redirect(localizedUrl, 302)
  }

  return context.next()
}

async function handleLocalizedProducts(request, location, context) {
  const url = new URL(request.url)

  // Add region-specific pricing
  const response = await context.next()

  if (response.headers.get('content-type')?.includes('text/html')) {
    const html = await response.text()

    // Inject pricing and availability script
    const pricingScript = generatePricingScript(location)
    const modifiedHtml = html.replace(
      '</head>',
      `${pricingScript}</head>`
    )

    return new Response(modifiedHtml, {
      headers: response.headers
    })
  }

  return response
}

function generatePricingScript(location) {
  const pricing = {
    'us': { currency: 'USD', symbol: '$', rate: 1 },
    'gb': { currency: 'GBP', symbol: '£', rate: 0.79 },
    'de': { currency: 'EUR', symbol: '€', rate: 0.92 },
    'fr': { currency: 'EUR', symbol: '€', rate: 0.92 },
    'es': { currency: 'EUR', symbol: '€', rate: 0.92 },
    'it': { currency: 'EUR', symbol: '€', rate: 0.92 },
    'br': { currency: 'BRL', symbol: 'R$', rate: 5.2 }
  }

  const localPricing = pricing[location.country] || pricing['us']

  return `
    <script>
      window.LOCAL_PRICING = ${JSON.stringify(localPricing)};
      window.USER_LOCATION = ${JSON.stringify(location)};

      // Apply localized pricing
      document.addEventListener('DOMContentLoaded', function() {
        const priceElements = document.querySelectorAll('[data-base-price]');
        priceElements.forEach(el => {
          const basePrice = parseFloat(el.dataset.basePrice);
          const localPrice = (basePrice * window.LOCAL_PRICING.rate).toFixed(2);
          el.textContent = '${localPricing.symbol}' + localPrice;
        });
      });
    </script>
  `
}

// Geolocation-based content filtering
// File: edge-functions/content-filter.js
const edgeFunction6 = async (request, context) => {
  const geo = request.geo || {}
  const country = geo.country?.code?.toLowerCase()

  const response = await context.next()

  // Skip for non-HTML responses
  if (!response.headers.get('content-type')?.includes('text/html')) {
    return response
  }

  const html = await response.text()

  // Apply content restrictions based on location
  let modifiedHtml = html

  // GDPR compliance for EU countries
  const euCountries = ['de', 'fr', 'it', 'es', 'nl', 'be', 'at', 'se', 'dk', 'fi']
  if (euCountries.includes(country)) {
    modifiedHtml = addGDPRBanner(modifiedHtml)
  }

  // Content filtering for specific regions
  if (country === 'cn') {
    modifiedHtml = filterContentForChina(modifiedHtml)
  }

  return new Response(modifiedHtml, {
    headers: response.headers
  })
}

function addGDPRBanner(html) {
  const banner = `
    <div id="gdpr-banner" style="position: fixed; bottom: 0; left: 0; right: 0;
                background: #333; color: white; padding: 1rem; z-index: 9999;
                display: flex; justify-content: space-between; align-items: center;">
      <span>This website uses cookies to ensure you get the best experience on our website.</span>
      <div>
        <button onclick="acceptCookies()" style="margin-right: 10px; padding: 5px 15px;
                background: #4CAF50; color: white; border: none; cursor: pointer;">
          Accept
        </button>
        <button onclick="rejectCookies()" style="padding: 5px 15px;
                background: #f44336; color: white; border: none; cursor: pointer;">
          Reject
        </button>
      </div>
    </div>
    <script>
      function acceptCookies() {
        document.getElementById('gdpr-banner').style.display = 'none';
        localStorage.setItem('gdpr-consent', 'accepted');
      }
      function rejectCookies() {
        document.getElementById('gdpr-banner').style.display = 'none';
        localStorage.setItem('gdpr-consent', 'rejected');
      }
      if (localStorage.getItem('gdpr-consent')) {
        document.getElementById('gdpr-banner').style.display = 'none';
      }
    </script>
  `

  return html.replace('</body>', banner + '</body>')
}

function filterContentForChina(html) {
  // Remove or modify content not available in China
  return html
    .replace(/<iframe[^>]*youtube[^>]*><\/iframe>/gi,
           '<div>Video content not available in your region</div>')
    .replace(/<iframe[^>]*google[^>]*><\/iframe>/gi,
           '<div>Google services not available in your region</div>')
}

// Timezone-aware content
// File: edge-functions/timezone.js
const edgeFunction7 = async (request, context) => {
  const timezone = request.geo?.timezone || 'UTC'
  const url = new URL(request.url)

  const response = await context.next()

  // Skip for non-HTML responses
  if (!response.headers.get('content-type')?.includes('text/html')) {
    return response
  }

  const html = await response.text()

  // Inject timezone information
  const timezoneScript = `
    <script>
      window.USER_TIMEZONE = '${timezone}';
      window.USER_TIME = new Date().toLocaleString('en-US', {
        timeZone: '${timezone}',
        year: 'numeric',
        month: 'long',
        day: 'numeric',
        hour: '2-digit',
        minute: '2-digit'
      });

      // Convert timestamps to user timezone
      function convertToLocalTime(utcTime) {
        return new Date(utcTime).toLocaleString('en-US', {
          timeZone: window.USER_TIMEZONE
        });
      }

      // Update all timestamp elements
      document.addEventListener('DOMContentLoaded', function() {
        const timeElements = document.querySelectorAll('[data-utc-time]');
        timeElements.forEach(el => {
          const utcTime = el.dataset.utcTime;
          el.textContent = convertToLocalTime(utcTime);
        });
      });
    </script>
  `

  const modifiedHtml = html.replace('</head>', timezoneScript + '</head>')

  return new Response(modifiedHtml, {
    headers: response.headers
  })
}
Code sourcejavascriptComplexe

Authentification et Autorisation

Système complet d'authentification avec validation JWT, gestion de session et contrôle d'accès basé sur les rôles

Difficulté

8/10

Temps estimé

35 min

Étiquettes

netlify, edge functions, security, auth

Prérequis

JWT, Authentication concepts, Cookie management, Role-based access control

javascript
// Authentication and Authorization Examples
// File: edge-functions/auth.js

const edgeFunction8 = async (request, context) => {
  const url = new URL(request.url)

  // Public routes that don't require authentication
  const publicRoutes = ['/login', '/signup', '/forgot-password', '/api/auth/login', '/api/auth/register', '/_next/static/']
  const isPublicRoute = publicRoutes.some(route => url.pathname.startsWith(route))

  if (isPublicRoute) {
    return context.next()
  }

  // Check for authentication
  const authResult = await authenticateRequest(request)

  if (!authResult.authenticated) {
    return handleUnauthenticated(request, authResult.reason)
  }

  // Add user context to request
  const response = await context.next()
  response.headers.set('x-user-id', authResult.userId)
  response.headers.set('x-user-role', authResult.role)
  response.headers.set('x-user-email', authResult.email)

  return response
}

async function authenticateRequest(request) {
  const authHeader = request.headers.get('authorization')
  const cookieHeader = request.headers.get('cookie') || ''

  // Try JWT token from Authorization header
  if (authHeader && authHeader.startsWith('Bearer ')) {
    const token = authHeader.slice(7)
    return await validateJWTToken(token)
  }

  // Try JWT token from cookies
  const tokenMatch = cookieHeader.match(/token=([^;]+)/)
  if (tokenMatch) {
    const token = tokenMatch[1]
    return await validateJWTToken(token)
  }

  return { authenticated: false, reason: 'no_token' }
}

async function validateJWTToken(token) {
  try {
    // Split JWT token
    const [, payloadBase64] = token.split('.')
    const payload = JSON.parse(atob(payloadBase64))

    // Check expiration
    if (payload.exp && Date.now() / 1000 > payload.exp) {
      return { authenticated: false, reason: 'token_expired' }
    }

    // In production, verify signature with secret key
    // For demo purposes, we'll just validate structure
    if (!payload.sub || !payload.email) {
      return { authenticated: false, reason: 'invalid_token' }
    }

    return {
      authenticated: true,
      userId: payload.sub,
      email: payload.email,
      role: payload.role || 'user',
      permissions: payload.permissions || []
    }

  } catch (error) {
    console.error('JWT validation error:', error)
    return { authenticated: false, reason: 'invalid_token' }
  }
}

function handleUnauthenticated(request, reason) {
  const url = new URL(request.url)

  // Return 401 for API routes
  if (url.pathname.startsWith('/api/')) {
    return new Response(JSON.stringify({
      error: 'Authentication required',
      reason: reason
    }), {
      status: 401,
      headers: { 'Content-Type': 'application/json' }
    })
  }

  // Redirect to login for web routes
  const loginUrl = new URL('/login', url)
  loginUrl.searchParams.set('redirect', url.pathname + url.search)
  loginUrl.searchParams.set('reason', reason)

  return Response.redirect(loginUrl, 302)
}

// Role-based access control
// File: edge-functions/rbac.js
const edgeFunction9 = async (request, context) => {
  const url = new URL(request.url)

  // Define protected routes and required roles
  const protectedRoutes = {
    '/admin': ['admin'],
    '/admin/users': ['admin'],
    '/admin/settings': ['admin'],
    '/dashboard': ['user', 'admin', 'moderator'],
    '/api/admin': ['admin'],
    '/api/moderator': ['admin', 'moderator'],
    '/profile': ['user', 'admin', 'moderator']
  }

  // Check if route requires specific role
  const requiredRole = getRequiredRole(url.pathname, protectedRoutes)

  if (requiredRole) {
    const authResult = await authenticateRequest(request)

    if (!authResult.authenticated) {
      return handleUnauthenticated(request, 'no_token')
    }

    if (!hasRequiredRole(authResult.role, requiredRole)) {
      return handleUnauthorized(authResult.role, requiredRole)
    }

    // Add user info to headers for downstream processing
    const response = await context.next()
    response.headers.set('x-user-id', authResult.userId)
    response.headers.set('x-user-role', authResult.role)
    response.headers.set('x-user-email', authResult.email)

    return response
  }

  return context.next()
}

function getRequiredRole(pathname, protectedRoutes) {
  for (const [route, roles] of Object.entries(protectedRoutes)) {
    if (pathname.startsWith(route)) {
      return roles
    }
  }
  return null
}

function hasRequiredRole(userRole, requiredRoles) {
  return requiredRoles.includes(userRole)
}

function handleUnauthorized(userRole, requiredRoles) {
  const url = new URL(request.url)

  // Return 403 for API routes
  if (url.pathname.startsWith('/api/')) {
    return new Response(JSON.stringify({
      error: 'Insufficient permissions',
      userRole: userRole,
      requiredRoles: requiredRoles
    }), {
      status: 403,
      headers: { 'Content-Type': 'application/json' }
    })
  }

  // Show unauthorized page for web routes
  return new Response(`
    <!DOCTYPE html>
    <html>
    <head>
      <title>Unauthorized Access</title>
      <style>
        body {
          font-family: Arial, sans-serif;
          display: flex;
          justify-content: center;
          align-items: center;
          height: 100vh;
          margin: 0;
          background: #f5f5f5;
        }
        .container {
          text-align: center;
          background: white;
          padding: 2rem;
          border-radius: 8px;
          box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        h1 { color: #e74c3c; margin-bottom: 1rem; }
        p { color: #666; margin-bottom: 1.5rem; }
        button {
          background: #3498db;
          color: white;
          border: none;
          padding: 0.5rem 1rem;
          border-radius: 4px;
          cursor: pointer;
          text-decoration: none;
          display: inline-block;
        }
      </style>
    </head>
    <body>
      <div class="container">
        <h1>🚫 Unauthorized Access</h1>
        <p>You don't have permission to access this resource.</p>
        <p>Your role: <strong>${userRole}</strong></p>
        <p>Required roles: <strong>${requiredRoles.join(', ')}</strong></p>
        <button onclick="history.back()">Go Back</button>
      </div>
    </body>
    </html>
  `, {
    status: 403,
    headers: { 'Content-Type': 'text/html' }
  })
}

// Session management with refresh tokens
// File: edge-functions/session.js
const edgeFunction10 = async (request, context) => {
  const url = new URL(request.url)

  // Skip for auth routes
  if (url.pathname.startsWith('/api/auth/')) {
    return context.next()
  }

  const cookieHeader = request.headers.get('cookie') || ''
  const accessToken = getCookieValue(cookieHeader, 'access_token')
  const refreshToken = getCookieValue(cookieHeader, 'refresh_token')

  // Check access token
  if (accessToken) {
    const authResult = await validateJWTToken(accessToken)

    if (authResult.authenticated) {
      const response = await context.next()
      addUserHeaders(response, authResult)
      return response
    }

    // Access token expired, try refresh
    if (refreshToken && (await shouldRefreshToken(accessToken))) {
      const refreshResult = await refreshAccessToken(refreshToken)

      if (refreshResult.success) {
        const response = await context.next()
        addAuthCookies(response, refreshResult.tokens)
        addUserHeaders(response, refreshResult.user)
        return response
      }
    }
  }

  // No valid tokens, redirect to login
  if (!url.pathname.startsWith('/login')) {
    const loginUrl = new URL('/login', url)
    return Response.redirect(loginUrl, 302)
  }

  return context.next()
}

function getCookieValue(cookieHeader, name) {
  const match = cookieHeader.match(new RegExp(`(^| )${name}=([^;]+)`))
  return match ? match[2] : null
}

async function shouldRefreshToken(accessToken) {
  try {
    const [, payloadBase64] = accessToken.split('.')
    const payload = JSON.parse(atob(payloadBase64))

    // Refresh if token expires within 5 minutes
    return payload.exp - (Date.now() / 1000) < 300
  } catch {
    return false
  }
}

async function refreshAccessToken(refreshToken) {
  try {
    // In production, call your authentication service
    // For demo, we'll simulate a refresh
    const response = await fetch('https://your-auth-service.com/refresh', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${refreshToken}`
      }
    })

    if (response.ok) {
      const data = await response.json()
      return {
        success: true,
        tokens: data.tokens,
        user: data.user
      }
    }

    return { success: false }
  } catch (error) {
    console.error('Token refresh error:', error)
    return { success: false }
  }
}

function addAuthCookies(response, tokens) {
  const cookieOptions = 'Path=/; HttpOnly; Secure; SameSite=Strict'

  response.headers.append('Set-Cookie', `access_token=${tokens.accessToken}; ${cookieOptions}`)
  response.headers.append('Set-Cookie', `refresh_token=${tokens.refreshToken}; ${cookieOptions}`)
}

function addUserHeaders(response, user) {
  response.headers.set('x-user-id', user.userId)
  response.headers.set('x-user-email', user.email)
  response.headers.set('x-user-role', user.role)
}
Code sourcejavascriptComplexe

Optimisation des Performances

Optimisation avancée des performances avec caching, compression, intégration CDN et optimisation des réponses

Difficulté

9/10

Temps estimé

45 min

Étiquettes

netlify, edge functions, performance, optimization

Prérequis

Performance optimization, Caching strategies, Web vitals, Service workers

javascript
// Performance Optimization Examples
// File: edge-functions/performance.js

const edgeFunction11 = async (request, context) => {
  const url = new URL(request.url)

  // Skip API routes and static assets
  if (url.pathname.startsWith('/api/') || url.pathname.startsWith('/static/')) {
    return context.next()
  }

  const response = await context.next()

  // Optimize based on content type
  const contentType = response.headers.get('content-type') || ''

  if (contentType.includes('text/html')) {
    return optimizeHTMLResponse(request, response)
  } else if (contentType.includes('application/json')) {
    return optimizeJSONResponse(response)
  } else if (contentType.includes('text/css')) {
    return optimizeCSSResponse(response)
  } else if (contentType.includes('application/javascript')) {
    return optimizeJSResponse(response)
  }

  return optimizeResponse(response)
}

async function optimizeHTMLResponse(request, response) {
  const html = await response.text()

  // Critical CSS inlining
  const optimizedHTML = await inlineCriticalCSS(html)

  // Resource hints for performance
  const resourceHints = generateResourceHints()

  // Service worker registration
  const serviceWorkerScript = generateServiceWorkerScript()

  // Performance monitoring script
  const performanceScript = generatePerformanceScript()

  const modifiedHTML = optimizedHTML
    .replace('</head>', resourceHints + serviceWorkerScript + performanceScript + '</head>')
    .replace('</body>', generatePerformanceBanner() + '</body>')

  // Add performance headers
  const performanceHeaders = {
    'Cache-Control': 'public, max-age=3600, must-revalidate',
    'X-Content-Type-Options': 'nosniff',
    'X-DNS-Prefetch-Control': 'on'
  }

  const newResponse = new Response(modifiedHTML, {
    status: response.status,
    statusText: response.statusText,
    headers: { ...Object.fromEntries(response.headers), ...performanceHeaders }
  })

  return newResponse
}

async function inlineCriticalCSS(html) {
  // Extract critical CSS for above-the-fold content
  const criticalCSS = await extractCriticalCSS(html)

  // Find the first CSS link
  const cssLinkMatch = html.match(/<link[^>]*rel=["']stylesheet["'][^>]*>/i)

  if (cssLinkMatch && criticalCSS) {
    // Insert critical CSS inline
    const inlineCSS = `<style data-inline="critical">${criticalCSS}</style>`
    return html.replace(cssLinkMatch[0], inlineCSS + cssLinkMatch[0])
  }

  return html
}

async function extractCriticalCSS(html) {
  // Mock critical CSS extraction
  // In production, use services like Penthouse or CriticalCSS
  return `
    body { font-family: system-ui, -apple-system, sans-serif; line-height: 1.6; }
    h1, h2, h3 { margin-top: 0; }
    img { max-width: 100%; height: auto; }
    .container { max-width: 1200px; margin: 0 auto; padding: 0 20px; }
  `
}

function generateResourceHints() {
  return `
    <!-- DNS prefetch for external resources -->
    <link rel="dns-prefetch" href="//fonts.googleapis.com">
    <link rel="dns-prefetch" href="//fonts.gstatic.com">
    <link rel="dns-prefetch" href="//cdn.jsdelivr.net">
    <link rel="dns-prefetch" href="//api.example.com">

    <!-- Preconnect for critical resources -->
    <link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

    <!-- Preload critical resources -->
    <link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
    <link rel="preload" href="/css/critical.css" as="style">

    <!-- Prefetch likely next pages -->
    <link rel="prefetch" href="/about">
    <link rel="prefetch" href="/contact">
  `
}

function generateServiceWorkerScript() {
  return `
    <script>
      // Service Worker Registration
      if ('serviceWorker' in navigator) {
        window.addEventListener('load', () => {
          navigator.serviceWorker.register('/sw.js')
            .then(registration => {
              console.log('SW registered: ', registration);
            })
            .catch(registrationError => {
              console.log('SW registration failed: ', registrationError);
            });
        });
      }
    </script>
  `
}

function generatePerformanceScript() {
  return `
    <script>
      // Performance Monitoring
      window.addEventListener('load', () => {
        // Core Web Vitals
        if ('PerformanceObserver' in window) {
          const observer = new PerformanceObserver((list) => {
            for (const entry of list.getEntries()) {
              if (entry.entryType === 'largest-contentful-paint') {
                console.log('LCP:', entry.startTime);
                // Send to analytics
                gtag('event', 'LCP', { value: entry.startTime });
              }
              if (entry.entryType === 'first-input') {
                console.log('FID:', entry.processingStart - entry.startTime);
                gtag('event', 'FID', { value: entry.processingStart - entry.startTime });
              }
              if (entry.entryType === 'layout-shift') {
                if (!entry.hadRecentInput) {
                  console.log('CLS:', entry.value);
                  gtag('event', 'CLS', { value: entry.value });
                }
              }
            }
          });

          observer.observe({ entryTypes: ['largest-contentful-paint', 'first-input', 'layout-shift'] });
        }

        // Navigation timing
        const navigation = performance.getEntriesByType('navigation')[0];
        if (navigation) {
          const loadTime = navigation.loadEventEnd - navigation.fetchStart;
          console.log('Page load time:', loadTime);
          gtag('event', 'page_load_time', { value: loadTime });
        }
      });

      // Lazy loading for images
      document.addEventListener('DOMContentLoaded', () => {
        if ('IntersectionObserver' in window) {
          const imageObserver = new IntersectionObserver((entries, observer) => {
            entries.forEach(entry => {
              if (entry.isIntersecting) {
                const img = entry.target;
                img.src = img.dataset.src;
                img.classList.remove('lazy');
                imageObserver.unobserve(img);
              }
            });
          });

          document.querySelectorAll('img[data-src]').forEach(img => {
            imageObserver.observe(img);
          });
        }
      });
    </script>
  `
}

function generatePerformanceBanner() {
  return `
    <div id="performance-banner" style="position: fixed; bottom: 20px; right: 20px;
                background: rgba(0,0,0,0.8); color: white; padding: 10px 15px;
                border-radius: 5px; font-size: 12px; z-index: 9999; display: none;">
      <div>Performance Metrics:</div>
      <div id="perf-metrics"></div>
    </div>
    <script>
      // Show performance metrics in development
      if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
        document.getElementById('performance-banner').style.display = 'block';

        setInterval(() => {
          const metrics = {
            memory: performance.memory ? Math.round(performance.memory.usedJSHeapSize / 1048576) + 'MB' : 'N/A',
            timing: Math.round(performance.now()) + 'ms'
          };
          document.getElementById('perf-metrics').innerHTML =
            'Memory: ' + metrics.memory + ' | Time: ' + metrics.timing;
        }, 1000);
      }
    </script>
  `
}

function optimizeJSONResponse(response) {
  // Compress JSON responses
  const headers = {
    'Content-Type': 'application/json',
    'Cache-Control': 'public, max-age=300, must-revalidate',
    'Vary': 'Accept-Encoding'
  }

  return new Response(response.body, {
    status: response.status,
    headers: { ...Object.fromEntries(response.headers), ...headers }
  })
}

function optimizeCSSResponse(response) {
  // Optimize CSS delivery
  const headers = {
    'Cache-Control': 'public, max-age=31536000, immutable',
    'X-Content-Type-Options': 'nosniff'
  }

  return new Response(response.body, {
    status: response.status,
    headers: { ...Object.fromEntries(response.headers), ...headers }
  })
}

function optimizeJSResponse(response) {
  // Optimize JavaScript delivery
  const headers = {
    'Cache-Control': 'public, max-age=31536000, immutable',
    'X-Content-Type-Options': 'nosniff'
  }

  return new Response(response.body, {
    status: response.status,
    headers: { ...Object.fromEntries(response.headers), ...headers }
  })
}

function optimizeResponse(response) {
  // General optimization for other content types
  const headers = {
    'Cache-Control': 'public, max-age=3600',
    'Vary': 'Accept-Encoding'
  }

  return new Response(response.body, {
    status: response.status,
    headers: { ...Object.fromEntries(response.headers), ...headers }
  })
}

// Advanced caching strategies
// File: edge-functions/caching.js
const edgeFunction12 = async (request, context) => {
  const url = new URL(request.url)
  const cacheKey = generateCacheKey(request)

  // Try to get from cache first
  const cachedResponse = await getFromCache(cacheKey)
  if (cachedResponse && !shouldBypassCache(request)) {
    return cachedResponse
  }

  const response = await context.next()

  // Cache successful responses
  if (response.ok) {
    await setCache(cacheKey, response, getCacheDuration(request))
  }

  // Add cache headers
  const cacheHeaders = generateCacheHeaders(request)
  cacheHeaders.forEach((value, key) => {
    response.headers.set(key, value)
  })

  return response
}

function generateCacheKey(request) {
  const url = new URL(request.url)
  const authHeader = request.headers.get('authorization')
  const cookieHeader = request.headers.get('cookie')

  // Include user-specific data in cache key for personalized content
  const userContext = authHeader || cookieHeader || 'anonymous'

  return `${request.method}:${url.pathname}:${url.search}:${userContext}`
}

function shouldBypassCache(request) {
  const url = new URL(request.url)

  // Bypass cache for specific conditions
  return (
    request.headers.get('cache-control') === 'no-cache' ||
    request.headers.get('pragma') === 'no-cache' ||
    url.searchParams.has('nocache') ||
    url.pathname.startsWith('/api/') && request.method !== 'GET'
  )
}

function getCacheDuration(request) {
  const url = new URL(request.url)

  // Different cache durations for different content
  if (url.pathname.startsWith('/api/')) {
    return 300 // 5 minutes for API
  } else if (url.pathname.startsWith('/static/')) {
    return 31536000 // 1 year for static assets
  } else if (url.pathname.includes('/blog/')) {
    return 3600 // 1 hour for blog posts
  } else {
    return 1800 // 30 minutes for regular pages
  }
}

function generateCacheHeaders(request) {
  const url = new URL(request.url)
  const duration = getCacheDuration(request)

  const headers = new Map()

  if (url.pathname.startsWith('/api/')) {
    headers.set('Cache-Control', `public, max-age=${duration}`)
    headers.set('Vary', 'Authorization, Cookie')
  } else if (url.pathname.startsWith('/static/')) {
    headers.set('Cache-Control', `public, max-age=${duration}, immutable`)
    headers.set('Vary', 'Accept-Encoding')
  } else {
    headers.set('Cache-Control', `public, max-age=${duration}, must-revalidate`)
    headers.set('Vary', 'Accept-Encoding, Cookie')
  }

  return headers
}

// Mock cache functions (replace with real KV storage in production)
async function getFromCache(key) {
  try {
    // In production, use Netlify KV or similar
    // const cached = await KV.get(key)
    // return cached ? new Response(cached) : null

    return null // Mock implementation
  } catch (error) {
    console.error('Cache get error:', error)
    return null
  }
}

async function setCache(key, response, duration) {
  try {
    // In production, use Netlify KV or similar
    // const body = await response.text()
    // await KV.put(key, body, { expirationTtl: duration })

    console.log('Cached:', key, 'for', duration, 'seconds')
  } catch (error) {
    console.error('Cache set error:', error)
  }
}

Outils

Outils souvent utilisés avec cet exemple

Associé

Collections d’exemples associées

Associé

Dossiers associés

Dossier

Déduire un JSON Schema depuis des exemples et des tableurs

Produisez un brouillon de JSON Schema relisible à partir d'exemples JSON représentatifs ou de lignes XLSX, puis examinez types, caractère obligatoire, valeurs nulles et anomalies avant toute adoption contractuelle.

Dossier

Revue et livraison d’un module de jeu promotionnel auto-hébergé

Contrôlez configuration, exemples de réponses, lisibilité et affichage adaptatif avant de livrer les fichiers du module et les preuves de recette de son intégration.

Dossier

Modeles pharmacocinetiques pedagogiques et controle des resultats

Explorer les formules pharmacocinetiques, les hypotheses de modele et la coherence des resultats pour l'enseignement ou la QA, sans avis clinique.

Dossier

Outils de chiffrement classique et moderne

Apprenez à utiliser les chiffrements en contexte éducatif ou CTF en comparant les transformations classiques réversibles au chiffrement moderne et à ses limites.

Accueil
Outils3212
Exemples593
Visualisations471
Visionneuses de fichiers103
Dossiers239
Étiquettes333
Images, audio et vidéo657

Outils de traitement, conversion et optimisation d’images, d’audio et de vidéo

Maths, dates et finance647

Calculateurs, outils numériques, logique de dates, statistiques et finance

Design et couleur298

Outils de couleur, mise en page, graphisme, style visuel et assistance design

Texte et rédaction209

Outils de rédaction, nettoyage, formatage, extraction et analyse de texte

Développement et Web193

Utilitaires développeur, réseau, débogage Web et assistants d’automatisation

Conversion et encodage175

Outils de conversion de formats, fichiers, archives, unités et encodages

Lancement d’un quiz de prospection et transmission des contacts
Textes commémoratifs : validation familiale et remise pour impression
Habitudes privées : sauvegarde, restauration et partage vérifié
D’un article aux brouillons X et LinkedIn : revue factuelle et livraison
Revue de cours Markdown interactif et livraison hors ligne

© 2026 Elysia Tools. Tous droits réservés.

DocumentationTarifsÀ proposConditions d'utilisationPolitique de confidentialitéCookiesContact

Design

Détecteur de Contours d'Image

Applique des algorithmes de détection de contours professionnels (Sobel, Prewitt, Laplacien, Canny) avec options de seuil ajustables et visualisation

Design

Noyau de Détection de Contours d'Image

Applique des noyaux de convolution de détection de contours pour identifier et mettre en évidence les contours

Design

Détection de Contours Prewitt

Applique l'opérateur Prewitt pour la détection de contours, identifiant les limites et gradients dans les images

Design

Détection de Contours Roberts Cross

Applique l'opérateur Roberts Cross pour une détection de contours simple et rapide, particulièrement efficace pour les contours diagonaux

Design

Détection de Contours Sobel

Applique l'opérateur Sobel pour la détection de contours, mettant en évidence les limites et contours dans les images

Format Conversion

Convertisseur de réseaux GraphML / GEXF / liste d’arêtes

Convertit GraphML, GEXF, DOT, matrices d’adjacence et CSV d’arêtes avec métriques réseau

Development

Optimiseur du budget TTL Cache-Control et CDN edge

Analyse les directives Cache-Control, calcule les TTL navigateur/edge, le budget stale, les conflits et les notes CDN statiques.

Math & Numbers

Calculateur de décomposition en fractions partielles (fonctions rationnelles)

Décompose en fractions partielles F(x) = N(x)/D(x) (dénominateur de degré ≤ 6, numérateur ≤ 8 ; les fractions impropres sont d'abord divisées par division polynomiale) : racines du dénominateur par Durand–Kerner regroupées par multiplicité et paires conjuguées, système linéaire exact sur les coefficients donnant les termes A/(x−r)^j et (Bx+C)/((x−α)²+β²), puis vérification numérique du résidu en des points algébriques de test. Classiques : (3x+5)/(x²+3x+2) = 2/(x+1) + 1/(x+2) ; (x³+2x)/(x²+1) = x + x/(x²+1) ; 1/(x(x+1)²) = 1/x − 1/(x+1) − 1/(x+1)².

Médias

Échantillons Audio DTS Libres de Droits

Échantillons DTS avec ambiance naturelle et musique relaxante pour l’écoute et la conversion audio

Médias

Échantillons Audio PCM Brut Libres de Droits

Échantillons PCM s16le bruts avec ambiance naturelle et musique relaxante pour la forme d’onde, l’écoute et la conversion

Validation

Alternatives de Modèles Regex

Plusieurs façons d'écrire le même modèle regex avec différents compromis