edge-rendering

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Edge Rendering

Edge Rendering

Description

描述

Edge Rendering generates and serves dynamic pages at the network edge, eliminating origin round-trips for content that varies by city, service, or user segment. This skill powers googleadsagent.ai™'s system of 18,000+ pages generated from a matrix of 116 services across 155+ cities, each with unique content, structured data, and SEO metadata—all rendered at the edge with sub-50ms TTFB globally.
The city × service page matrix demonstrates the power of edge rendering at scale. Rather than pre-building 18,000 static pages or routing every request to a centralized origin, Workers generate each page on demand using templates, city-specific data from KV, and service metadata from D1. Rendered pages are cached at the edge with stale-while-revalidate semantics, providing instant responses while keeping content fresh.
This pattern extends beyond SEO landing pages to any content that follows a combinatorial template: product × location pages, event × venue pages, or service × industry pages. The edge rendering pipeline handles template resolution, data injection, structured data generation (JSON-LD), meta tag construction, and cache management as a unified system.
边缘渲染在网络边缘生成并提供动态页面,消除了针对因城市、服务或用户细分而不同的内容的源站往返请求。该技能为googleadsagent.ai™的系统提供支持,该系统基于155+城市的116项服务矩阵生成了18000+个页面,每个页面都有独特的内容、结构化数据和SEO元数据——所有这些都在边缘渲染,全球范围内首字节时间(TTFB)低于50毫秒。
城市×服务页面矩阵展示了大规模边缘渲染的能力。无需预构建18000个静态页面或将每个请求路由到中心化源站,Workers会按需使用模板、KV中的城市特定数据以及D1中的服务元数据生成每个页面。渲染后的页面会在边缘缓存,并采用stale-while-revalidate语义,在保持内容新鲜的同时提供即时响应。
这种模式不仅适用于SEO落地页,还适用于任何遵循组合模板的内容:产品×位置页面、活动×场地页面或服务×行业页面。边缘渲染流水线将模板解析、数据注入、结构化数据生成(JSON-LD)、元标签构建和缓存管理整合为一个统一系统。

Use When

适用场景

  • Generating pages from a combinatorial matrix (city × service, product × category)
  • Serving SEO-critical content that must have fast TTFB globally
  • Building landing page systems with thousands of unique URLs
  • Replacing static site generation that takes hours to build
  • Implementing stale-while-revalidate caching at the edge
  • Rendering structured data (JSON-LD) dynamically per page
  • 从组合矩阵(城市×服务、产品×分类)生成页面
  • 提供对SEO至关重要且需全球范围内快速TTFB的内容
  • 构建包含数千个唯一URL的落地页系统
  • 替代需要数小时构建的静态站点生成(SSG)
  • 在边缘实现stale-while-revalidate缓存
  • 为每个页面动态渲染结构化数据(JSON-LD)

How It Works

工作原理

mermaid
graph TD
    A[Request: /google-ads/chicago] --> B[Worker: Parse city + service]
    B --> C{Edge Cache Hit?}
    C -->|Hit| D[Return Cached HTML]
    C -->|Miss| E[Fetch City Data from KV]
    E --> F[Fetch Service Data from D1]
    F --> G[Render Template]
    G --> H[Inject JSON-LD Structured Data]
    H --> I[Generate Meta Tags]
    I --> J[Cache at Edge]
    J --> K[Return Fresh HTML]
    D --> L[Background: Revalidate if Stale]
Every request resolves to a (city, service) tuple. The Worker checks the edge cache first. On miss, it fetches city and service data in parallel, renders the template, injects structured data, and caches the result. Stale entries trigger background revalidation without blocking the response.
mermaid
graph TD
    A[Request: /google-ads/chicago] --> B[Worker: Parse city + service]
    B --> C{Edge Cache Hit?}
    C -->|Hit| D[Return Cached HTML]
    C -->|Miss| E[Fetch City Data from KV]
    E --> F[Fetch Service Data from D1]
    F --> G[Render Template]
    G --> H[Inject JSON-LD Structured Data]
    H --> I[Generate Meta Tags]
    I --> J[Cache at Edge]
    J --> K[Return Fresh HTML]
    D --> L[Background: Revalidate if Stale]
每个请求都会解析为(城市,服务)元组。Worker首先检查边缘缓存。如果未命中,则并行获取城市和服务数据,渲染模板,注入结构化数据,并缓存结果。过期的条目会触发后台重新验证,不会阻塞响应。

Implementation

实现代码

typescript
export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(request.url);
    const [, service, city] = url.pathname.split("/");

    const cacheKey = new Request(url.toString());
    const cache = caches.default;
    let response = await cache.match(cacheKey);

    if (response) {
      const age = parseInt(response.headers.get("age") ?? "0");
      if (age > 3600) {
        ctx.waitUntil(revalidate(env, cache, cacheKey, service, city));
      }
      return response;
    }

    return revalidate(env, cache, cacheKey, service, city);
  },
} satisfies ExportedHandler<Env>;

async function revalidate(
  env: Env, cache: Cache, cacheKey: Request, service: string, city: string
): Promise<Response> {
  const [cityData, serviceData] = await Promise.all([
    env.CITY_KV.get<CityData>(city, "json"),
    env.DB.prepare("SELECT * FROM services WHERE slug = ?").bind(service).first<ServiceData>(),
  ]);

  if (!cityData || !serviceData) {
    return new Response("Not Found", { status: 404 });
  }

  const html = renderPage(cityData, serviceData);
  const response = new Response(html, {
    headers: {
      "Content-Type": "text/html;charset=UTF-8",
      "Cache-Control": "public, s-maxage=86400, stale-while-revalidate=3600",
    },
  });

  await cache.put(cacheKey, response.clone());
  return response;
}

