Edge computing brings computation and data storage closer to the location where it’s needed, improving response times and reducing bandwidth usage. Here’s how to leverage edge computing in your React applications:
Core Edge Patterns for React
1. Edge-Side Rendering (ESR) with Cloudflare Workers
// worker.js - Cloudflare Worker for edge rendering
import { renderToString } from 'react-dom/server';
import App from './src/App';
import htmlTemplate from './template';
async function handleRequest(request) {
const url = new URL(request.url);
const response = await fetch(`https://your-origin.com${url.pathname}`);
if (response.headers.get('Content-Type')?.includes('text/html')) {
const body = await response.text();
const renderedApp = renderToString(<App />);
const edgeRendered = body.replace(
'<div id="root"></div>',
`<div id="root">${renderedApp}</div>`
);
return new Response(edgeRendered, {
headers: response.headers,
status: response.status
});
}
return response;
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
2. Edge Caching with Cache API
// Service Worker for edge caching (sw.js)
const CACHE_NAME = 'react-app-v1';
const ASSETS = [
'/',
'/static/js/main.js',
'/static/css/main.css',
'/manifest.json'
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(ASSETS))
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
Performance Optimization at the Edge
3. Edge Image Optimization
// Next.js Image Optimization (next.config.js)
module.exports = {
images: {
domains: ['your-cdn.com'],
loader: 'custom',
path: 'https://edge.your-cdn.com/',
deviceSizes: [640, 750, 828, 1080, 1200, 1920],
formats: ['image/webp']
}
};
// React component using optimized images
function OptimizedImage({ src, alt, width, height }) {
return (
<img
src={`https://edge.your-cdn.com/${src}?width=${width}&height=${height}&format=webp`}
alt={alt}
loading="lazy"
/>
);
}
4. Edge API Routes (Next.js)
// pages/api/edge.js - Next.js Edge API Route
import { NextResponse } from 'next/server';
export const config = {
runtime: 'edge',
};
export default function handler(request) {
const url = new URL(request.url);
const country = request.geo.country || 'US';
return NextResponse.json({
message: `Hello from the edge! You're accessing from ${country}`,
path: url.pathname
});
}
Advanced Edge Architectures
5. Edge Config with KV Storage
// Cloudflare Worker with KV
async function handleRequest(request) {
const featureFlags = await EDGE_CONFIG.get('feature_flags', 'json');
const userRegion = request.cf.country;
const shouldEnableFeature = featureFlags[userRegion]?.newFeature || false;
const response = await fetch(request);
const html = await response.text();
const modifiedHtml = html.replace(
'<!--FEATURE_FLAG-->',
`<script>window.featureFlags = ${JSON.stringify({ newFeature: shouldEnableFeature })}</script>`
);
return new Response(modifiedHtml, {
headers: response.headers
});
}
6. Edge Personalization
// Edge middleware for personalization (Next.js)
import { NextResponse } from 'next/server';
export function middleware(request) {
const url = request.nextUrl;
const country = request.geo.country;
const city = request.geo.city;
// Redirect based on location
if (country === 'GB' && !url.pathname.startsWith('/uk')) {
url.pathname = `/uk${url.pathname}`;
return NextResponse.redirect(url);
}
// Add geo headers to API requests
if (url.pathname.startsWith('/api')) {
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-user-country', country);
requestHeaders.set('x-user-city', city);
return NextResponse.next({
request: {
headers: requestHeaders
}
});
}
return NextResponse.next();
}
Edge Data Fetching Patterns
7. Edge-Side Data Fetching
// React component with edge data fetching
async function getEdgeData() {
const response = await fetch('/api/edge-data', {
headers: {
'x-edge-request': 'true'
}
});
return response.json();
}
function EdgeEnhancedComponent() {
const [data, setData] = useState(null);
useEffect(() => {
getEdgeData().then(setData);
}, []);
return (
<div>
{data ? (
<p>Edge-processed data: {data.message}</p>
) : (
<p>Loading edge data...</p>
)}
</div>
);
}
8. Edge-Aware API Client
// edge-aware fetch wrapper
async function edgeFetch(url, options = {}) {
const headers = {
...options.headers,
'x-edge-prefer': 'true',
'x-user-timezone': Intl.DateTimeFormat().resolvedOptions().timeZone
};
const response = await fetch(url, { ...options, headers });
if (response.headers.get('x-edge-processed')) {
console.log('Response processed at edge location:',
response.headers.get('x-edge-location'));
}
return response;
}
// Usage in components
async function fetchUserData() {
const response = await edgeFetch('/api/user');
return response.json();
}
Edge Security Patterns
9. Edge Authentication
// Edge auth middleware (Cloudflare Worker)
async function handleRequest(request) {
const authToken = request.headers.get('Authorization');
const authResponse = await fetch('https://auth-service/verify', {
headers: { 'Authorization': authToken }
});
if (!authResponse.ok) {
return new Response('Unauthorized', { status: 401 });
}
const userData = await authResponse.json();
const newRequest = new Request(request);
newRequest.headers.set('x-user-id', userData.id);
return fetch(newRequest);
}
10. Edge Rate Limiting
// Edge rate limiting (Cloudflare Worker)
async function handleRequest(request) {
const ip = request.headers.get('cf-connecting-ip');
const cache = caches.default;
const cacheKey = `rate_limit_${ip}`;
let limit = await cache.get(cacheKey);
limit = limit ? parseInt(limit) + 1 : 1;
await cache.put(cacheKey, limit.toString(), { expirationTtl: 60 });
if (limit > 100) {
return new Response('Rate limit exceeded', { status: 429 });
}
return fetch(request);
}
Edge Deployment Strategies
11. CI/CD for Edge Functions
# GitHub Actions workflow for edge deployment
name: Deploy Edge Functions
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Install dependencies
run: npm install
- name: Build React app
run: npm run build
- name: Deploy to Cloudflare Workers
uses: cloudflare/wrangler-action@2.0.0
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: publish
env:
WORKERS_SITE: true
12. Edge Feature Flags
// Feature flag middleware (Next.js edge function)
export function middleware(request) {
const url = request.nextUrl;
const country = request.geo.country;
// Check feature flag for country
const flags = {
US: { newDashboard: true },
GB: { newDashboard: false }
};
if (flags[country]?.newDashboard && url.pathname === '/dashboard') {
url.pathname = '/dashboard/new';
return NextResponse.rewrite(url);
}
return NextResponse.next();
}
Best Practices Checklist
- Performance Optimization
- [ ] Implement edge caching for static assets
- [ ] Use edge image optimization
- [ ] Leverage edge-side rendering for faster TTI
- Personalization
- [ ] Utilize geo-location data
- [ ] Implement edge-based A/B testing
- [ ] Use edge config for regional customization
- Security
- [ ] Implement edge authentication
- [ ] Set up edge rate limiting
- [ ] Use edge functions for security headers
- Data Fetching
- [ ] Move API routes to the edge
- [ ] Cache API responses at the edge
- [ ] Implement edge-aware data fetching
- Deployment
- [ ] Set up CI/CD for edge functions
- [ ] Monitor edge performance
- [ ] Test across edge locations
- Resilience
- [ ] Implement edge fallbacks
- [ ] Use edge-based load balancing
- [ ] Set up edge health checks