Cloudflare Workers
Overview
Section titled “Overview”Pageflare ships a WebAssembly (WASM) build of its core optimization engine. You can import this WASM module directly into a Cloudflare Worker and run it as an edge middleware — intercepting HTML responses and rewriting them before they reach the user.
When this makes sense:
- You are proxying a backend that generates HTML dynamically and you cannot run a build step.
- You want to apply optimizations to cached Cloudflare responses without rebuilding.
- You need per-request control over which optimizations apply (e.g., based on headers or cookies).
When to prefer the CLI approach:
- Your site is a static build (Astro, Hugo, Next.js static export, etc.) — use Cloudflare Pages instead.
- You want the lowest operational complexity.
How It Works
Section titled “How It Works”The pageflare WASM module exposes a transform(html: string, config: object): string function. You wrap your Worker’s fetch handler so that HTML responses pass through transform before being returned to the client.
Client → Worker fetch handler → origin / cache ↓ transform(html) ↓ Optimized HTML → Client1. Install the WASM Package
Section titled “1. Install the WASM Package”npm install @pageflare/wasm2. Create the Worker
Section titled “2. Create the Worker”import { transform } from '@pageflare/wasm';
export default { async fetch(request: Request, env: Env): Promise<Response> { // Pass non-HTML requests straight through const response = await fetch(request); const contentType = response.headers.get('content-type') ?? ''; if (!contentType.includes('text/html')) { return response; }
const html = await response.text(); const optimized = transform(html, { minify_html: true, minify_css: true, minify_js: true, js_defer: true, lazy_images: true, img_dimensions: true, font_swap: true, });
return new Response(optimized, { status: response.status, headers: response.headers, }); },} satisfies ExportedHandler<Env>;3. Configure wrangler.toml
Section titled “3. Configure wrangler.toml”name = "pageflare-edge"main = "src/worker.ts"compatibility_date = "2024-01-01"
# WASM binding (if using a .wasm file directly rather than the npm package)# [[wasm_modules]]# name = "PAGEFLARE_WASM"# path = "node_modules/@pageflare/wasm/pageflare_bg.wasm"4. Set the License
Section titled “4. Set the License”Pro optimizations require the license. Pass it via a Worker secret:
wrangler secret put PAGEFLARE_LICENSEThen read it in your Worker:
const optimized = transform(html, { license: env.PAGEFLARE_LICENSE, minify_html: true, // ...});5. Deploy
Section titled “5. Deploy”wrangler deployPerformance Considerations
Section titled “Performance Considerations”Running WASM in a Worker adds latency to every HTML response. Keep the following in mind:
- CPU time limits: Cloudflare Workers have CPU time limits (default 10 ms on the free plan, 30 ms on Paid). Complex optimization passes on large HTML pages may approach this limit. Benchmark with your actual pages before deploying to production.
- Memory: WASM modules consume memory. The pageflare WASM module is approximately 2 MB. Workers are limited to 128 MB.
- Cold starts: WASM instantiation adds to cold start time. Cloudflare mitigates this by keeping Workers warm, but the first request after a new deployment will be slower.
- Caching strategy: Apply pageflare transformation before writing to the Cache API so the cached copy is already optimized:
const cache = caches.default;const cacheKey = new Request(request.url, request);let response = await cache.match(cacheKey);
if (!response) { response = await fetch(request); const html = await response.text(); const optimized = transform(html, config); response = new Response(optimized, response); // Cache the optimized version await cache.put(cacheKey, response.clone());}
return response;Selective Optimization
Section titled “Selective Optimization”You can apply different optimization levels based on request properties:
const isBot = /bot|crawler|spider/i.test( request.headers.get('user-agent') ?? '');
const optimized = transform(html, { minify_html: true, // Only defer scripts for real users, not bots js_defer: !isBot, lazy_images: !isBot,});Limitations
Section titled “Limitations”- No filesystem access: The WASM runtime cannot self-host fonts or perform file-system reads. Features that require reading external files (e.g.,
self_host_fonts,critical_cssinlining from disk) are not available. - No relative path resolution: Image dimension inference that requires reading image files from disk is not available; only HTML-embedded dimension hints work.
- Experimental API: The WASM API surface may change between minor versions. Pin to a specific version in production.
Next Steps
Section titled “Next Steps”- Read the Cloudflare Pages guide for a simpler build-time alternative.
- See the Configuration reference for all available optimization options.
- Check the CLI CI/CD guide for hybrid approaches that combine build-time and edge optimization.