コンテンツにスキップ

ブラウザレンダリングワーカーを耐久オブジェクトでデプロイする

Last reviewed: 12 months ago

このガイドに従うことで、ブラウザレンダリングAPIとDurable Objectsを使用して、ウェブページのスクリーンショットを取得し、それをR2に保存するワーカーを作成します。

耐久オブジェクトを使用してブラウザセッションを永続化することで、新しいブラウザセッションを立ち上げるのにかかる時間を排除し、パフォーマンスが向上します。耐久オブジェクトはセッションを再利用するため、必要な同時セッションの数を減らします。

  1. Sign up for a Cloudflare account.
  2. Install npm.
  3. Install Node.js.

Node.js version manager

Use a Node version manager like Volta or nvm to avoid permission issues and change Node.js versions. Wrangler, discussed later in this guide, requires a Node version of 16.17.0 or later.

1. ワーカープロジェクトを作成する

Cloudflare Workersは、インフラストラクチャを設定または維持することなく、新しいアプリケーションを作成したり、既存のアプリケーションを拡張したりできるサーバーレス実行環境を提供します。あなたのワーカーアプリケーションは、ヘッドレスブラウザと対話してスクリーンショットを取得するなどのアクションを実行するためのコンテナです。

次のコマンドを実行して、browser-workerという名前の新しいワーカープロジェクトを作成します。

Terminal window
npm create cloudflare@latest -- browser-worker

2. ダッシュボードで耐久オブジェクトを有効にする

耐久オブジェクトを有効にするには、Workersの有料プランを購入する必要があります。

  1. Cloudflareダッシュボードにログインし、アカウントを選択します。
  2. Workers & Pages > Plansに移動します。
  3. Purchase Workers Paidを選択し、耐久オブジェクトを有効にするための支払いプロセスを完了します。

3. Puppeteerをインストールする

browser-workerディレクトリ内で、CloudflareのPuppeteerのフォークをインストールします。

Terminal window
npm install @cloudflare/puppeteer --save-dev

4. R2バケットを作成する

本番用と開発用の2つのR2バケットを作成します。

バケット名は小文字でなければならず、ダッシュのみを含むことができます。

Terminal window
wrangler r2 bucket create screenshots
wrangler r2 bucket create screenshots-test

バケットが作成されたことを確認するには、次のコマンドを実行します。

Terminal window
wrangler r2 bucket list

listコマンドを実行すると、作成したバケット名を含むすべてのバケット名が表示されます。

5. wrangler.tomlを構成する

browser-workerプロジェクトのwrangler.tomlファイルを構成し、ブラウザのバインディングNode.js互換フラグを追加します。ブラウザバインディングは、ワーカーとヘッドレスブラウザ間の通信を可能にし、スクリーンショットの取得やPDFの生成などのアクションを実行できます。

次のようにwrangler.toml構成ファイルを更新します。

name = "rendering-api-demo"
main = "src/index.js"
compatibility_date = "2023-09-04"
compatibility_flags = [ "nodejs_compat"]
account_id = <ACCOUNT_ID>
# ブラウザレンダリングAPIバインディング
browser = { binding = "MYBROWSER" }
# R2バケットをバインド
[[r2_buckets]]
binding = "BUCKET"
bucket_name = "screenshots"
preview_bucket_name = "screenshots-test"
# 耐久オブジェクトへのバインディング
[[durable_objects.bindings]]
name = "BROWSER"
class_name = "Browser"
[[migrations]]
tag = "v1" # 各エントリに対して一意である必要があります
new_classes = ["Browser"] # 新しいクラスの配列

6. コード

以下のコードは、耐久オブジェクトを使用してPuppeteerを使用してブラウザをインスタンス化します。その後、異なる解像度のウェブページを一連に開き、それぞれのスクリーンショットを取得し、R2にアップロードします。

