@cf-wasm/og

中文文档
0.5.0发布于 2026/08/01MITTypeScriptES Module构建来源已验证近 30 天下载 29.8万

Generate Open Graph Images dynamically from HTML/CSS without a browser.

原始使用文档
文档目录15 节
  1. Installation
  2. Usage
  3. Documentation
  4. Use ImageResponse.async
  5. Cloudflare Workers/Pages
  6. Font Loaders
  7. Default font
  8. SVG format
  9. Render HTML
  10. render function
  11. Tailwind CSS
  12. Examples
  13. Cloudflare Workers
  14. Next.js (App Router)
  15. Next.js (Pages Router)

@cf-wasm/og

Generate Open Graph Images dynamically from HTML/CSS without a browser.

Powered by satori and resvg-js.

[!WARNING] Breaking changes may be introduced without following semantic versioning.
Please note that this package may undergo breaking changes between versions without adhering strictly to semantic versioning (SemVer). While efforts will be made to minimize disruptions, it's recommended to review release notes carefully before upgrading to a new version. We apologize for any inconvenience this may cause and appreciate your understanding.

Installation

npm install @cf-wasm/og       # npm
yarn add @cf-wasm/og          # yarn
pnpm add @cf-wasm/og          # pnpm

Usage

Because package.json includes conditional exports for node, workerd, and edge-light, you can usually import directly from @cf-wasm/og and let the runtime choose the correct entrypoint:

import { ImageResponse } from "@cf-wasm/og";

If you want to be explicit, import from a submodule instead:

  • Cloudflare Workers / Pages (Wrangler):

    import { ImageResponse } from "@cf-wasm/og/workerd";
    
  • Next.js Edge Runtime:

    import { ImageResponse } from "@cf-wasm/og/edge-light";
    
  • Node.js (inline):

    import { ImageResponse } from "@cf-wasm/og/node";
    

Documentation

Use ImageResponse.async

It is recommended to use ImageResponse.async() async static method instead of new ImageResponse() constructor:

import React from "react";
import { ImageResponse } from "@cf-wasm/og/node";

// this is recommended
await ImageResponse.async(<>Hello World!</>);

// instead of
new ImageResponse(<>Hello World!</>);

Cloudflare Workers/Pages

If you are using Cloudflare Workers/Pages, you must set the execution context as shown:

import React from "react";
import { ImageResponse, cache } from "@cf-wasm/og/workerd";

export default {
  async fetch(req, env, ctx) {
    // Set execution context
    cache.setExecutionContext(ctx);

    return await ImageResponse.async(<>Hello World!</>);
  },
} satisfies ExportedHandler;

Font Loaders

You can load Google fonts and Custom fonts with ease using GoogleFont and CustomFont classes respectively:

import React from "react";
import {
  ImageResponse,
  GoogleFont,
  CustomFont,
  cache,
} from "@cf-wasm/og/workerd";

export default {
  async fetch(req, env, ctx) {
    cache.setExecutionContext(ctx);

    return await ImageResponse.async(
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          alignItems: "center",
          justifyContent: "center",
          width: "100%",
          height: "100%",
        }}
      >
        <p>Text with Default font</p>
        <p style={{ fontFamily: "Inclusive Sans" }}>Text with Google font</p>
        <p style={{ fontFamily: "JetBrains Mono" }}>Text with Custom font</p>
      </div>,
      {
        fonts: [
          // Using Google font loader
          new GoogleFont("Inclusive Sans"),
          // Using Custom font loader
          new CustomFont("JetBrains Mono", () =>
            fetch(
              "https://github.com/JetBrains/JetBrainsMono/raw/master/fonts/ttf/JetBrainsMono-Regular.ttf",
            ).then((res) => res.arrayBuffer()),
          ),
        ],
      },
    );
  },
} satisfies ExportedHandler;

Default font

You can set global default font using GoogleFont or CustomFont classes:

import React from "react";
import {
  ImageResponse,
  CustomFont,
  GoogleFont,
  defaultFont,
  cache,
} from "@cf-wasm/og/workerd";

// By using Google font loader
defaultFont.set(new GoogleFont("Merriweather"));

