Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Cloudflare platform skill covering Workers, D1, R2, KV, AI, Durable Objects, and security.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/static-assets/patterns.md
1### Common Patterns23**1. Forward request to assets:**45```typescript6export default {7async fetch(request: Request, env: Env): Promise<Response> {8return env.ASSETS.fetch(request);9}10};11```1213**2. Fetch specific asset by path:**1415```typescript16const response = await env.ASSETS.fetch("https://assets.local/logo.png");17```1819**3. Modify request before fetching asset:**2021```typescript22const url = new URL(request.url);23url.pathname = "/index.html";24return env.ASSETS.fetch(new Request(url, request));25```2627**4. Transform asset response:**2829```typescript30const response = await env.ASSETS.fetch(request);31const modifiedResponse = new Response(response.body, response);32modifiedResponse.headers.set("X-Custom-Header", "value");33modifiedResponse.headers.set("Cache-Control", "public, max-age=3600");34return modifiedResponse;35```3637**5. Conditional asset serving:**3839```typescript40export default {41async fetch(request: Request, env: Env): Promise<Response> {42const url = new URL(request.url);43if (url.pathname === '/') {44return env.ASSETS.fetch('/index.html');45}46return env.ASSETS.fetch(request);47}48};49```5051**6. SPA with API routes:**5253Most common full-stack pattern - static SPA with backend API:5455```typescript56export default {57async fetch(request: Request, env: Env): Promise<Response> {58const url = new URL(request.url);59if (url.pathname.startsWith('/api/')) {60return handleAPI(request, env);61}62return env.ASSETS.fetch(request);63}64};6566async function handleAPI(request: Request, env: Env): Promise<Response> {67return new Response(JSON.stringify({ status: 'ok' }), {68headers: { 'Content-Type': 'application/json' }69});70}71```7273**Config:** Set `run_worker_first: ["/api/*"]` (see configuration.md:66-106)7475**7. Auth gating for protected assets:**7677```typescript78export default {79async fetch(request: Request, env: Env): Promise<Response> {80const url = new URL(request.url);81if (url.pathname.startsWith('/admin/')) {82const session = await validateSession(request, env);83if (!session) {84return Response.redirect('/login', 302);85}86}87return env.ASSETS.fetch(request);88}89};90```9192**Config:** Set `run_worker_first: ["/admin/*"]`9394**8. Custom headers for security:**9596```typescript97export default {98async fetch(request: Request, env: Env): Promise<Response> {99const response = await env.ASSETS.fetch(request);100const secureResponse = new Response(response.body, response);101secureResponse.headers.set('X-Frame-Options', 'DENY');102secureResponse.headers.set('X-Content-Type-Options', 'nosniff');103secureResponse.headers.set('Content-Security-Policy', "default-src 'self'");104return secureResponse;105}106};107```108109**9. A/B testing via cookies:**110111```typescript112export default {113async fetch(request: Request, env: Env): Promise<Response> {114const cookies = request.headers.get('Cookie') || '';115const variant = cookies.includes('variant=b') ? 'b' : 'a';116const url = new URL(request.url);117if (url.pathname === '/') {118return env.ASSETS.fetch(`/index-${variant}.html`);119}120return env.ASSETS.fetch(request);121}122};123```124125**10. Locale-based routing:**126127```typescript128export default {129async fetch(request: Request, env: Env): Promise<Response> {130const locale = request.headers.get('Accept-Language')?.split(',')[0] || 'en';131const url = new URL(request.url);132if (url.pathname === '/') {133return env.ASSETS.fetch(`/${locale}/index.html`);134}135if (!url.pathname.startsWith(`/${locale}/`)) {136url.pathname = `/${locale}${url.pathname}`;137}138return env.ASSETS.fetch(url);139}140};141```142143**11. OAuth callback handling:**144145```typescript146export default {147async fetch(request: Request, env: Env): Promise<Response> {148const url = new URL(request.url);149if (url.pathname === '/auth/callback') {150const code = url.searchParams.get('code');151if (code) {152const session = await exchangeCode(code, env);153return new Response(null, {154status: 302,155headers: {156'Location': '/',157'Set-Cookie': `session=${session}; HttpOnly; Secure; SameSite=Lax`158}159});160}161}162return env.ASSETS.fetch(request);163}164};165```166167**Config:** Set `run_worker_first: ["/auth/*"]`168169**12. Cache control override:**170171```typescript172export default {173async fetch(request: Request, env: Env): Promise<Response> {174const response = await env.ASSETS.fetch(request);175const url = new URL(request.url);176// Immutable assets (hashed filenames)177if (/\.[a-f0-9]{8,}\.(js|css|png|jpg)$/.test(url.pathname)) {178return new Response(response.body, {179...response,180headers: {181...Object.fromEntries(response.headers),182'Cache-Control': 'public, max-age=31536000, immutable'183}184});185}186return response;187}188};189```190