新規投稿のお知らせを受信されたい方は、サブスクリプションをご登録ください:

Cloudflare WorkersでJavaScriptモジュールのサポートを開始

2021/11/16

5分で読了

Cloudflare WorkersでJavaScriptモジュールのサポートを開始します。JavaScriptで記述されたWorkerの例を見れば、過去数年間にインターネット上で出現するようになった次のコードスニペットに気付くかもしれません:

addEventListener("fetch", (event) => {
  event.respondWith(new Response("Hello Worker!"));
}

上記の構文は「Service Worker」APIとして知られており、Webブラウザで使用するために標準化することが提案されました。JavaScriptファイルをWebページにアタッチして、そのHTTP要求と応答を変更し、仮想エンドポイントのように動作させることができます。それはまさにWorkersにとって必要なものであり、 fetch()cachesなどの標準的なWeb APIともうまく統合されていました。

モジュールを導入する前に、サービスWorker APIが引き続きサポートされることを明確にしておきましょう。 「APIまたは機能が非推奨になっているため、あなたの書いたコードをあなた自身で書き直す必要がります」というメールを受け取りたりたい開発者は居ません。あなたは私たちからそれを知らされることはありません。私たちがこの決定を下した理由を知りたい場合は、Workersに向けた下位互換性への取り組みについてご確認ください。

JavaScriptモジュールとは

ECMAScript(略称「ES」)モジュールとも呼ばれるJavaScriptモジュールは、JavaScriptでコードをインポートおよびエクスポートするための標準APIです。これは、JavaScriptの「ES6」言語仕様によって導入され、ほとんどのWebブラウザ、Node.js、Deno、そして現在はCloudflare Workersによって実装されています。以下は、これがどのように機能するかを示す例です:

// filename: ./src/util.js
export function getDate(time) {
  return new Date(time).toISOString().split("T")[0]; // "YYYY-MM-DD"
}

「export」キーワードは、「getDate」関数を現在のモジュールからエクスポートすることを示します。次に、別のモジュールから「import」を使用して、その機能を使用できます。

// filename: ./src/index.js
import { getDate } from "./util.js"

console.log("Today’s date:", getDate());

以上は基本ですが、モジュールでできることは他にもたくさんあります。これにより、格調高い方法でコードの整理、保守、再利用を、簡単に行うことができます。ここでは、モジュールのすべて の側面について説明することはできませんが、詳細については、モジュールに関する MDNガイド またはLin Clarkによる技術的な詳細をご覧になることをお勧めします。

Workersでモジュールを使用するにはどうすればよいですか?

Workerを表すデフォルトのモジュールをエクスポートできます。「addEventListener」を使用する代わりに、各イベントハンドラーはそのモジュールの関数として定義されます。現在、cronトリガーでは、HTTPおよびWebSocketリクエストの「fetch」と、「scheduled」をサポートしています。

export default {
  async fetch(request, environment, context) {
    return new Response("I’m a module!");
  },
  async scheduled(controller, environment, context) {
    // await doATask();
  }
}

また、各イベントハンドラーのパラメーターなど、他のいくつかの違いにも気付くかもしれません。単一の「イベント」オブジェクトの代わりに、必要とされるパラメータ群はそれぞれ分散されています。最初のパラメータはイベントタイプに固有です。「fetch」の場合は リクエスト オブジェクトであり、「scheduled」の場合はcronスケジュールを含む コントーラー です。

2番目のパラメータは、環境変数を含むオブジェクトです(「バインディング」とも呼ばれます)。以前は、各変数はWorkerのグローバルスコープに挿入されていました。単純なソリューションではありますが、コードに変数を魔法のように表示させるのは混乱を招きます。これで、環境オブジェクトを使用して、環境変数にアクセスするモジュールとライブラリを制御できます。このメカニズムは、欠陥のある、または不要な挙動をするサードパーティライブラリがすべての変数または機密を列挙するのを防止することができるため、より安全です。

3番目のパラメータはコンテキストオブジェクトであり、  waitUntil() を使用してバックグラウンドタスクを登録できます。これは、イベントの実行をブロックしてはならないロギングやエラーレポートなどのタスクに役立ちます。

これらをすべてまとめると、複数のモジュールをインポートおよびエクスポートしたり、新しいイベントハンドラー構文を使用したりできます。

// filename: ./src/error.js
export async function logError(url, error) {
  await fetch(url, {
     method: "POST",
     body: error.stack
  })
}
// filename: ./src/worker.js
import { logError } from "./error.js"

export default {
  async fetch(request, environment, context) {
    try {
       return await fetch(request);
    } catch (error) {
       context.waitUntil(logError(environment.ERROR_URL, error));
       return new Response("Oops!", { status: 500 });
    }
  }
}

今週初めに一般提供された、クラスもエクスポートできるDurable Objectsをお忘れなく!Durable Objectクラスを定義する方法です。これは増加された値を返す「Counter」Durable Objectの別の例です。

// filename: ./src/counter.js
export class Counter {
  value = 0;
  fetch() {
    this.value++;
    return new Response(this.value.toString());
  }
}
// filename: ./src/worker.js
// We need to re-export the Durable Object class in the Worker module.
export { Counter } from "./counter.js"

export default {
  async fetch(request, environment) {
    const clientId = request.headers.get("cf-connecting-ip");
    const counterId = environment.Counter.idFromName(clientId);
    // Each IP address gets its own Counter.
    const counter = environment.Counter.get(counterId);
    return counter.fetch("https://counter.object/increment");
  }
}

JavaScript以外のモジュールはありますか?

はい!モジュールは主にJavaScript用ですが、他のモジュールタイプもサポートしています。ただし、一部はまだ標準化されていません。

たとえば、 WebAssemblyモジュールとしてインポートできます。以前、サービスWorker APIには、WebAssemblyがバインディングとして含まれていました。 WebAssemblyは外部リソースではなくコードとして表現する必要があるため、これは間違いだったと思います。モジュールを使用して、WebAssemblyをインポートする新しい方法は次のとおりです:

import module from "./lib/hello.wasm"

export default {
  async fetch(request) {
    const instance = await WebAssembly.instantiate(module);
    const result = instance.exports.hello();
    return new Response(result);
  }
}

現在はサポートされていませんが、この 提案で概説されているように、将来はWebAssemblyモジュールとJavaScriptモジュールをより緊密に統合できることを楽しみにしています。以下に示す人間工学的な改善は、WebAssemblyをJavaScriptエコシステムにさらに組み込むために大いに役立つ可能性があります。

import module from "./lib/hello.wasm"

export default {
  async fetch(request) {
    const instance = await WebAssembly.instantiate(module);
    const result = instance.exports.hello();
    return new Response(result);
  }
}

テキストモジュールとバイナリモジュールのサポートも追加しました。これにより、Stringと ArrayBufferをインポートできるようになりました。標準化されていませんが、HTMLファイルや画像などのリソースを簡単にインポートできるようになりました。

<!-- filename: ./public/index.html -->
<!DOCTYPE html>
<html><body>
<p>Hello!</p>
</body></html>
import html from "../public/index.html"

export default {
  fetch(request) {
    if (request.url.endsWith("/index.html") {
       return new Response(html, {
          headers: { "Content-Type": "text/html" }
       });
    }
    return fetch(request);
  }
}

開始方法

モジュールを使い始めるには多くの方法があります。

まず、 プレイグラウンド (アカウントは不要)またはダッシュボードの クイックエディタを使用して、ブラウザでモジュールを試すことができます。ブラウザは、モジュールを使用していることを自動的に検出しサービスWorker APIからシームレスに切り替えることができます。現在のところ、ブラウザで作成できるJavaScriptモジュールは1つだけですが、間もなく複数のモジュールの作成が可能になる予定です。

冒険心があり、モジュールを使用して新しい プロジェクトを始めてみたい方は、Workers向けの次世代コマンドラインインターフェイス(CLI)であるwrangler 2.0のベータリリースをお試しいただけます。

既存のプロジェクトでは、wrangler 1.0 (リリース1.17以降)を使用することをお勧めします。モジュールを有効にするには、「wrangler.toml」構成を次の例に合わせます:

name = "my-worker"
type = "javascript"
workers_dev = true

[build.upload]
format = "modules"
dir = "./src"
main = "./worker.js" # becomes "./src/worker.js"

[[build.upload.rules]]
type = "ESModule"
globs = ["**/*.js"]

# Uncomment if you have a build script.
# [build]
# command = "npm run build"

モジュールの詳細を説明するためにドキュメントを更新しました。ただし、両方の形式を紹介するように移行するため、一部では引き続きサービスWorker APIを使用します。(おまけとしてTypeScriptもあります!)

モジュールで何か問題が発生したり、お気づきの点がある場合は、私たちにお知らせください。確認させていただきます。コーディングをお楽しみいただき、あなたがモジュールを使用して作成されるものを楽しみにしています!

Cloudflareは企業ネットワーク全体を保護し、お客様がインターネット規模のアプリケーションを効率的に構築し、あらゆるWebサイトやインターネットアプリケーションを高速化し、DDoS攻撃を退けハッカーの侵入を防ぎゼロトラスト導入を推進できるようお手伝いしています。

ご使用のデバイスから1.1.1.1 にアクセスし、インターネットを高速化し安全性を高めるCloudflareの無料アプリをご利用ください。

より良いインターネットの構築支援という当社の使命について、詳しくはこちらをご覧ください。新たなキャリアの方向性を模索中の方は、当社の求人情報をご覧ください。
Full Stack Week (JP)日本語JavaScript (JP)Cloudflare Workers (JP)Product News (JP)Developers (JP)

Xでフォロー

Ashcon Partovi|@ashconpartovi
Cloudflare|@cloudflare

関連ブログ投稿

2021年11月20日 13:59

ネットワークパフォーマンスの最新情報:Full Stack Week

2か月と少し前に、世界中のラストワンマイルネットワークの広範なベンチマーク結果を共有しました。さまざまなテスト (TCP接続時間、最初の1バイトを受信するまでの時間(TTFB)、最後の1バイトを受信するまでの時間(TTLB))、また、さまざ...

2021年11月19日 14:00

Cloudflare Workersで、StripeのJavaScript SDKをネイティブサポート

アプリの中で支払いを処理することは、オンラインビジネスを構築する上で非常に重要です。多くの開発者が決済のプラットフォームに選ぶのがStripeです。私が初めてStripeに出会ったのは約7年前ですが、このサービスは単純な支払い処理をはるかに超えて進化しています。...

2021年11月19日 13:59

Cloudflareで次の動画アプリケーションを構築

歴史的に、動画アプリケーションの構築は非常に難しいものでした。動画の録画、エンコード、そして再生の裏には多くの複雑な技術があります。幸いなことに、Cloudflare Streamではすべての難しい部分を取り除くことで、カスタム動画やストリーミングアプリケーションを簡単に構築できます...

2021年11月19日 13:59

CloudflareスタックでのオープンソースCMS:紹介記事

Cloudflareのドキュメントは、コンセプトを学習したり、APIの使用上の注意を確認したりする場合や、APIやコンセプトを説明するための簡潔なスニペットが必要な場合に役立つ資料です。しかし、その資料が網羅的であるとしても、Cloudflare Workersプラットフォームの新規ユーザーは、...