// or
// By using Custom font loader
defaultFont.set(
  new CustomFont("JetBrains Mono", () =>
    fetch(
      "https://github.com/JetBrains/JetBrainsMono/raw/master/fonts/ttf/JetBrainsMono-Regular.ttf",
    ).then((res) => res.arrayBuffer()),
  ),
);

export default {
  async fetch(req, env, ctx) {
    cache.setExecutionContext(ctx);

    // It should render with JetBrains Mono font
    return await ImageResponse.async(<>Hello World!</>);
  },
} satisfies ExportedHandler;

You can also set default font using defaultFont option:

import React from "react";
import { ImageResponse, GoogleFont, cache } from "@cf-wasm/og/workerd";

export default {
  async fetch(req, env, ctx) {
    cache.setExecutionContext(ctx);

    return await ImageResponse.async(<>Hello World!</>, {
      // Set default font
      defaultFont: new GoogleFont("Merriweather"),
    });
  },
} satisfies ExportedHandler;

SVG format

By default ImageResponse renders to PNG but you can use format option to render to SVG:

import React from "react";
import { ImageResponse, cache } from "@cf-wasm/og/workerd";

export default {
  async fetch(req, env, ctx) {
    cache.setExecutionContext(ctx);

    return await ImageResponse.async(<>Hello World!</>, {
      // Set format
      format: "svg",
    });
  },
} satisfies ExportedHandler;

Render HTML

The @cf-wasm/og/html-to-react submodule provides a function t which can be used to transform html to ReactElement making it possible to render html as well:

import { ImageResponse, cache } from "@cf-wasm/og/workerd";
import { t } from "@cf-wasm/og/html-to-react";

export default {
  async fetch(req, env, ctx) {
    cache.setExecutionContext(ctx);

    const html = `<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%; height: 100%;">
        <p>Renders HTML</p>
        <p>Hello World!</p>
      </div>`;

    return await ImageResponse.async(t(html));
  },
} satisfies ExportedHandler;

render function

You can also use render function instead of ImageResponse to catch errors or for other use cases:

import React from "react";
import { render, cache } from "@cf-wasm/og/workerd";

export default {
  async fetch(req, env, ctx) {
    cache.setExecutionContext(ctx);

    try {
      const { image } = await render(<>Hello World!</>).asPng();

      return new Response(image, {
        headers: {
          "Content-Type": "image/png",
        },
      });
    } catch {
      return new Response("Not found", {
        status: 404,
      });
    }
  },
} satisfies ExportedHandler;

Tailwind CSS

Satori has experimental support for Tailwind CSS, you can use it by passing Tailwind CSS classes to tw prop of ReactElement.

import React from "react";
import { ImageResponse, cache } from "@cf-wasm/og/workerd";

export default {
  async fetch(req, env, ctx) {
    cache.setExecutionContext(ctx);

    return await ImageResponse.async(
      <div tw="flex w-full h-full items-center justify-center">
        Hello World!
      </div>,
    );
  },
} satisfies ExportedHandler;

Examples

Following are some examples for using this library:

Cloudflare Workers

If you are using Cloudflare Workers, you can use it as shown below:

// src/index.tsx
import React from "react";
import { ImageResponse, GoogleFont, cache } from "@cf-wasm/og/workerd";

export default {
  async fetch(req, env, ctx) {
    // Make sure to set the execution context
    cache.setExecutionContext(ctx);

    const { searchParams } = new URL(req.url);
    const parameters = Object.fromEntries(searchParams.entries());

    return await ImageResponse.async(
      <div
        style={{
          display: "flex",
          flexDirection: "column",
          width: "100%",
          height: "100%",
          alignItems: "center",
          justifyContent: "center",
          backgroundColor: "#6f90ab",
          fontSize: "2rem",
          color: "#fff",
        }}
      >
        <span>Noto Sans (Default Font)</span>
        <span
          style={{
            fontFamily: "JetBrains Mono",
          }}
        >
          JetBrains Mono (using GoogleFont class)
        </span>
        <span>These are emojis: 😎🌩️</span>
        <span
          style={{
            fontFamily: "JetBrains Mono",
          }}
        >
          Parameters: {JSON.stringify(parameters)}
        </span>
      </div>,
      {
        fonts: [new GoogleFont("JetBrains Mono")],
        emoji: "fluent",
      },
    );
  },
} satisfies ExportedHandler;