耐久オブジェクトは、最後の使用から60秒間ブラウザセッションをオープンに保ちます。ブラウザセッションがオープンしている場合、リクエストは新しいセッションを作成するのではなく、既存のセッションを再利用します。次のコードをコピーして、ワーカーコードを更新します。

import puppeteer from "@cloudflare/puppeteer";
export default {
async fetch(request, env) {
let id = env.BROWSER.idFromName("browser");
let obj = env.BROWSER.get(id);
// 耐久オブジェクトにリクエストを送信し、その応答を待ちます。
let resp = await obj.fetch(request.url);
return resp;
},
};
const KEEP_BROWSER_ALIVE_IN_SECONDS = 60;
export class Browser {
constructor(state, env) {
this.state = state;
this.env = env;
this.keptAliveInSeconds = 0;
this.storage = this.state.storage;
}
async fetch(request) {
// テストする画面解像度
const width = [1920, 1366, 1536, 360, 414];
const height = [1080, 768, 864, 640, 896];
// 現在の日付と時刻を使用してR2のフォルダ構造を作成
const nowDate = new Date();
var coeff = 1000 * 60 * 5;
var roundedDate = new Date(
Math.round(nowDate.getTime() / coeff) * coeff,
).toString();
var folder = roundedDate.split(" GMT")[0];
//ブラウザセッションがオープンしている場合は再利用
if (!this.browser || !this.browser.isConnected()) {
console.log(`Browser DO: 新しいインスタンスを開始しています`);
try {
this.browser = await puppeteer.launch(this.env.MYBROWSER);
} catch (e) {
console.log(
`Browser DO: ブラウザインスタンスを開始できませんでした。エラー: ${e}`,
);
}
}
// DOへの各呼び出し後にkeptAliveをリセット
this.keptAliveInSeconds = 0;
const page = await this.browser.newPage();
// 各画面サイズのスクリーンショットを取得
for (let i = 0; i < width.length; i++) {
await page.setViewport({ width: width[i], height: height[i] });
await page.goto("https://workers.cloudflare.com/");
const fileName = "screenshot_" + width[i] + "x" + height[i];
const sc = await page.screenshot({ path: fileName + ".jpg" });
await this.env.BUCKET.put(folder + "/" + fileName + ".jpg", sc);
}
// ページでの作業が完了したらタブを閉じる
await page.close();
// DOに対するタスクを実行した後にkeptAliveをリセット
this.keptAliveInSeconds = 0;
// DOを生かしておくための最初のアラームを設定
let currentAlarm = await this.storage.getAlarm();
if (currentAlarm == null) {
console.log(`Browser DO: アラームを設定しています`);
const TEN_SECONDS = 10 * 1000;
await this.storage.setAlarm(Date.now() + TEN_SECONDS);
}
return new Response("成功");
}
async alarm() {
this.keptAliveInSeconds += 10;
// ブラウザDOの寿命を延ばす
if (this.keptAliveInSeconds < KEEP_BROWSER_ALIVE_IN_SECONDS) {
console.log(
`Browser DO: ${this.keptAliveInSeconds}秒間生かされています。寿命を延ばしています。`,
);
await this.storage.setAlarm(Date.now() + 10 * 1000);
// 作業がない場合は自動的に閉じることができます
// 例えば、`await this.browser.version()`をリクエストすることでws接続を維持できます
} else {
console.log(
`Browser DO: ${KEEP_BROWSER_ALIVE_IN_SECONDS}sを超えました。`,
);
if (this.browser) {
console.log(`ブラウザを閉じています。`);
await this.browser.close();
}
}
}
}

7. テスト

npx wrangler dev --remoteを実行して、Cloudflareのグローバルネットワークにデプロイする前にワーカーをリモートでテストします。ブラウザレンダリングのローカルモードサポートは存在しないため、--remoteが必要です。

8. デプロイ

npx wrangler deployを実行して、ワーカーをCloudflareのグローバルネットワークにデプロイします。

関連リソース