function renderPage(city: CityData, service: ServiceData): string {
  const jsonLd = {
    "@context": "https://schema.org",
    "@type": "LocalBusiness",
    name: `${service.name} in ${city.name}`,
    address: { "@type": "PostalAddress", addressLocality: city.name, addressRegion: city.state },
    geo: { "@type": "GeoCoordinates", latitude: city.lat, longitude: city.lng },
    url: `https://googleadsagent.ai/${service.slug}/${city.slug}`,
  };

  return `<!DOCTYPE html>
<html lang="en">
<head>
  <title>${service.name} in ${city.name} | googleadsagent.ai</title>
  <meta name="description" content="${service.description} for businesses in ${city.name}, ${city.state}." />
  <script type="application/ld+json">${JSON.stringify(jsonLd)}</script>
</head>
<body>${service.template.replace("{{city}}", city.name)}</body>
</html>`;
}
typescript
export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(request.url);
    const [, service, city] = url.pathname.split("/");

    const cacheKey = new Request(url.toString());
    const cache = caches.default;
    let response = await cache.match(cacheKey);

    if (response) {
      const age = parseInt(response.headers.get("age") ?? "0");
      if (age > 3600) {
        ctx.waitUntil(revalidate(env, cache, cacheKey, service, city));
      }
      return response;
    }

    return revalidate(env, cache, cacheKey, service, city);
  },
} satisfies ExportedHandler<Env>;

async function revalidate(
  env: Env, cache: Cache, cacheKey: Request, service: string, city: string
): Promise<Response> {
  const [cityData, serviceData] = await Promise.all([
    env.CITY_KV.get<CityData>(city, "json"),
    env.DB.prepare("SELECT * FROM services WHERE slug = ?").bind(service).first<ServiceData>(),
  ]);

  if (!cityData || !serviceData) {
    return new Response("Not Found", { status: 404 });
  }

  const html = renderPage(cityData, serviceData);
  const response = new Response(html, {
    headers: {
      "Content-Type": "text/html;charset=UTF-8",
      "Cache-Control": "public, s-maxage=86400, stale-while-revalidate=3600",
    },
  });

  await cache.put(cacheKey, response.clone());
  return response;
}

function renderPage(city: CityData, service: ServiceData): string {
  const jsonLd = {
    "@context": "https://schema.org",
    "@type": "LocalBusiness",
    name: `${service.name} in ${city.name}`,
    address: { "@type": "PostalAddress", addressLocality: city.name, addressRegion: city.state },
    geo: { "@type": "GeoCoordinates", latitude: city.lat, longitude: city.lng },
    url: `https://googleadsagent.ai/${service.slug}/${city.slug}`,
  };

  return `<!DOCTYPE html>
<html lang="en">
<head>
  <title>${service.name} in ${city.name} | googleadsagent.ai</title>
  <meta name="description" content="${service.description} for businesses in ${city.name}, ${city.state}." />
  <script type="application/ld+json">${JSON.stringify(jsonLd)}</script>
</head>
<body>${service.template.replace("{{city}}", city.name)}</body>
</html>`;
}

Best Practices

最佳实践

  • Fetch city and service data in parallel with
    Promise.all
    , never sequentially
  • Use
    stale-while-revalidate
    to serve cached content while refreshing in the background
  • Generate JSON-LD structured data for every page to maximize search engine visibility
  • Keep KV values under 25MB and D1 queries under 100ms for consistent edge performance
  • Implement a sitemap generator that reflects the current city × service matrix
  • Monitor cache hit ratios—target above 95% for production traffic
  • 使用
    Promise.all
    并行获取城市和服务数据,切勿串行获取
  • 使用
    stale-while-revalidate
    在后台刷新内容的同时提供缓存内容
  • 为每个页面生成JSON-LD结构化数据,以最大化搜索引擎可见性
  • 保持KV值在25MB以下,D1查询在100ms以内,以确保稳定的边缘性能
  • 实现一个能反映当前城市×服务矩阵的站点地图生成器
  • 监控缓存命中率——生产流量目标应高于95%

Platform Compatibility

平台兼容性

PlatformSupportNotes
CursorFullWorker development + deployment
VS CodeFullWrangler integration
WindsurfFullEdge-first development
Claude CodeFullTemplate + Worker generation
ClineFullEdge architecture support
aiderPartialTemplate generation only
平台支持情况说明
Cursor完全支持Worker开发与部署
VS Code完全支持Wrangler集成
Windsurf完全支持边缘优先开发
Claude Code完全支持模板与Worker生成
Cline完全支持边缘架构支持
aider部分支持仅模板生成

Related Skills

相关技能

  • Cloudflare Workers
  • CI/CD Pipelines
  • Observability
  • CodeQL & Semgrep
  • Cloudflare Workers
  • CI/CD 流水线
  • 可观测性
  • CodeQL & Semgrep

Keywords

关键词

edge-rendering
city-service-pages
cloudflare-workers
seo
json-ld
stale-while-revalidate
dynamic-pages
structured-data

© 2026 googleadsagent.ai™ | Agent Skills™ | MIT License
edge-rendering
city-service-pages
cloudflare-workers
seo
json-ld
stale-while-revalidate
dynamic-pages
structured-data

© 2026 googleadsagent.ai™ | Agent Skills™ | MIT License