[!WARNING] If you are using @cf-wasm/og on Cloudflare Workers/Pages, you may hit the CPU time limit, 128 MB Memory limit or 3 MB script size limit (Workers Free Plan).
Avoid loading multiple fonts and assets in memory.

Next.js (App Router)

If you are using Next.js (App router) with edge runtime, you can use it as shown below:

// (src/)app/api/og/route.tsx
import React from "react";
import { type NextRequest } from "next/server";
import { ImageResponse, GoogleFont } from "@cf-wasm/og/edge-light";

export const runtime = "edge";

export async function GET(req: NextRequest) {
  const { searchParams } = req.nextUrl;
  const parameters = Object.fromEntries(searchParams.entries());

  return await ImageResponse.async(
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        width: "100%",
        height: "100%",
        alignItems: "center",
        justifyContent: "center",
        backgroundColor: "#6f90ab",
        fontSize: "2rem",
        color: "#fff",
      }}
    >
      <span>Noto Sans (Default Font)</span>
      <span
        style={{
          fontFamily: "JetBrains Mono",
        }}
      >
        JetBrains Mono (using GoogleFont class)
      </span>
      <span>These are emojis: 😎🌩️</span>
      <span
        style={{
          fontFamily: "JetBrains Mono",
        }}
      >
        Parameters: {JSON.stringify(parameters)}
      </span>
    </div>,
    {
      fonts: [new GoogleFont("JetBrains Mono")],
      emoji: "fluent",
    },
  );
}

Next.js (Pages Router)

If you are using Next.js (Pages router) with edge runtime, you can use it as shown below:

// (src/)pages/api/og.tsx
import React from "react";
import { type NextRequest } from "next/server";
import { ImageResponse, GoogleFont } from "@cf-wasm/og/edge-light";

export const config = {
  runtime: "edge",
};

export default async function handler(req: NextRequest) {
  const { searchParams } = req.nextUrl;
  const parameters = Object.fromEntries(searchParams.entries());

  return await ImageResponse.async(
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        width: "100%",
        height: "100%",
        alignItems: "center",
        justifyContent: "center",
        backgroundColor: "#6f90ab",
        fontSize: "2rem",
        color: "#fff",
      }}
    >
      <span>Noto Sans (Default Font)</span>
      <span
        style={{
          fontFamily: "JetBrains Mono",
        }}
      >
        JetBrains Mono (using GoogleFont class)
      </span>
      <span>These are emojis: 😎🌩️</span>
      <span
        style={{
          fontFamily: "JetBrains Mono",
        }}
      >
        Parameters: {JSON.stringify(parameters)}
      </span>
    </div>,
    {
      fonts: [new GoogleFont("JetBrains Mono")],
      emoji: "fluent",
    },
  );
}

版本与发布记录

@cf-wasm/og 共发布 48 个版本,首次发布于 2024/03/31;过去 12 个月发布了 15 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.5.0latest2026/08/013 个月前
0.4.12026/07/143 个月前
0.4.02026/06/164 个月前
0.3.82026/05/046 个月前
0.3.72026/02/118 个月前
0.3.62026/02/108 个月前

关于 @cf-wasm/og 的常见问题

@cf-wasm/og 是什么?

Generate Open Graph Images dynamically from HTML/CSS without a browser.

如何安装 @cf-wasm/og?

在项目目录运行 npm install @cf-wasm/og,或使用 pnpm add / yarn add / bun add。

@cf-wasm/og 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cf-wasm/og 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@cf-wasm/og 可以商用吗?

@cf-wasm/og 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cf-wasm/og 的下载量有多少?

根据 npm 官方下载统计,@cf-wasm/og 在 2026/10/10 – 2026/11/08 这 30 天内被下载 298,048 次,日均约 9,935 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cf-wasm/og 还在维护吗?

最新版本 0.5.0 发布于 2026/08/01(3 个月前);至今共发布 48 个版本,其中过去 12 个月发布了 15 个;首次发布于 2024/03/31。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。