
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Fri, 10 Apr 2026 20:06:41 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Improved Cloudflare Workers testing via Vitest and workerd]]></title>
            <link>https://blog.cloudflare.com/workers-vitest-integration/</link>
            <pubDate>Fri, 15 Mar 2024 14:00:35 GMT</pubDate>
            <description><![CDATA[ Today, we’re excited to announce a new Workers Vitest integration - allowing you to write unit and integration tests via the popular testing framework, Vitest, that execute directly in our runtime, workerd ]]></description>
            <content:encoded><![CDATA[ <p></p><p></p><p>Today, we’re excited to announce a new Workers Vitest integration - allowing you to write unit and integration tests via the popular testing framework, <a href="https://vitest.dev/">Vitest</a>, that execute directly in our runtime, <a href="https://github.com/cloudflare/workerd">workerd</a>!</p><p>This integration provides you with the ability to test <b><i>anything</i></b> related to your Worker!</p><p>For the first time, you can write unit tests that run within the same <a href="https://github.com/cloudflare/workerd">runtime</a> that Cloudflare Workers run on in production, providing greater confidence that the behavior of your Worker in tests will be the same as when deployed to production. For integration tests, you can now write tests for Workers that are triggered by <a href="https://developers.cloudflare.com/workers/configuration/cron-triggers/">Cron Triggers</a> in addition to traditional <code>fetch()</code> events. You can also more easily test complex applications that interact with <a href="https://developers.cloudflare.com/kv/">KV</a>, <a href="https://www.cloudflare.com/developer-platform/products/r2/">R2</a>, <a href="https://developers.cloudflare.com/d1/">D1</a>, <a href="https://developers.cloudflare.com/queues/">Queues</a>, <a href="https://developers.cloudflare.com/workers/configuration/bindings/about-service-bindings/">Service Bindings</a>, and more Cloudflare products.</p><p>For all of your tests, you have access to <a href="https://vitest.dev/guide/features.html">Vitest features</a> like snapshots, mocks, timers, and spies.</p><p>In addition to increased testing and functionality, you’ll also notice other developer experience improvements like hot-module-reloading, watch mode on by default, and per-test isolated storage. Meaning that, as you develop and edit your tests, they’ll automatically re-run, without you having to restart your test runner.</p>
    <div>
      <h2>Get started testing Workers with Vitest</h2>
      <a href="#get-started-testing-workers-with-vitest">
        
      </a>
    </div>
    <p>The easiest way to get started with testing your Workers via Vitest is to start a new Workers project via our create-cloudflare tool:</p>
            <pre><code>npm create cloudflare@latest hello-world -- --type=hello-world</code></pre>
            <p>Running this command will scaffold a new project for you with the Workers Vitest integration already set up. An example unit test and integration test are also included.</p>
    <div>
      <h3>Manual install and setup instructions</h3>
      <a href="#manual-install-and-setup-instructions">
        
      </a>
    </div>
    <p>If you prefer to manually install and set up the Workers Vitest integration, begin by installing <code>@cloudflare/vitest-pool-workers</code> from npm:</p>
            <pre><code>$ npm install --save-dev @cloudflare/vitest-pool-workers</code></pre>
            <p><code>@cloudflare/vitest-pool-workers</code> has a peer dependency on a specific version of <code>vitest</code>. Modern versions of <code>npm</code> will install this automatically, but we recommend you install it explicitly too. Refer to the <a href="https://developers.cloudflare.com/workers/testing/vitest-integration/get-started/write-your-first-test/">getting started guide</a> for the current supported version. If you’re using TypeScript, add <code>@cloudflare/vitest-pool-workers</code> to your <code>tsconfig.json</code>’s <code>types</code> to get types for the <code>cloudflare:test</code> module:</p>
            <pre><code>{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "bundler",
    "lib": ["esnext"],
    "types": [
      "@cloudflare/workers-types/experimental",
      "@cloudflare/vitest-pool-workers"
    ]
  }
}</code></pre>
            <p>Then, enable the pool in your Vitest configuration file:</p>
            <pre><code>// vitest.config.js
import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";

export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        wrangler: { configPath: "./wrangler.toml" },
      },
    },
  },
});</code></pre>
            <p>After that, define a compatibility date after “2022-10-31” and enable the <a href="https://developers.cloudflare.com/workers/configuration/compatibility-dates/#nodejs-compatibility-flag"><code>nodejs_compat</code> compatibility flag</a> in your <code>wrangler.toml</code>:</p>
            <pre><code># wrangler.toml
main = "src/index.ts"
compatibility_date = "2024-01-01"
compatibility_flags = ["nodejs_compat"]</code></pre>
            
    <div>
      <h2>Test anything exported from a Worker</h2>
      <a href="#test-anything-exported-from-a-worker">
        
      </a>
    </div>
    <p>With the new Workers Vitest Integration, you can test anything exported from your Worker in both unit and integration-style tests. Within these tests, you can also test connected resources like R2, KV, and Durable Objects, as well as applications involving multiple Workers.</p>
    <div>
      <h3>Writing unit tests</h3>
      <a href="#writing-unit-tests">
        
      </a>
    </div>
    <p>In a Workers context, a unit test imports and directly calls functions from your Worker then asserts on their return values. Let’s say you have a Worker that looks like this:</p>
            <pre><code>export function add(a, b) {
  return a + b;
}

export default {
  async fetch(request) {
    const url = new URL(request.url);
    const a = parseInt(url.searchParams.get("a"));
    const b = parseInt(url.searchParams.get("b"));
    return new Response(add(a, b));
  }
}</code></pre>
            <p>After you’ve setup and installed the Workers Vitest integration, you can unit test this Worker by creating a new test file called <code>index.spec.js</code> with the following code:</p>
            <pre><code>import { env, createExecutionContext, waitOnExecutionContext, } from "cloudflare:test";
import { describe, it, expect } from "vitest";
import { add }, worker from "./src";

describe("Hello World worker", () =&gt; {
  it(“adds two numbers”, async () =&gt; {
    expect(add(2,3).toBe(5);
  });
  it("sends request (unit style)", async () =&gt; {
    const request = new Request("http://example.com/?a=3&amp;b=4");
    const ctx = createExecutionContext();
    const response = await worker.fetch(request, env, ctx);
    await waitOnExecutionContext(ctx);
    expect(await response.text()).toMatchInlineSnapshot(`"7"`);
  });
});</code></pre>
            <p>Using the Workers Vitest integration, you can write unit tests like these for any of your Workers.</p>
    <div>
      <h3>Writing integration tests</h3>
      <a href="#writing-integration-tests">
        
      </a>
    </div>
    <p>While unit tests are great for testing individual parts of your application, integration tests assess multiple units of functionality, ensuring that workflows and features work as expected. These are usually more complex than unit tests, but provide greater confidence that your app works as expected. In the Workers context, an integration test sends HTTP requests to your Worker and asserts on the HTTP responses.</p><p>With the Workers Vitest Integration, you can run integration tests by importing <code>SELF</code> from the new <code>cloudflare:test</code> utility like this:</p>
            <pre><code>// test/index.spec.ts
import { SELF } from "cloudflare:test";
import { it, expect } from "vitest";
import "../src";

// an integration test using SELF
it("sends request (integration style)", async () =&gt; {
   const response = await SELF.fetch("http://example.com/?a=3&amp;b=4");
   expect(await response.text()).toMatchInlineSnapshot(`"7"`);
});</code></pre>
            <p>When using <code>SELF</code> for integration tests, your Worker code runs in the same context as the test runner. This means you can use mocks to control your Worker.</p>
    <div>
      <h3>Testing different scenarios</h3>
      <a href="#testing-different-scenarios">
        
      </a>
    </div>
    <p>Whether you’re writing unit or integration tests, if your application uses Cloudflare Developer Platform products (e.g. KV, R2, <a href="https://www.cloudflare.com/developer-platform/products/d1/">D1</a>, Queues, or Durable Objects), you can test them. To demonstrate this, we have created a set of <a href="https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples">examples</a> to help get you started testing.</p>
    <div>
      <h2>Better testing experience === better testing</h2>
      <a href="#better-testing-experience-better-testing">
        
      </a>
    </div>
    <p>Having better testing tools makes it easier to test your projects right from the start, which leads to better overall quality and experience for your end users. The Workers Vitest integration provides that better experience, not just in terms of developer experience, but in making it easier to test your entire application.</p><p>The rest of this post will focus on <i>how</i> we built this new testing integration, diving into the internals of how Vitest works, the problems we encountered trying to get a framework to work within our runtime, and ultimately how we solved it and the improved DX that it unlocked.</p>
    <div>
      <h2>How Vitest traditionally works</h2>
      <a href="#how-vitest-traditionally-works">
        
      </a>
    </div>
    <p>When you start Vitest’s CLI, it first collects and sequences all your test files. By default, Vitest uses a “threads” pool, which spawns <a href="https://nodejs.org/api/worker_threads.html">Node.js worker threads</a> for isolating and running tests in parallel. Each thread gets a test file to run, dynamically requesting and evaluating code as needed. When the test runner imports a module, it sends a request to the host’s “Vite Node Server” which will either return raw JavaScript code transformed by Vite, or an external module path. If raw code is returned, it will be executed using the <a href="https://nodejs.org/api/vm.html#vmruninthiscontextcode-options"><code>node:vm</code> <code>runInThisContext()</code> function</a>. If a module path is returned, it will be imported using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import">dynamic <code>import()</code></a>. Transforming user code with Vite allows hot-module-reloading (HMR) — when a module changes, it’s invalidated in the module cache and a new version will be returned when it’s next imported.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/bmF35IKzPZ9mTXK7lnTA8/c6924d8fd533ea835035fb67dbf0e0c4/Untitled-1.png" />
            
            </figure><p>Miniflare is a fully-local simulator for Cloudflare's Developer Platform. <a href="/miniflare/">Miniflare v2</a> provided a <a href="https://miniflare.dev/testing/vitest">custom environment</a> for Vitest that allowed you to run your tests <i>inside</i> the Workers sandbox. This meant you could import and call any function using Workers runtime APIs in your tests. You weren’t restricted to integration tests that just sent and received HTTP requests. In addition, this environment provided per-test isolated storage, automatically undoing any changes made at the end of each test. In Miniflare v2, this environment was relatively simple to implement. We’d already reimplemented Workers Runtime APIs in a Node.js environment, and could inject them using Vitest’s APIs into the global scope of the test runner.</p><p>By contrast, Miniflare v3 runs your Worker code <a href="/miniflare-and-workerd">inside the same <code>workerd</code> runtime</a> that Cloudflare uses in production. Running tests directly in <a href="https://github.com/cloudflare/workerd"><code>workerd</code></a> presented a challenge — <code>workerd</code> runs in its own process, separate from the Node.js worker thread, and it’s not possible to reference JavaScript classes across a process boundary.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Ngw1zLJWN4jfTko19ZhOn/e052b51d4bf2f00d89826cd02d2a2ad5/Untitled--1--1.png" />
            
            </figure>
    <div>
      <h2>Solving the problem with custom pools</h2>
      <a href="#solving-the-problem-with-custom-pools">
        
      </a>
    </div>
    <p>Instead, we use <a href="https://vitest.dev/advanced/pool.html">Vitest’s custom pools</a> feature to run the test runner in Cloudflare Workers running locally with <a href="/workerd-open-source-workers-runtime"><code>workerd</code></a>. A pool receives test files to run and decides how to execute them. By executing the runner inside <code>workerd</code>, tests have direct access to Workers runtime APIs as they’re running in a Worker. WebSockets are used to send and receive serialisable RPC messages between the Node.js host and <code>workerd</code> process. Note we’re running the exact same test runner code originally designed for a Node-context inside a Worker here. This means our Worker needs to provide Node’s built-in modules, support for dynamic code evaluation, and loading of arbitrary modules from disk with <a href="https://nodejs.org/api/esm.html#resolution-algorithm-specification">Node-resolution behavior</a>. The <a href="/workers-node-js-asynclocalstorage/"><code>nodejs_compat</code> compatibility flag</a> provides support for some of Node’s built-in modules, but does not solve our other problems. For that, we had to get creative…</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2xktF5P98mL5puD3UaQnZx/0a66f121c5cc631009df97c3b0f33dd7/Untitled--2--1.png" />
            
            </figure>
    <div>
      <h2>Dynamic code evaluation</h2>
      <a href="#dynamic-code-evaluation">
        
      </a>
    </div>
    <p>For <a href="https://developers.cloudflare.com/workers/runtime-apis/web-standards/#javascript-standards">security reasons</a>, the Cloudflare Workers runtime does not allow dynamic code evaluation via <code>eval()</code> or <code>new Function()</code>. It also requires all modules to be defined ahead-of-time before execution starts. The test runner doesn't know what code to run until we start executing tests, so without lifting these restrictions, we have no way of executing the raw JavaScript code transformed by Vite nor importing arbitrary modules from disk. Fortunately, code that is only meant to run locally – like tests – has a much more relaxed security model than deployed code. To support local testing and other development-specific use-cases such as <a href="https://vitejs.dev/guide/api-vite-runtime">Vite’s new Runtime API</a>, we added <a href="https://github.com/cloudflare/workerd/pull/1338">“unsafe-eval bindings”</a> and <a href="https://github.com/cloudflare/workerd/pull/1423">“module-fallback services”</a> to <code>workerd</code>.</p><p>Unsafe-eval bindings provide local-only access to the <code>eval()</code> function, and <code>new Function()</code>/<code>new AsyncFunction()</code>/<code>new WebAssembly.Module()</code> constructors. By exposing these through a binding, we retain control over which code has access to these features.</p>
            <pre><code>// Type signature for unsafe-eval bindings
interface UnsafeEval {
  eval(script: string, name?: string): unknown;
  newFunction(script: string, name?: string, ...args: string[]): Function;
  newAsyncFunction(script: string, name?: string, ...args: string[]): AsyncFunction;
  newWasmModule(src: BufferSource): WebAssembly.Module;
}</code></pre>
            <p>Using the unsafe-eval binding <code>eval()</code> method, we were able to implement a <a href="https://github.com/cloudflare/workers-sdk/blob/main/packages/vitest-pool-workers/src/worker/lib/node/vm.ts">polyfill for the required <code>vm.runInThisContext()</code></a> function. While we could also implement loading of arbitrary modules from disk using unsafe-eval bindings, this would require us to rebuild <code>workerd</code>’s module resolution system in JavaScript. Instead, we allow workers to be configured with module fallback services. If enabled, imports that cannot be resolved by <code>workerd</code> become HTTP requests to the fallback service. These include the specifier, referrer, and whether it was an <code>import</code> or <code>require</code>. The service may respond with a module definition, or a redirect to another location if the resolved location doesn’t match the specifier. Requests originating from synchronous <code>require</code>s will block the main thread until the module is resolved. The Workers Vitest pool’s <a href="https://github.com/cloudflare/workers-sdk/blob/main/packages/vitest-pool-workers/src/pool/module-fallback.ts">fallback service</a> implements <a href="https://nodejs.org/api/esm.html#resolution-algorithm">Node-like resolution</a> with Node-style <a href="https://nodejs.org/api/esm.html#interoperability-with-commonjs">interoperability between CommonJS and ES modules</a>.</p>
    <div>
      <h2>Durable Objects as test runners</h2>
      <a href="#durable-objects-as-test-runners">
        
      </a>
    </div>
    <p>Now that we can run and import arbitrary code, the next step is to get Vitest’s thread worker running inside <code>workerd</code>. Every incoming request has its own request context. To improve overall performance, I/O objects such as streams, request/response bodies and WebSockets created in one request context cannot be used from another. This means if we want to use a WebSocket for RPC between the pool and our <code>workerd</code> processes, we need to make sure the WebSocket is only used from one request context. To coordinate this, we define a singleton Durable Object for accepting the RPC connection and running tests from. Functions using RPC such as resolving modules, reporting results and console logging will always use this singleton. We use <a href="https://github.com/cloudflare/miniflare/pull/639">Miniflare’s “magic proxy” system</a> to get a reference to the singleton’s stub in Node.js, and send a WebSocket upgrade request directly to it. After adding a few more Node.js polyfills, and a basic <code>cloudflare:test</code> module to provide access to bindings and a function for creating <code>ExecutionContext</code>s, we’re able to write basic Workers unit tests! 🎉</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2vRactoOowJXYwInIONXC9/68880e0b835a82a299d434f859607a1c/Vitest-Pool-Workers-Architecture--4-.png" />
            
            </figure>
    <div>
      <h2>Integration tests with hot-module-reloading</h2>
      <a href="#integration-tests-with-hot-module-reloading">
        
      </a>
    </div>
    <p>In addition to unit tests, we support integration testing with a special <code>SELF</code> service binding in the <code>cloudflare:test</code> module. This points to a special <code>export default { fetch(...) {...} }</code> handler which uses Vite to import your Worker’s <code>main</code> module.</p><p>Using Vite’s transformation pipeline here means your handler gets hot-module-reloading (HMR) for free! When code is updated, the module cache is invalidated, tests are rerun, and subsequent requests will execute with new code. The same approach of wrapping user code handlers applies to Durable Objects too, providing the same HMR benefits.</p><p>Integration tests can be written by calling <code>SELF.fetch()</code>, which will dispatch a <code>fetch()</code> event to your user code in the same global scope as your test, but under a different request context. This means global mocks apply to your Worker’s execution, as do request context lifetime restrictions. In particular, if you forget to call <code>ctx.waitUntil()</code>, you’ll see an appropriate error message. This wouldn’t be the case if you called your Worker’s handler directly in a unit test, as you’d be running under the runner singleton’s Durable Object request context, whose lifetime is automatically extended.</p>
            <pre><code>// test/index.spec.ts
import { SELF } from "cloudflare:test";
import { it, expect } from "vitest";
import "../src/index";

it("sends request", async () =&gt; {
   const response = await SELF.fetch("https://example.com");
   expect(await response.text()).toMatchInlineSnapshot(`"body"`);
});</code></pre>
            
    <div>
      <h2>Isolated per-test storage</h2>
      <a href="#isolated-per-test-storage">
        
      </a>
    </div>
    <p>Most Workers applications will have at least one binding to a Cloudflare storage service, such as KV, R2 or D1. Ideally, tests should be self-contained and runnable in any order or on their own. To make this possible, writes to storage need to be undone at the end of each test, so reads by other tests aren’t affected. Whilst it’s possible to do this manually, it can be tricky to keep track of all writes and undo them in the correct order. For example, take the following two functions:</p>
            <pre><code>// helpers.ts
interface Env {
  NAMESPACE: KVNamespace;
}
// Get the current list stored in a KV namespace
export async function get(env: Env, key: string): Promise&lt;string[]&gt; {
  return await env.NAMESPACE.get(key, "json") ?? [];
}
// Add an item to the end of the list
export async function append(env: Env, key: string, item: string) {
  const value = await get(env, key);
  value.push(item);
  await env.NAMESPACE.put(key, JSON.stringify(value));
}</code></pre>
            <p>If we wanted to test these functions, we might write something like below. Note we have to keep track of all the keys we might write to, and restore their values at the end of tests, even if those tests fail.</p>
            <pre><code>// helpers.spec.ts
import { env } from "cloudflare:test";
import { beforeAll, beforeEach, afterEach, it, expect } from "vitest";
import { get, append } from "./helpers";

let startingList1: string | null;
let startingList2: string | null;
beforeEach(async () =&gt; {
  // Store values before each test
  startingList1 = await env.NAMESPACE.get("list 1");
  startingList2 = await env.NAMESPACE.get("list 2");
});
afterEach(async () =&gt; {
  // Restore starting values after each test
  if (startingList1 === null) {
    await env.NAMESPACE.delete("list 1");
  } else {
    await env.NAMESPACE.put("list 1", startingList1);
  }
  if (startingList2 === null) {
    await env.NAMESPACE.delete("list 2");
  } else {
    await env.NAMESPACE.put("list 2", startingList2);
  }
});

beforeAll(async () =&gt; {
  await append(env, "list 1", "one");
});

it("appends to one list", async () =&gt; {
  await append(env, "list 1", "two");
  expect(await get(env, "list 1")).toStrictEqual(["one", "two"]);
});

it("appends to two lists", async () =&gt; {
  await append(env, "list 1", "three");
  await append(env, "list 2", "four");
  expect(await get(env, "list 1")).toStrictEqual(["one", "three"]);
  expect(await get(env, "list 2")).toStrictEqual(["four"]);
});</code></pre>
            <p>This is slightly easier with the recently introduced <a href="https://vitest.dev/api/#ontestfinished"><code>onTestFinished()</code> hook</a>, but you still need to remember which keys were written to, or enumerate them at the start/end of tests. You’d also need to manage this for KV, R2, Durable Objects, caches and any other storage service you used. Ideally, the testing framework should just manage this all for you.</p><p>That’s exactly what the Workers Vitest pool does with the <code>isolatedStorage</code> option which is enabled by default. Any writes to storage performed in a test are automagically undone at the end of the test. To support seeding data in <code>beforeAll()</code> hooks, including those in nested <code>describe()</code>-blocks, a stack is used. Before each suite or test, a new frame is pushed to the storage stack. All writes performed by the test or associated <code>beforeEach()</code>/<code>afterEach()</code> hooks are written to the frame. After each suite or test, the top frame is popped from the storage stack, undoing any writes.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4Ixe0KPm6lrn7dvt7N1AhY/525418edee96350e76dffebf7c95895d/Untitled--3--1.png" />
            
            </figure><p>Miniflare implements simulators for storage services <a href="https://github.com/cloudflare/miniflare/pull/656">on top of Durable Objects</a> with <a href="https://github.com/cloudflare/miniflare/discussions/525">a separate blob store</a>. When running locally, <code>workerd</code> uses SQLite for Durable Object storage. To implement isolated storage, we implement an on-disk stack of <code>.sqlite</code> database files by backing up the databases when “pushing”, and restoring backups when “popping”. Blobs stored in the separate store are retained through stack operations, and cleaned up at the end of each test run. Whilst this works, it involves copying lots of <code>.sqlite</code> files. Looking ahead, we’d like to explore using SQLite <a href="https://www.sqlite.org/lang_savepoint.html"><code>SAVEPOINTS</code></a> for a more efficient solution.</p>
    <div>
      <h2>Declarative request mocking</h2>
      <a href="#declarative-request-mocking">
        
      </a>
    </div>
    <p>In addition to storage, most Workers will make outbound <code>fetch()</code> requests. For tests, it’s often useful to mock responses to these requests. Miniflare already allows you to specify an <a href="https://undici.nodejs.org/#/docs/api/MockAgent"><code>undici</code> <code>MockAgent</code></a> to route all requests through. The <code>MockAgent</code> class provides a declarative interface for specifying requests to mock and the corresponding responses to return. This API is relatively simple, whilst being flexible enough for advanced use cases. We provide an instance of <code>MockAgent</code> as <code>fetchMock</code> in the <code>cloudflare:test</code> module.</p>
            <pre><code>import { fetchMock } from "cloudflare:test";
import { beforeAll, afterEach, it, expect } from "vitest";

beforeAll(() =&gt; {
  // Enable outbound request mocking...
  fetchMock.activate();
  // ...and throw errors if an outbound request isn't mocked
  fetchMock.disableNetConnect();
});
// Ensure we matched every mock we defined
afterEach(() =&gt; fetchMock.assertNoPendingInterceptors());

it("mocks requests", async () =&gt; {
  // Mock the first request to `https://example.com`
  fetchMock
    .get("https://example.com")
    .intercept({ path: "/" })
    .reply(200, "body");

  const response = await fetch("https://example.com/");
  expect(await response.text()).toBe("body");
});</code></pre>
            <p>To implement this, we bundled a stripped down version of <code>undici</code> containing just the <code>MockAgent</code> code. We then <a href="https://github.com/cloudflare/workers-sdk/blob/main/packages/vitest-pool-workers/src/worker/fetch-mock.ts">built a custom <code>undici</code> <code>Dispatcher</code></a> that used the Worker’s global <code>fetch()</code> function instead of <code>undici</code>’s built-in HTTP implementation based on <a href="https://github.com/nodejs/llhttp"><code>llhttp</code></a> and <a href="https://nodejs.org/api/net.html"><code>node:net</code></a>.</p>
    <div>
      <h2>Testing Durable Objects directly</h2>
      <a href="#testing-durable-objects-directly">
        
      </a>
    </div>
    <p>Finally, Miniflare v2’s custom Vitest environment provided support for accessing the instance methods and state of Durable Objects in tests directly. This allowed you to unit test Durable Objects like any other JavaScript class—you could mock particular methods and properties, or immediately call specific handlers like <code>alarm()</code>. To implement this in <code>workerd</code>, we rely on our existing wrapping of user Durable Objects for Vite transforms and hot-module reloading. When you call the <code>runInDurableObject(stub, callback)</code> function from <code>cloudflare:test</code>, we store <code>callback</code> in a global cache and send a special <code>fetch()</code> request to <code>stub</code> which is intercepted by the wrapper. The wrapper executes the <code>callback</code> in the request context of the Durable Object, and stores the result in the same cache. <code>runInDurableObject()</code> then reads from this cache, and returns the result.</p><p>Note that this assumes the Durable Object is running in the same isolate as the <code>runInDurableObject()</code> call. While this is true for same-Worker Durable Objects running locally, it means Durable Objects defined in auxiliary workers can’t be accessed directly.</p>
    <div>
      <h2>Try it out!</h2>
      <a href="#try-it-out">
        
      </a>
    </div>
    <p>We are excited to release the <code>@cloudflare/vitest-pool-workers</code> package on npm, and to provide an improved testing experience for you.</p><p>Make sure to read the <a href="https://developers.cloudflare.com/workers/testing/vitest-integration/get-started/write-your-first-test/">Write your first test guide</a> and begin writing unit and integration tests today! If you’ve been writing tests using one of our previous options, our <code>unstable_dev</code> <a href="https://developers.cloudflare.com/workers/testing/vitest-integration/get-started/migrate-from-unstable-dev/">migration guide</a> or our Miniflare 2 <a href="https://developers.cloudflare.com/workers/testing/vitest-integration/get-started/migrate-from-miniflare-2/">migration guide</a> should explain key differences and help you move your tests over quickly.</p><p>If you run into issues or have suggestions for improvements, please <a href="https://github.com/cloudflare/workers-sdk/issues/new/choose">file an issue</a> in our GitHub repo or reach out via our <a href="https://discord.com/invite/cloudflaredev">Developer Discord</a>.</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Testing]]></category>
            <guid isPermaLink="false">P0mpqczsiU6cJvsOQWpbi</guid>
            <dc:creator>Brendan Coll</dc:creator>
            <dc:creator>Adam Murray</dc:creator>
        </item>
        <item>
            <title><![CDATA[Better debugging for Cloudflare Workers, now with breakpoints]]></title>
            <link>https://blog.cloudflare.com/debugging-cloudflare-workers/</link>
            <pubDate>Tue, 28 Nov 2023 14:00:20 GMT</pubDate>
            <description><![CDATA[ We provide many tools to help you debug Cloudflare Workers; from your local environment all the way into production. In this post, we highlight some of the tools we currently offer, and do a deep dive into one specific area - breakpoint debugging - a tool we recently added into our workerd runtime ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2kmdQgGjQDnMeJ0amrvTDS/9577ec3eefd6e91d3e9a3aeb76e9f299/Debugging-1.png" />
            
            </figure><p>As developers, we’ve all experienced times when our code doesn’t work like we expect it to. Whatever the root cause is, being able to quickly dive in, diagnose the problem, and ship a fix is invaluable.</p><p>If you’re developing with Cloudflare Workers, we provide many tools to help you debug your applications; from your local environment all the way into production. This additional insight helps save you time and resources and provides visibility into how your application actually works — which can help you optimize and refactor code even before it goes live.</p><p>In this post, we’ll explore some of the tools we currently offer, and do a deep dive into one specific area — breakpoint debugging — looking at not only how to use it, but how we recently implemented it in our runtime, <a href="https://github.com/cloudflare/workerd">workerd</a>.</p>
    <div>
      <h2>Available Debugging Tools</h2>
      <a href="#available-debugging-tools">
        
      </a>
    </div>
    
    <div>
      <h3>Logs</h3>
      <a href="#logs">
        
      </a>
    </div>
    <p><code>console.log</code>. It might be the simplest tool for a developer to debug, but don’t underestimate it. Built into the Cloudflare runtime is node-like logging, which provides detailed, color-coded logs. Locally, you can view these logs in a terminal window, and they will look like this:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6FOAbByfvb94W0iinSF3dp/47b7086fcbf1ff54a39ae39fb09e6f95/image5-2.png" />
            
            </figure><p>Outside local development, once your Worker is deployed, <code>console.log</code> statements are visible via the Real-time Logs interface in the Cloudflare Dashboard or via the Workers CLI tool, <a href="https://developers.cloudflare.com/workers/wrangler/install-and-update/">Wrangler</a>, using the <a href="https://developers.cloudflare.com/workers/wrangler/commands/#tail"><code>wrangler tail</code></a> command. Each log that comes through <code>wrangler tail</code> is structured JSON, and the command has options to filter and search incoming logs to make results as relevant as possible.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6PA8wVYsgB1hkhz6zyhk97/17410babcdcbfef6bc8ef74a261b7c12/image2-4.png" />
            
            </figure><p>If you’d like to send these logs to third-parties for processing and storage, you can leverage <a href="https://developers.cloudflare.com/workers/observability/logpush/">Workers Trace Events Logpush</a> which supports a variety of <a href="https://developers.cloudflare.com/logs/get-started/enable-destinations/">destinations</a>.</p>
    <div>
      <h3>DevTools</h3>
      <a href="#devtools">
        
      </a>
    </div>
    <p>In addition to logging, you can also leverage <a href="https://github.com/cloudflare/workers-sdk/tree/main/packages/wrangler-devtools">our implementation</a> of <a href="https://developer.chrome.com/docs/devtools/overview/">Chrome’s DevTools</a> to do things like view and debug network requests, take memory heap snapshots, and monitor CPU usage.</p><p>This interactive tool provides even further insight and information about your Cloudflare Workers, and can be started from within Wrangler by running <a href="https://developers.cloudflare.com/workers/wrangler/commands/#dev"><code>wrangler dev</code></a> and pressing <b>[d]</b> once the dev server is spun up. It can also be accessed by the editor that is built into the <a href="https://dash.cloudflare.com/login?redirect_uri=https%3A%2F%2Fdash.cloudflare.com%2F%3Faccount%3Dworkers">Cloudflare Dashboard</a> or the <a href="https://workers.new">Workers Playground</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5FjYb3g7ceyAbIa5gmgPPb/3f94eda9e0ccb498daed4c1fc01b40bb/image6-1.png" />
            
            </figure>
    <div>
      <h3>Breakpoints</h3>
      <a href="#breakpoints">
        
      </a>
    </div>
    <p>Breakpoints allow developers to stop code execution at specific points (lines) to evaluate what is happening. This is great for situations where you might have a race condition or times when you don’t know exactly what is happening, and your code isn’t behaving as expected. Breakpoints allow you to walk through your code line by line to see how it behaves.</p><div>
  
</div><p>You can get started with breakpoint debugging from within the Wrangler CLI by running <a href="https://developers.cloudflare.com/workers/wrangler/commands/#dev"><code>wrangler dev</code></a> and pressing <b>[d]</b> to open up a DevTools debugger session. If you prefer to debug via your IDE, we support VSCode and WebStorm.</p><p><b>Setting up VSCode</b>To set up VSCode to debug Cloudflare Workers with breakpoints, you’ll need to create a new <code>.vscode/launch.json</code> file with the following content:</p>
            <pre><code>{
  "configurations": [
    {
  "name": "Wrangler",
  "type": "node",
  "request": "attach",
  "port": 9229,
  "cwd": "/",
  "resolveSourceMapLocations": null,
  "attachExistingChildren": false,
  "autoAttachChildProcesses": false
    }
  ]
}</code></pre>
            <p>Once you’ve created this configuration in <code>launch.json</code>, open your project in VSCode. Open a new terminal window from VSCode, and run <code>npx wrangler dev</code> to start a local dev server.</p><p>At the top of the <b>Run &amp; Debug</b> panel, you should see an option to select a configuration. Choose <b>Wrangler</b>, and select the play icon. You should see <b>Wrangler: Remote Process [0]</b> show up in the Call Stack panel on the left. Go back to a <b>.js</b> or <b>.ts</b> file in your project and add at least one breakpoint.</p><p>Open your browser and go to the Worker’s local URL (default <a href="http://127.0.0.1:8787">http://127.0.0.1:8787</a>). The breakpoint should be hit, and you should see details about your code at the specified line.</p><p><b>Setting up WebStorm</b>To set up WebStorm with breakpoint debugging, create a new “Attach to Node.js/Chrome” Debug Configuration, setting the port to <code>9229</code>:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4DTxZCPd3CPizjkeZoSeKv/17b9aeb346b798d02755b7a463485a90/image4-2.png" />
            
            </figure><p>Run <code>npx wrangler dev</code> to start a local dev server, then start the Debug Configuration:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4TDefT0FNe3cWNuPvTzxSK/7656e30ced53a2f15d504c74703d438f/Screenshot-2023-11-28-at-10.07.57.png" />
            
            </figure><p>Add a breakpoint, then open your browser and go to the Worker’s local URL (default <a href="http://127.0.0.1:8787">http://127.0.0.1:8787</a>). The breakpoint should be hit, and you should see details about your code at the specified line.</p>
    <div>
      <h2>How we enabled breakpoint debugging via workerd</h2>
      <a href="#how-we-enabled-breakpoint-debugging-via-workerd">
        
      </a>
    </div>
    <p>Both <a href="/workerd-open-source-workers-runtime/">workerd</a> and Cloudflare Workers embed <a href="https://v8.dev/">V8</a> to run workers code written in JavaScript and WASM. V8 is a component of the world’s most widely used web browser today, <a href="https://www.google.com/chrome/">Google Chrome</a>, and it is also widely used embedded into open source projects like <a href="https://nodejs.org/">Node.js</a>.</p><p>The Google Chrome team has created a set of web developer tools, <a href="https://developer.chrome.com/docs/devtools/">Chrome DevTools</a>, that are built directly into the browser. These provide a wide range of features for inspecting, debugging, editing, and optimizing web pages. Chrome DevTools are exposed through a UI in Chrome that talks to the components of the browser, such as V8, using the <a href="https://chromedevtools.github.io/devtools-protocol/">Chrome DevTools Protocol</a> (CDP). The protocol uses JSON-RPC transmitted over a websocket to exchange messages and notifications between clients, like the DevTools UI, and the components of Chrome. Within Chrome Devtools protocols are domains (DOM, Debugger, Media) that group related commands by functionality that can be implemented by different components in Chrome.</p><p>V8 supports the following CDP domains:</p><ul><li><p>Runtime</p></li><li><p>Debugger</p></li><li><p>Profiler</p></li><li><p>HeapProfiler</p></li></ul><p>These domains are available to all projects that embed V8, including workerd, so long as the embedding application is able to route messages between a DevTools client and V8. DevTools clients use the Debugger domain to implement debugging functionality. The Debugger domain exposes all the commands to debug an application, such as setting breakpoints. It also sends debugger events, like hitting a breakpoint, up to DevTools clients, so they can present the state of the script in a debugger UI.</p><p>While workerd has supported CDP since its first release, support for the Debugger domain is new. The Debugger domain differs from the other domains exposed by V8 because it requires the ability to suspend the execution of a script whilst it is being debugged. This presents a complication for introducing breakpoint debugging in workerd, because workerd runs each Worker in a V8 isolate in which there is just a single thread that receives incoming requests and runs the scripts associated with them.</p><p>Why is this a problem? Workerd uses an event-driven programming model and its single thread is responsible for both responding to incoming requests and for running JavaScript / WASM code. In practice, this is implemented via an event loop that sits at the bottom of the call stack that sends and receives network messages and calls event handlers that run JavaScript code. The thread needs to fall back into the event loop after running event handlers to be able to process network messages. However, the V8 API for handling breakpoints expects execution to be suspended within a method implemented by the embedder that is called from V8 when a breakpoint is hit. This method is called from the event handler that is running JavaScript in V8. Unfortunately, this prevents the workerd thread from falling back into the event loop and processing any incoming network events, including all CDP commands relating to debugging. So if a client asks to resume execution by sending a CDP command, it cannot be relayed to the executing thread because it is unable to fall into the eventloop whilst in a breakpoint.</p><p>We solved this event processing problem by adding an I/O thread to workerd. The I/O thread handles sending and receiving CDP messages, because the thread executing JavaScript can be suspended due to hitting a breakpoint or a JavaScript `debugger` statement. The I/O thread wakes the JavaScript thread when CDP commands arrive and also handles sending responses back to the CDP client. Conceptually, this was not difficult, but it required some careful synchronization to avoid dropped messages.</p>
    <div>
      <h2>Use the Source</h2>
      <a href="#use-the-source">
        
      </a>
    </div>
    <p>When debugging, JavaScript developers expect to see their source code in the debugger. For this to work, the embedded V8 needs to be able to locate sources. It is common for JavaScript code to be generated either by combining and minifying multiple JavaScript sources, or by transpiling to JavaScript from another language, such as <a href="https://www.typescriptlang.org/">TypeScript</a>, <a href="https://dart.dev/">Dart</a>, <a href="https://coffeescript.org/">CoffeeScript</a>, or <a href="https://elm-lang.org/">Elm</a>. To render the source code in the debugger in its original form, the embedded V8 needs to know 1) where the source code came from and 2) how any given line of JavaScript visible to V8 maps back to the original sources before any transformation of the original sources was applied. The standard solution to this problem is to embed a <a href="https://firefox-source-docs.mozilla.org/devtools-user/debugger/how_to/use_a_source_map/index.html">source map</a> into the JavaScript code that JavaScript engine runs. The embedding is performed through a special comment in the JavaScript running in the JavaScript engine:</p><p><code>//# sourceMappingURL=generated.js.map</code></p><p>This source map’s URL is resolved relative to the source URL. This can be set when instantiating a source file with the V8 API, or via another special comment:</p><p><code>//# sourceURL=file:///absolute/path/to/generated.js</code></p><p>An example source map looks something like this:</p>
            <pre><code>{
  "version": 3,
  "sources": ["../src/index.ts"],
  "sourcesContent": ["interface Env { ... }\n\nexport default ..."],
  "mappings": ";AAIA,IAAO,mBAA8B;AAAA,EACjC,MAAM,MAAM,SAAS,KAAK,KAAK;...",
  "names": []
}</code></pre>
            <p>Each of the relative paths in <code>sources</code> are resolved relative to the source map’s fully-qualified URL. When DevTools connects to V8 and enables the Debugger domain, V8 will send information on all parsed scripts including the source map’s fully-qualified URL. In our example, this would be <code>file:///absolute/path/to/generated.js.map</code>. DevTools needs to fetch this URL along with source URLs to perform source mapping. Unfortunately, our patched version of DevTools is hosted at <a href="https://devtools.devprod.cloudflare.dev/">https://devtools.devprod.cloudflare.dev/</a>, and browsers prohibit fetching <code>file://</code> URLs from non-<code>file://</code> origins for security reasons. However, we need to use <code>file://</code> URLs so IDEs like Visual Studio Code can match up source files from source maps to files on disk. To get around this, we used Wrangler's inspector proxy to rewrite the CDP script parsed messages sent by V8 to use a different protocol if the <code>User-Agent</code> of the inspector WebSocket handshake is a browser.</p><p>Now that we can set breakpoints and fetch source maps, DevTools works as normal. When a user tries to set a breakpoint in an original source file, DevTools will use the map’s <code>mappings</code> to find the location in the generated JavaScript file and set a breakpoint there. This is the opposite problem to source mapping error stack traces. When V8 hits this JavaScript breakpoint, DevTools will pause on the location in the original source file. Stepping through the source file requires mapping the stepped-over segment to generated code, sending the step-over command to V8, then mapping back the new paused location in generated code to the original source file.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4biqz5FNB0gTzSFbvM3O9B/5a9d60f06cab849c4b56a14b164600d4/image3-5.png" />
            
            </figure><p><i>(sequence diagram showing process of setting, hitting, and stepping over breakpoints) (</i><a href="https://mermaid.live/edit#pako:eNq1VUtvEzEQ_iuWTyClG1DUA6sqh6pCQmpLlRJxqHNw1pONidde_AitVvnvjOPdNgmbEgTsyfbMfN88dxpaGAE0pw6-B9AFXEleWl4xTfDjhTeWTB3YdK-59bKQNdeeXMH6izHK_Sr5arkuVZ_ND2NXYEUSdABn43FnkePjPJQl2Aw0nytImp0YNVuEnCRJez3rx3CFlbW_49aBuJjbcUOcCbaAG15PJ9eIQRdSQT4cZlk2lFrAY_bNZRWvGR0QfCObA36k6bz-I5rkZkt0EYIU4wOK3mTcgo-WmTJctOcJJOzEE6w6DX4ngy8BNMTDo48ADWOMrsE6aXQ85qOtNaOdfWyBPdt78OTSAl_VRmofvXmTEuhd_uHtKQV24F8ALp-mVu3F1FOZGJOSGm5DNY9Q56NjMR7pkl0_GjJ_Zv8UNen7_HyUv8t7iV_NYxJp44FYWS49MYttwmKWtHBkEkfL-VM6tubhuYkKrtRHHEVAigd0ZzYgUbCUO3mLotc9n3Wu4yzLNUcf94awv7UP6oeyFM_d1r1jLeGhJp_X3dz_pvqoHHXbeVnJ-lo67MUHvHj8Y8QC7deabNpqz04veD-3BReqLgwB_yIxk13Ivyjx_yrWsSiZpgNaga24FLgEmvjKqF9CBfgXwKOABQ_KM8r0BlV58Ob-SRc09zbAgIZaIGa7M7pHEBLXxk3aK9v1svkJ1EsiBw"><i>mermaid URL</i></a><i>)</i></p>
    <div>
      <h2>Future Work</h2>
      <a href="#future-work">
        
      </a>
    </div>
    <p>Both the Visual Studio Code and WebStorm configurations for breakpoint debugging require attaching to an <i>existing</i> dev server. It would be great if your IDE could <i>launch</i> the dev server too, and automatically attach to it.</p><p>When you debug a Node.js program in Visual Studio Code or WebStorm, an additional <a href="https://nodejs.org/api/cli.html#-r---require-module"><code>--require</code></a> hook is added to the <a href="https://nodejs.org/api/cli.html#node_optionsoptions"><code>NODE_OPTIONS</code></a> environment variable. This hook registers the process’s inspector URL with the editor over a well-known socket. This means if your Node.js process spawns another Node.js child process, your editor will debug that child process too. This is how Visual Studio Code’s <a href="https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_javascript-debug-terminal">JavaScript Debug Terminal</a> works, and is how editors can debug Node.js processes started by npm scripts.</p><p>Our plan is to detect this <code>--require</code> hook, and register <code>workerd</code> child processes started by Wrangler and Miniflare. This will mean you can debug <code>npm</code> launch tasks, without having to worry about starting the dev server and then attaching to it.</p>
    <div>
      <h2>Start debugging!</h2>
      <a href="#start-debugging">
        
      </a>
    </div>
    <p>All the debugging tools listed above are ready to be used today. Logs and DevTools can be accessed either by logging into the Cloudflare dashboard or by downloading <a href="https://www.npmjs.com/package/wrangler">Wrangler</a>, the command-line tool for the Cloudflare Developer Platform. Breakpoint debugging and Node-style logging is built into the latest version of Wrangler, and can be accessed by running <code>npx wrangler@latest dev</code> in a terminal window. Let us know what you think in the #wrangler channel on the <a href="https://discord.gg/cloudflaredev">Cloudflare Developers Discord</a>, and please <a href="https://github.com/cloudflare/workers-sdk/issues/new/choose">open a GitHub issue</a> if you hit any unexpected behavior.</p> ]]></content:encoded>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developers]]></category>
            <guid isPermaLink="false">1wZwoTGB5bvoUK93vzeTWx</guid>
            <dc:creator>Adam Murray</dc:creator>
            <dc:creator>Brendan Coll</dc:creator>
        </item>
        <item>
            <title><![CDATA[Improved local development with wrangler and workerd]]></title>
            <link>https://blog.cloudflare.com/wrangler3/</link>
            <pubDate>Wed, 17 May 2023 13:00:15 GMT</pubDate>
            <description><![CDATA[ We’re proud to announce the release of Wrangler v3 – the first version of Wrangler with local-by-default development, powered by Miniflare v3 and the open-source Workers `workerd` runtime. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3iSHHNyNYsb21AEw80h3lW/953b982411c18fcb0721afc8dd83ac7e/image5-7.png" />
            
            </figure><p>For over a year now, we’ve been working to improve the Workers local development experience. Our goal has been to improve parity between users' local and production environments. This is important because it provides developers with a fully-controllable and easy-to-debug local testing environment, which leads to increased developer efficiency and confidence.</p><p>To start, we integrated <a href="https://github.com/cloudflare/miniflare">Miniflare</a>, a fully-local simulator for Workers, directly <a href="/miniflare/">into Wrangler</a>, the Workers CLI. This allowed users to develop locally with Wrangler by running <code>wrangler dev --local</code>. Compared to the <code>wrangler dev</code> default, which relied on remote resources, this represented a significant step forward in local development. As good as it was, it couldn’t leverage the actual Workers runtime, which led to some inconsistencies and behavior mismatches.</p><p>Last November, we <a href="/miniflare-and-workerd/">announced the experimental version of Miniflare v3,</a> powered by the newly open-sourced <a href="https://github.com/cloudflare/workerd"><code>workerd</code> runtime</a>, the same runtime used by Cloudflare Workers. Since then, we’ve continued to improve upon that experience both in terms of accuracy with the real runtime and in cross-platform compatibility.</p><p>As a result of all this work, we are proud to announce the release of Wrangler v3 – the first version of Wrangler with local-by-default development.</p>
    <div>
      <h2>A new default for Wrangler</h2>
      <a href="#a-new-default-for-wrangler">
        
      </a>
    </div>
    <p>Starting with Wrangler v3, users running <code>wrangler dev</code> will be leveraging Miniflare v3 to run your Worker locally. This local development environment is effectively as accurate as a production Workers environment, providing an ability for you to test every aspect of your application before deploying. It provides the same runtime and bindings, but has its own simulators for KV, R2, D1, Cache and Queues. Because you’re running everything on your machine, you won’t be billed for operations on KV namespaces or R2 buckets during development, and you can try out paid-features like Durable Objects for free.</p><p>In addition to a more accurate developer experience, you should notice performance differences. Compared to remote mode, we’re seeing a 10x reduction to startup times and 60x reduction to script reload times with the new local-first implementation. This massive reduction in reload times drastically improves developer velocity!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3iwuiO3yvOuQQLFa9DbQZU/21379c38d9ce9a73e0f7a1c6eb8fbfb4/image4-12.png" />
            
            </figure><p>Remote development isn’t going anywhere. We recognise many developers still prefer to test against real data, or want to test Cloudflare services like <a href="https://developers.cloudflare.com/images/image-resizing/resize-with-workers">image resizing</a> that aren’t implemented locally yet. To run <code>wrangler dev</code> on Cloudflare’s network, just like previous versions, use the new <code>--remote</code> flag.</p>
    <div>
      <h2>Deprecating Miniflare v2</h2>
      <a href="#deprecating-miniflare-v2">
        
      </a>
    </div>
    <p>For users of Miniflare, there are two important pieces of information for those updating from v2 to v3. First, if you’ve been using Miniflare’s CLI directly, you’ll need to switch to <code>wrangler dev</code>. Miniflare v3 no longer includes a CLI. Secondly, if you’re using Miniflare’s API directly, upgrade to <code>miniflare@3</code> and follow the <a href="https://miniflare.dev/get-started/migrating">migration guide</a>.</p>
    <div>
      <h2>How we built Miniflare v3</h2>
      <a href="#how-we-built-miniflare-v3">
        
      </a>
    </div>
    <p>Miniflare v3 is now built using <code>workerd</code>, the open-source Cloudflare Workers runtime. As <code>workerd</code> is a server-first runtime, every configuration defines at least one socket to listen on. Each socket is configured with a service, which can be an external server, disk directory or most importantly for us, a Worker! To start a <code>workerd</code> server running a Worker, create a <code>worker.capnp</code> file as shown below, run <code>npx workerd serve worker.capnp</code> and visit <a href="http://localhost:8080">http://localhost:8080</a> in your browser:</p>
            <pre><code>using Workerd = import "/workerd/workerd.capnp";


const helloConfig :Workerd.Config = (
 services = [
   ( name = "hello-worker", worker = .helloWorker )
 ],
 sockets = [
   ( name = "hello-socket", address = "*:8080", http = (), service = "hello-worker" )
 ]
);


const helloWorker :Workerd.Worker = (
 modules = [
   ( name = "worker.mjs",
     esModule =
       `export default {
       `  async fetch(request, env, ctx) {
       `    return new Response("Hello from workerd! 👋");
       `  }
       `}
   )
 ],
 compatibilityDate = "2023-04-04",
);</code></pre>
            <p>If you’re interested in what else <code>workerd</code> can do, check out the <a href="https://github.com/cloudflare/workerd/tree/main/samples">other samples</a>. Whilst <code>workerd</code> provides the runtime and bindings, it doesn’t provide the underlying implementations for the other products in the Developer Platform. This is where Miniflare comes in! It provides simulators for KV, R2, D1, Queues and the Cache API.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/44vdcPO7sdaTtBi0u0HMgE/85e6510a0f8689284add4318e09c4c2c/image1-43.png" />
            
            </figure>
    <div>
      <h3>Building a flexible storage system</h3>
      <a href="#building-a-flexible-storage-system">
        
      </a>
    </div>
    <p>As you can see from the diagram above, most of Miniflare’s job is now providing different interfaces for data storage. In Miniflare v2, we used a custom key-value store to back these, but this had <a href="https://github.com/cloudflare/miniflare/issues/167">a</a> <a href="https://github.com/cloudflare/miniflare/issues/247">few</a> <a href="https://github.com/cloudflare/miniflare/issues/530">limitations</a>. For Miniflare v3, we’re now using the industry-standard <a href="https://sqlite.org/index.html">SQLite</a>, with a separate blob store for KV values, R2 objects, and cached responses. Using SQLite gives us much more flexibility in the queries we can run, allowing us to support future unreleased storage solutions. 👀</p><p>A separate blob store allows us to provide efficient, ranged, <a href="https://streams.spec.whatwg.org/#example-rbs-pull">streamed access</a> to data. Blobs have unguessable identifiers, can be deleted, but are otherwise immutable. These properties make it possible to perform atomic updates with the SQLite database. No other operations can interact with the blob until it's committed to SQLite, because the ID is not guessable, and we don't allow listing blobs. For more details on the rationale behind this, check out the <a href="https://github.com/cloudflare/miniflare/discussions/525">original GitHub discussion</a>.</p>
    <div>
      <h3>Running unit tests inside Workers</h3>
      <a href="#running-unit-tests-inside-workers">
        
      </a>
    </div>
    <p>One of Miniflare’s primary goals is to provide a great local testing experience. Miniflare v2 provided <a href="https://miniflare.dev/testing/vitest">custom environments</a> for popular Node.js testing frameworks that allowed you to run your tests <i>inside</i> the Miniflare sandbox. This meant you could import and call any function using Workers runtime APIs in your tests. You weren’t restricted to integration tests that just send and receive HTTP requests. In addition, these environments provide per-test isolated storage, automatically undoing any changes made at the end of each test.</p><p>In Miniflare v2, these environments were relatively simple to implement. We’d already reimplemented Workers Runtime APIs in a Node.js environment, and could inject them using Jest and Vitest’s APIs into the global scope.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6UrAr6zl1SsIbG2Qyvq1p2/40113914d049e7ad928c16373dab7fa7/image3-13.png" />
            
            </figure><p>For Miniflare v3, this is much trickier. The runtime APIs are implemented in a separate <code>workerd</code> process, and you can’t reference JavaScript classes across a process boundary. So we needed a new approach…</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/44s7Z0ZD3r5hQpdCxr1atZ/8b1d395872b13a1123cf77e25ab07533/image7-7.png" />
            
            </figure><p>Many test frameworks like Vitest use Node’s built-in <a href="https://nodejs.org/api/worker_threads.html"><code>worker_threads</code></a> module for running tests in parallel. This module spawns new operating system threads running Node.js and provides a <code>MessageChannel</code> interface for communicating between them. What if instead of spawning a new OS thread, we spawned a new <code>workerd</code> process, and used WebSockets for communication between the Node.js host process and the <code>workerd</code> “thread”?</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5jGThLJfIpVq47I9KaxaS3/86a1ff8b9739f21e6629eb8f8b793ffa/image8-8.png" />
            
            </figure><p>We have a proof of concept using Vitest showing this approach can work in practice. Existing Vitest IDE integrations and the Vitest UI continue to work without any additional work. We aren’t quite ready to release this yet, but will be working on improving it over the next few months. Importantly, the <code>workerd</code> “thread” needs access to Node.js built-in modules, which we recently started <a href="/workers-node-js-asynclocalstorage/">rolling out support for</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/HqXRYKmlaionjMJK7PW6i/974cb97c5b694db5c3f567f628d861ed/image2-23.png" />
            
            </figure>
    <div>
      <h3>Running on every platform</h3>
      <a href="#running-on-every-platform">
        
      </a>
    </div>
    <p>We want developers to have this great local testing experience, regardless of which operating system they’re using. Before open-sourcing, the Cloudflare Workers runtime was originally only designed to run on Linux. For Miniflare v3, we needed to add support for macOS and Windows too. macOS and Linux are both Unix-based, making porting between them relatively straightforward. Windows on the other hand is an entirely different beast… 😬</p><p>The <code>workerd</code> runtime uses <a href="https://github.com/capnproto/capnproto/tree/master/c%2B%2B/src/kj">KJ</a>, an alternative C++ base library, which is already cross-platform. We’d also migrated to the <a href="https://bazel.build/">Bazel</a> build system in preparation for open-sourcing the runtime, which has good Windows support. When compiling our C++ code for Windows, we use LLVM's MSVC-compatible compiler driver <a href="https://llvm.org/devmtg/2014-04/PDFs/Talks/clang-cl.pdf"><code>clang-cl</code></a>, as opposed to using Microsoft’s Visual C++ compiler directly. This enables us to use the "same" compiler frontend on Linux, macOS, and Windows, massively reducing the effort required to compile <code>workerd</code> on Windows. Notably, this provides proper support for <code>#pragma once</code> when using symlinked virtual includes produced by Bazel, <code>__atomic_*</code> functions, a standards-compliant preprocessor, GNU statement expressions used by some KJ macros, and understanding of the <code>.c++</code> extension by default. After switching out <a href="https://github.com/mrbbot/workerd/blob/5e10e308e6683f8f88833478801c07da4fe01063/src/workerd/server/workerd.c%2B%2B#L802-L808">unix API calls for their Windows equivalents</a> using <code>#if _WIN32</code> preprocessor directives, and fixing a bunch of segmentation faults caused by execution order differences, we were finally able to get <code>workerd</code> running on Windows! No WSL or Docker required! 🎉</p>
    <div>
      <h2>Let us know what you think!</h2>
      <a href="#let-us-know-what-you-think">
        
      </a>
    </div>
    <p>Wrangler v3 is now generally available! Upgrade by running <code>npm install --save-dev wrangler@3</code> in your project. Then run <code>npx wrangler dev</code> to try out the new local development experience powered by Miniflare v3 and the open-source Workers runtime. Let us know what you think in the <code>#wrangler</code> channel on the <a href="https://discord.com/invite/cloudflaredev">Cloudflare Developers Discord</a>, and please <a href="https://github.com/cloudflare/workers-sdk/issues/new/choose">open a GitHub issue</a> if you hit any unexpected behavior.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Wrangler]]></category>
            <category><![CDATA[Miniflare]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">6XGVmk1ZbylTfVULuFs2jk</guid>
            <dc:creator>Brendan Coll</dc:creator>
            <dc:creator>Adam Murray</dc:creator>
        </item>
        <item>
            <title><![CDATA[Doubling down on local development with Workers: Miniflare meets workerd]]></title>
            <link>https://blog.cloudflare.com/miniflare-and-workerd/</link>
            <pubDate>Fri, 18 Nov 2022 14:00:00 GMT</pubDate>
            <description><![CDATA[ Today, we’re taking local development to the next level by releasing Miniflare 3, powered by the open-source workerd runtime, along with support for migrating existing dashboard projects and using real data locally. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/dwWDZZWvAwOWqtzMwqqA8/0ed1217e005b7d723b60acf47de62e95/image3-38.png" />
            
            </figure><p>Local development gives you a fully-controllable and easy-to-debug testing environment. At the start of this year, we brought this experience to Workers developers by <a href="/miniflare/">launching Miniflare 2.0</a>: a local Cloudflare Workers simulator. Miniflare 2 came with features like step-through debugging support, detailed <code>console.log</code>s, pretty <a href="https://miniflare.dev/developing/source-maps">source-mapped</a> error pages, <a href="https://miniflare.dev/developing/live-reload">live reload</a> and a highly-configurable <a href="https://miniflare.dev/testing/jest">unit testing environment</a>. Not only that, but we also incorporated Miniflare into Wrangler, our Workers CLI, to enable <code>wrangler dev</code>’s --<code>local</code> mode.</p><p>Today, we’re taking local development to the next level! In addition to introducing new support for migrating existing projects to your local development environment, we're making it easier to work with your remote data—locally! Most importantly, we're releasing a much more accurate Miniflare 3, powered by the <a href="/workerd-open-source-workers-runtime/">recently open-sourced <code>workerd</code> runtime</a>—the same runtime used by Cloudflare Workers!</p>
    <div>
      <h3>Enabling local development with workerd</h3>
      <a href="#enabling-local-development-with-workerd">
        
      </a>
    </div>
    <p>One of the superpowers of having a local development environment is that you can test changes without affecting users in production. A great local environment offers a level of fidelity on par with production.</p><p>The way we originally approached local development was with Miniflare 2, which reimplemented Workers runtime APIs in JavaScript. Unfortunately, there were <a href="https://github.com/cloudflare/miniflare/issues?page=1&amp;q=is%3Aissue+label%3A%22behaviour+mismatch%22">subtle behavior mismatches</a> between these re-implementations and the real Workers runtime. These types of issues are really difficult for developers to debug, as they don’t appear locally, and step-through debugging of deployed Workers isn’t possible yet. For example, the following Worker returns responses successfully in Miniflare 2, so we might assume it’s safe to publish:</p>
            <pre><code>let cachedResponsePromise;
export default {
  async fetch(request, env, ctx) {
    // Let's imagine this fetch takes a few seconds. To speed up our worker, we
    // decide to only fetch on the first request, and reuse the result later.
    // This works fine in Miniflare 2, so we must be good right?
    cachedResponsePromise ??= fetch("https://example.com");
    return (await cachedResponsePromise).clone();
  },
};</code></pre>
            <p>However, as soon as we send multiple requests to our deployed Worker, it fails with <code>Error: Cannot perform I/O on behalf of a different request</code>. The problem here is that response bodies created in one request’s handler cannot be accessed from a different request's handler. This limitation allows Cloudflare to improve overall Worker performance, but it was almost impossible for Miniflare 2 to detect these types of issues locally. In this particular case, the best solution is to <a href="https://developers.cloudflare.com/workers/examples/cache-using-fetch/">cache using <code>fetch</code> itself</a>.</p><p>Additionally, because the Workers runtime uses a very recent version of V8, it supports some JavaScript features that aren’t available in all versions of Node.js. This meant a few features implemented in Workers, like <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLast"><code>Array#findLast</code></a>, weren’t always available in Miniflare 2.</p><p>With the Workers runtime <a href="/workerd-open-source-workers-runtime/">now open-sourced</a>, Miniflare 3 can leverage the same implementations that are deployed on Cloudflare’s network, giving bug-for-bug compatibility and practically eliminating behavior mismatches. ?</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6VB6hw88YFoVMQWokJ0eIr/dda37612c76ed09051c4e997cf789c70/image4-26.png" />
            
            </figure><p>Miniflare 3’s new simplified architecture using worked</p><p>This radically simplifies our implementation too. We were able to remove <b>over 50,000</b> lines of code from Miniflare 2. Of course, we still kept all the Miniflare special-sauce that makes development fun like live reload and detailed logging. ?</p><a href="https://github.com/cloudflare/miniflare/pull/392"><img src="http://staging.blog.mrk.cfdata.org/content/images/2022/11/image5-15.png" /></a>
<p></p>
    <div>
      <h3>Local development with real data</h3>
      <a href="#local-development-with-real-data">
        
      </a>
    </div>
    <p>We know that many developers choose to test their Workers remotely on the Cloudflare network as it gives them the ability to test against real data. Testing against fake data in staging and local environments is sometimes difficult, as it never quite matches the real thing.</p><p>With Miniflare 3, we’re blurring the lines between local and remote development, by bringing real data to your machine as an experimental opt-in feature. If enabled, Miniflare will read and write data to namespaces on the Cloudflare network, as your Worker would when deployed. This is only supported with <a href="https://developers.cloudflare.com/workers/runtime-apis/kv/">Workers KV</a> for now, but we’re exploring similar solutions for <a href="https://developers.cloudflare.com/r2/">R2</a> and <a href="/introducing-d1/">D1</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6lSKVsotKwkVeNIXGo3XoK/c10227a6bec12bb7ea72c44e72cb3f39/image2-46.png" />
            
            </figure><p>Miniflare’s system for accessing real KV data, reads and writes are cached locally for future accesses</p>
    <div>
      <h3>A new default for Wrangler</h3>
      <a href="#a-new-default-for-wrangler">
        
      </a>
    </div>
    <p>With Miniflare 3 now effectively as accurate as the real Workers environment, and the ability to access real data locally, we’re revisiting the decision to make remote development the initial Wrangler experience. In a future update, <code><b>wrangler dev --local</b></code><b> will become the default</b>. <code>--local</code> will no longer be required. Benchmarking suggests this will bring an approximate <b>10x reduction to startup</b> and a massive <b>60x reduction to script reload</b> times! Over the next few weeks, we’ll be focusing on further optimizing Wrangler’s performance to bring you the fastest Workers development experience yet!</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4qal4ZCSp4RwfzHJf5FTBa/43d3f6e244136954aeb084c7c798d632/image1-63.png" />
            
            </figure>
    <div>
      <h3><code>wrangler init --from-dash</code></h3>
      <a href="#wrangler-init-from-dash">
        
      </a>
    </div>
    <p>We want all developers to be able to take advantage of the improved local experience, so we’re making it easy to start a local Wrangler project from an existing Worker that’s been developed in the Cloudflare dashboard. With <a href="https://nodejs.org/">Node.js</a> installed, run <code>`npx wrangler init` --`from-dash &lt;your_worker_name&gt;`</code>in your terminal to set up a new project with all your existing code and bindings such as KV namespaces configured. You can now seamlessly continue development of your application locally, taking advantage of all the developer experience improvements Wrangler and Miniflare provide. When you’re ready to deploy your worker, run <code>npx wrangler publish</code>.</p>
    <div>
      <h3>Looking to the future</h3>
      <a href="#looking-to-the-future">
        
      </a>
    </div>
    <p>Over the next few months, the Workers team is planning to further improve the local development experience with a specific focus on automated testing. Already, we’ve released a <a href="https://developers.cloudflare.com/workers/wrangler/api/#unstable_dev">preliminary API</a> for programmatic end-to-end tests with <code>wrangler dev</code>, but we’re also investigating ways of bringing <a href="https://miniflare.dev/testing/jest">Miniflare 2’s Jest/Vitest environments</a> to <code>workerd</code>. We’re also considering creating extensions for popular IDEs to make developing workers even easier. ?</p><p>Miniflare 3.0 is now included in Wrangler! Try it out by running <code>npx wrangler@latest dev --experimental-local</code>. Let us know what you think in the <code>#wrangler</code> channel on the <a href="https://discord.gg/cloudflaredev">Cloudflare Developers Discord</a>, and please <a href="https://github.com/cloudflare/wrangler2/issues/new/choose">open a GitHub issue</a> if you hit any unexpected behavior.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Miniflare]]></category>
            <category><![CDATA[Wrangler]]></category>
            <guid isPermaLink="false">QtR4nYtrKq40SS7vGNN9N</guid>
            <dc:creator>Brendan Coll</dc:creator>
        </item>
        <item>
            <title><![CDATA[Improving Workers TypeScript support: accuracy, ergonomics and interoperability]]></title>
            <link>https://blog.cloudflare.com/improving-workers-types/</link>
            <pubDate>Fri, 18 Nov 2022 14:00:00 GMT</pubDate>
            <description><![CDATA[ Today, we’re excited to announce the next major release of Workers TypeScript definitions with a bunch of improvements, and the open-sourcing of the new automatic generation scripts. ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6q7OqfYCQg4hWl6fxHoOq6/308a694c52ae40e073bc40b25e8dbe23/image2-47.png" />
            
            </figure><p><a href="https://www.typescriptlang.org/">TypeScript</a> makes it easy for developers to write code that doesn’t crash, by catching type errors before your program runs. We want developers to take advantage of this tooling, which is why one year ago, we <a href="/automatically-generated-types/">built a system to automatically generate TypeScript types</a> for the Cloudflare Workers runtime. This enabled developers to see code completions in their IDEs for Workers APIs, and to type check code before deploying. Each week, <a href="https://github.com/cloudflare/workers-types/pull/210">a new version of the types would be published</a>, reflecting the most recent changes.</p><p>Over the past year, we’ve received lots of feedback from customers and internal teams on how we could improve our types. With the switch to the Bazel build system in <a href="/workerd-open-source-workers-runtime/">preparation for open-sourcing the runtime</a>, we saw an opportunity to rebuild our types to be more accurate, easier to use, and simpler to generate. Today, we’re excited to announce the next major release of <code>@cloudflare/workers-types</code> with a bunch of new features, and the open-sourcing of the <a href="https://github.com/cloudflare/workerd/tree/main/types">fully-rewritten automatic generation scripts</a>.</p>
    <div>
      <h3>How to use TypeScript with Workers</h3>
      <a href="#how-to-use-typescript-with-workers">
        
      </a>
    </div>
    <p>Setting up TypeScript in Workers is easy! If you’re just getting started with Workers, install <a href="https://nodejs.org/">Node.js</a>, then run <code>npx wrangler init</code> in your terminal to generate a new project. If you have an existing Workers project and want to take advantage of our improved typings, install the latest versions of TypeScript and <code>@cloudflare/workers-types</code> with <code>npm install --save-dev typescript @cloudflare/workers-types@latest</code>, then create a <code>tsconfig.json</code> file with the following contents:</p>
            <pre><code>{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "lib": ["esnext"],
    "types": ["@cloudflare/workers-types"]
  }
}</code></pre>
            <p>Your editor will now highlight issues and give you code completions as you type, leading to a less error-prone and more enjoyable developer experience.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3Q1weJrUhhrrT7QIUkGMIw/c32d14dd8965a8b5598496045ac4fe2b/image3-39.png" />
            
            </figure><p>Editor highlighting incorrect use of <code>set</code> instead of <code>put</code>, and providing code completions</p>
    <div>
      <h3>Improved interoperability with standard types</h3>
      <a href="#improved-interoperability-with-standard-types">
        
      </a>
    </div>
    <p>Cloudflare Workers implement many of the same runtime APIs as browsers, and we’re working to improve our standards compliance even more with the <a href="/introducing-the-wintercg/">WinterCG</a>. However, there will always be fundamental differences between what browsers and Workers can do. For example, browsers can play audio files, whereas Workers have direct access to Cloudflare’s network for storing globally-distributed data. This mismatch means that the runtime APIs and types provided by each platform are different, which in turn makes it difficult to use Workers types with frameworks, like <a href="https://remix.run/">Remix</a>, that run the same files on the Cloudflare network and in the browser. These files need to be type-checked against <a href="https://raw.githubusercontent.com/microsoft/TypeScript/main/lib/lib.dom.d.ts"><code>lib.dom.d.ts</code></a>, which is incompatible with our types.</p><p>To solve this problem, we now generate a separate version of our types that can be selectively imported, without having to include <code>@cloudflare/workers-types</code> in your <code>tsconfig.json</code>’s <code>types</code> field. Here’s an example of what this looks like:</p>
            <pre><code>import type { KVNamespace } from "@cloudflare/workers-types";

declare const USERS_NAMESPACE: KVNamespace;</code></pre>
            <p>In addition, we automatically generate a diff of our types against TypeScript’s <a href="https://raw.githubusercontent.com/microsoft/TypeScript/main/lib/lib.webworker.d.ts"><code>lib.webworker.d.ts</code></a>. Going forward, we’ll use this to identify areas where we can further improve our spec-compliance.</p>
    <div>
      <h3>Improved compatibility with compatibility dates</h3>
      <a href="#improved-compatibility-with-compatibility-dates">
        
      </a>
    </div>
    <p>Cloudflare maintains strong backwards compatibility promises for all the APIs we provide. We use <a href="https://developers.cloudflare.com/workers/platform/compatibility-dates/">compatibility flags and dates</a> to make breaking changes in a backwards-compatible way. Sometimes these compatibility flags change the types. For example, the <a href="https://developers.cloudflare.com/workers/platform/compatibility-dates#global-navigator"><code>global_navigator</code></a> flag adds a new <code>navigator</code> global, and the <a href="https://developers.cloudflare.com/workers/platform/compatibility-dates#new-url-parser-implementation"><code>url_standard</code></a> flag changes the <code>URLSearchParams</code> constructor signature.</p><p>We now allow you to select the version of the types that matches your compatibility date, so you can be sure you’re not using features that won’t be supported at runtime.</p>
            <pre><code>{
  "compilerOptions": {
    ...
    "types": ["@cloudflare/workers-types/2022-08-04"]
  }
}</code></pre>
            
    <div>
      <h3>Improved integration with Wrangler</h3>
      <a href="#improved-integration-with-wrangler">
        
      </a>
    </div>
    <p>In addition to compatibility dates, your Worker environment configuration also impacts the runtime and type API surface. If you have bindings such as <a href="https://developers.cloudflare.com/workers/wrangler/configuration/#kv-namespaces">KV namespaces</a> or <a href="https://developers.cloudflare.com/workers/wrangler/configuration/#r2-buckets">R2 buckets</a> configured in your <code>wrangler.toml</code>, these need to be reflected in TypeScript types. Similarly, <a href="https://developers.cloudflare.com/workers/wrangler/configuration/#bundling">custom text, data and WebAssembly module rules</a> need to be declared so TypeScript knows the types of exports. Previously, it was up to you to create a separate ambient TypeScript file containing these declarations.</p><p>To keep <code>wrangler.toml</code> as the single source of truth, you can now run <code>npx wrangler types</code> to generate this file automatically.</p><p>For example, the following <code>wrangler.toml</code>…</p>
            <pre><code>kv_namespaces = [{ binding = "MY_NAMESPACE", id = "..." }]
rules = [{ type = "Text", globs = ["**/*.txt"] }]</code></pre>
            <p>…generates these ambient types:</p>
            <pre><code>interface Env {
  MY_NAMESPACE: KVNamespace;
}
declare module "*.txt" {
  const value: string;
  export default value;
}</code></pre>
            
    <div>
      <h3>Improved integrated documentation and changelogs</h3>
      <a href="#improved-integrated-documentation-and-changelogs">
        
      </a>
    </div>
    <p>Code completions provide a great way for developers new to the Workers platform to explore the API surface. We now include the documentation for standard APIs from TypeScript’s official types in our types. We’re also starting the process of bringing <a href="https://developers.cloudflare.com/workers/runtime-apis/">docs for Cloudflare specific APIs</a> into them too.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4N4SjX4uCcnhULQ6BeRfD9/d678d5a385b812670f70f331796c3fcc/image4-27.png" />
            
            </figure><p>For developers already using the Workers platform, it can be difficult to see how types are changing with each release of <code>@cloudflare/workers-types</code>. To avoid type errors and highlight new features, we now generate a detailed changelog with each release that <a href="https://github.com/cloudflare/workers-types/pull/291#issuecomment-1274541965">splits out new, changed and removed definitions</a>.</p>
    <div>
      <h3>How does type generation work under the hood?</h3>
      <a href="#how-does-type-generation-work-under-the-hood">
        
      </a>
    </div>
    <p>As mentioned earlier, we’ve completely rebuilt the <a href="https://github.com/cloudflare/workerd/tree/main/types">automatic type generation scripts</a> to be more reliable, extensible and maintainable. This means developers will get improved types as soon as new versions of the runtime are published. Our system now uses <code>workerd</code>’s new <a href="https://github.com/cloudflare/workerd/blob/200ded3d8469371f9ece6a00d4012e26637e5abc/src/workerd/jsg/rtti.h">runtime-type-information (RTTI) system</a> to query types of Workers runtime APIs, rather than attempting to extract this information from parsed C++ ASTs.</p>
            <pre><code>// Encode the KV namespace type without any compatibility flags enabled
CompatibilityFlags::Reader flags = {};
auto builder = rtti::Builder(flags);
auto type = builder.structure&lt;KvNamespace&gt;();
capnp::TextCodec codec;
auto encoded = codec.encode(type);
KJ_DBG(encoded); // (name = "KvNamespace", members = [ ... ], ...)</code></pre>
            <p>We then pass this RTTI to a TypeScript program that uses the <a href="https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API">TypeScript Compiler API</a> to generate declarations and perform AST transformations to tidy them up. This is built into <code>workerd</code>’s Bazel build system, meaning generating types is now a single <code>bazel build //types:types</code> command. We leverage Bazel’s cache to rebuild as little as possible during generation.</p>
            <pre><code>import ts, { factory as f } from "typescript";

const keyParameter = f.createParameterDeclaration(
  /* decorators */ undefined,
  /* modifiers */ undefined,
  /* dotDotDotToken */ undefined,
  "key",
  /* questionToken */ undefined,
  f.createTypeReferenceNode("string")
);
const returnType = f.createTypeReferenceNode("Promise", [
  f.createUnionTypeNode([
    f.createTypeReferenceNode("string"),
    f.createLiteralTypeNode(f.createNull()),
  ]),
]);
const getMethod = f.createMethodSignature(
  /* modifiers */ undefined,
  "get",
  /* questionToken */ undefined,
  /* typeParameters */ undefined,
  [keyParameter],
  returnType
);
const kvNamespace = f.createInterfaceDeclaration(
  /* decorators */ undefined,
  /* modifiers */ undefined,
  "KVNamespace",
  /* typeParameters */ undefined,
  /* heritageClauses */ undefined,
  [getMethod]
);

const file = ts.createSourceFile("file.ts", "", ts.ScriptTarget.ESNext);
const printer = ts.createPrinter();
const output = printer.printNode(ts.EmitHint.Unspecified, kvNamespace, file);
console.log(output); // interface KVNamespace { get(key: string): Promise&lt;string | null&gt;; }</code></pre>
            
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6d9euawkfvZmWDJeIRw0Yn/b0a19f0287fc55c2b869b0ee56c71a81/image1-64.png" />
            
            </figure><p>Whilst the auto-generated types <i>correctly</i> describe the JavaScript interface of Workers runtime APIs, TypeScript provides additional features we can use to provide <i>higher-fidelity</i> types and improve developer ergonomics. Our system allows us to handwrite partial TypeScript “overrides” that get merged with the auto-generated types. This enables us to…</p><ul><li><p>Add type parameters (generics) to types such as <a href="https://github.com/cloudflare/workerd/blob/aad867dfbaf6293fce9af70e08f82e1aa07dbdd5/src/workerd/api/streams/readable.h#L300-L318"><code>ReadableStream</code></a> and avoid <code>any</code> typed values.</p></li><li><p>Specify the correspondence between input and output types with method overloads. For example, <a href="https://github.com/cloudflare/workerd/blob/aad867dfbaf6293fce9af70e08f82e1aa07dbdd5/src/workerd/api/kv.h#L117-L125"><code>KVNamespace#get()</code></a> should return a <code>string</code> when the <code>type</code> argument is <code>text</code>, but <code>ArrayBuffer</code> when it’s <code>arrayBuffer</code>.</p></li><li><p>Rename types to match TypeScript standards and reduce verbosity.</p></li><li><p>Fully-replace a type for more accurate declarations. For example, we replace <a href="https://github.com/cloudflare/workerd/blob/aad867dfbaf6293fce9af70e08f82e1aa07dbdd5/src/workerd/api/web-socket.h#L384-L406"><code>WebSocketPair</code></a> with a <code>const</code> declaration for better types with <code>Object.values()</code>.</p></li><li><p>Provide types for values that are internally untyped such as the <code>Request#cf</code> object.</p></li><li><p>Hide internal types that aren’t usable in your workers.</p></li></ul><p>Previously, these overrides were defined in separate TypeScript files to the C++ declarations they were overriding. This meant they often fell out-of-sync with the original declarations. In the new system, overrides are defined alongside the originals with C++ macros, meaning they can be reviewed alongside runtime implementation changes. See the <a href="https://github.com/cloudflare/workerd/blob/aad867dfbaf6293fce9af70e08f82e1aa07dbdd5/src/workerd/jsg/README.md#typescript">README for <code>workerd</code>’s JavaScript glue code</a> for many more details and examples.</p>
    <div>
      <h3>Try typing with workers-types today!</h3>
      <a href="#try-typing-with-workers-types-today">
        
      </a>
    </div>
    <p>We encourage you to upgrade to the latest version of <code>@cloudflare/workers-types</code> with <code>npm install --save-dev @cloudflare/workers-types@latest</code>, and try out the new <code>wrangler types</code> command. We’ll be publishing a new version of the types with each <code>workerd</code> release. Let us know what you think on the <a href="https://discord.gg/cloudflaredev">Cloudflare Developers Discord</a>, and please <a href="https://github.com/cloudflare/workerd/issues/new">open a GitHub issue</a> if you find any types that could be improved.</p> ]]></content:encoded>
            <category><![CDATA[Developer Week]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Wrangler]]></category>
            <guid isPermaLink="false">7eNVYoR4NxTj3mypa2LM7U</guid>
            <dc:creator>Brendan Coll</dc:creator>
        </item>
        <item>
            <title><![CDATA[Miniflare 2.0: fully-local development and testing for Workers]]></title>
            <link>https://blog.cloudflare.com/miniflare/</link>
            <pubDate>Fri, 07 Jan 2022 13:58:33 GMT</pubDate>
            <description><![CDATA[ We're thrilled to announce the release of the next major version: a more modular, lightweight and accurate Miniflare 2.0 ]]></description>
            <content:encoded><![CDATA[ <p></p><p>In July 2021, I launched Miniflare 1.0, a fun, full-featured, fully-local simulator for Workers, on the <a href="https://discord.gg/cloudflaredev">Cloudflare Workers Discord server</a>. What began as a pull request to the <a href="https://github.com/gja/cloudflare-worker-local/pull/57"><code>cloudflare-worker-local</code></a> project has now become an official Cloudflare project and a core part of the Workers ecosystem, being integrated into <a href="/wrangler-v2-beta/">wrangler 2.0</a>. Today, I'm thrilled to announce the release of the next major version: a more modular, lightweight, and accurate Miniflare 2.0. ?</p>
    <div>
      <h2><b>Background: Why Miniflare was created</b></h2>
      <a href="#background-why-miniflare-was-created">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6aIIQnDFxercxfK9GYesIQ/1eadb8649cdc019daee1dad6acf05d2a/image3-7.png" />
            
            </figure><p>At the end of 2020, I started to build my first Workers app. Initially I used the then <a href="/announcing-wrangler-dev-the-edge-on-localhost/">recently released <code>wrangler dev</code></a>, but found it was taking a few seconds before changes were reflected. While this was still impressive considering it was running on the Workers runtime, I was using <a href="https://vitejs.dev/">Vite</a> to develop the frontend, so I knew a significantly faster developer experience was possible.</p><p>I then found <a href="https://github.com/gja/cloudflare-worker-local"><code>cloudflare-worker-local</code></a> and <a href="https://github.com/dollarshaveclub/cloudworker"><code>cloudworker</code></a>, which were local Workers simulators, but didn’t have support for newer features like Workers Sites. I wanted a magical simulator that would <i>just work</i> ✨ in existing projects, focusing on the developer experience, and — by the reception of Miniflare 1.0 — I wasn't the only one.</p><p>Miniflare 1.0 brought near instant reloads, source map support (so you could see where errors were thrown), cleaner logs (no more <code>{ unknown object }</code>s or massive JSON stack traces), a pretty error page that highlighted the cause of the error, <a href="https://miniflare.dev/developing/debugger">step-through debugger support</a>, and more.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2KeKH4ewXNY0saCTIUa0pK/5f34f2c536ccccdf72752a4253ae4b9b/image2-81.png" />
            
            </figure><p>Pretty-error page powered by `youch`</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5MmJ7lqEBt90UQrBLC1Zxm/9a87a210a98b64b21f5a975129a4d830/image5-5.png" />
            
            </figure>
    <div>
      <h2><b>The next iteration: What's new in version 2</b></h2>
      <a href="#the-next-iteration-whats-new-in-version-2">
        
      </a>
    </div>
    <p>In the relatively short time since the launch of Miniflare 1.0 in July, Workers as a platform has improved dramatically. Durable Objects now have <a href="/durable-objects-easy-fast-correct-choose-three/">input and output gates</a> for ensuring consistency without explicit transactions, Workers has <a href="/backwards-compatibility-in-cloudflare-workers/">compatibility dates</a> allowing developers to opt-into backwards-incompatible fixes, and you can now write Workers using <a href="/workers-javascript-modules/">JavaScript modules</a>.</p><p>Miniflare 2 supports all these features and has been completely redesigned with three primary design goals:</p><ol><li><p><b>Modular:</b> Miniflare 2 splits Workers components (KV, Durable Objects, etc.) into separate packages (<code>@miniflare/kv</code>, <code>@miniflare/durable-objects</code>, etc.) that you can import on their own for testing. This will also make it easier to add support for new, unreleased features like <a href="/introducing-r2-object-storage/">R2 Storage</a>.</p></li><li><p><b>Lightweight:</b> Miniflare 1 included <a href="http://npm.anvaka.com/#/view/2d/miniflare/1.4.1">122 third-party packages</a> with a total install size of <code>88.3MB</code>. Miniflare 2 reduces this to <b>23 packages and </b><code><b>6MB</b></code> by leveraging features included with Node.js 16.</p></li><li><p><b>Accurate:</b> Miniflare 2 replicates the quirks and thrown errors of the real Workers runtime, so you'll know before you deploy if things are going to break. Of course, <code>wrangler dev</code> will always be the most accurate preview, running on the real edge with real data, but Miniflare 2 is really close!</p></li></ol><p>It also adds a new <a href="https://miniflare.dev/developing/live-reload">live-reload feature</a> and first-class support for testing with Jest for an even more enjoyable developer experience.</p><div></div>
<p></p>
    <div>
      <h2><b>Getting started with local development</b></h2>
      <a href="#getting-started-with-local-development">
        
      </a>
    </div>
    <p>As mentioned in the introduction, Miniflare 2.0 is now integrated into <a href="/wrangler-v2-beta/">wrangler 2.0</a>, so you just need to run <code>npx wrangler@beta dev --local</code> to start a fully-local Worker development server or <code>npx wrangler@beta pages dev</code> to start a <a href="/cloudflare-pages-goes-full-stack/">Cloudflare Pages Functions</a> server. Make sure you've got the <a href="https://nodejs.org/">latest release of Node.js</a> installed.</p><p>However, if you're using Wrangler 1 or want to customize your local environment, you can install Miniflare standalone. If you've got an existing worker with a <code>wrangler.toml</code> file, just run <code>npx miniflare --live-reload</code> to start a live-reloading development server. Miniflare will automatically load configuration like KV namespaces or Durable Object bindings from your <code>wrangler.toml</code> file and secrets from a <code>.env</code> file.</p><p>Miniflare is highly configurable. For example, if you want to persist KV data between restarts, include the <code>--kv-persist</code> flag. See the <a href="https://miniflare.dev/">Miniflare docs</a> or run <code>npx miniflare --help</code> for many more options, like running multiple workers or starting an HTTPS server.</p><p>If you've got a <code>scheduled</code> event handler, you can manually trigger it by visiting <code>http://localhost:8787/cdn-cgi/mf/scheduled</code> in your browser.</p>
    <div>
      <h2><b>Testing for Workers with Jest</b></h2>
      <a href="#testing-for-workers-with-jest">
        
      </a>
    </div>
    <p><a href="https://jestjs.io/">Jest</a> is one of the most popular JavaScript testing frameworks, so it made sense to add first-class support for it. Miniflare 2.0 includes a <a href="https://jestjs.io/docs/configuration#testenvironment-string">custom test environment</a> that gives your tests access to <a href="https://developers.cloudflare.com/workers/runtime-apis">Workers runtime APIs</a>.</p><p>For example, suppose we have the following worker, written using JavaScript modules, that stores the number of times each URL is visited in Workers KV:</p><blockquote><p>Aside: Workers KV is not designed for counters as it's eventually consistent. In a real worker, you should use Durable Objects. This is just a simple example.</p></blockquote>
            <pre><code>// src/index.mjs
export async function increment(namespace, key) {
  // Get the current count from KV
  const currentValue = await namespace.get(key);
  // Increment the count, defaulting it to 0
  const newValue = parseInt(currentValue ?? "0") + 1;
  // Store and return the new count
  await namespace.put(key, newValue.toString());
  return newValue;
}

export default {
  async fetch(request, env, ctx) {
    // Use the pathname for a key
    const url = new URL(request.url);
    const key = url.pathname;
    // Increment the key
    const value = await increment(env.COUNTER_NAMESPACE, key);
    // Return the new incremented count
    return new Response(`count for ${key} is now ${value}`);
  },
};</code></pre>
            
            <pre><code># wrangler.toml
kv_namespaces = [
  { binding = "COUNTER_NAMESPACE", id = "..." }
]

[build.upload]
format = "modules"
dist = "src"
main = "./index.mjs"</code></pre>
            <p>...we can write unit tests like so:</p>
            <pre><code>// test/index.spec.mjs
import worker, { increment } from "../src/index.mjs";

// When using `format = "modules"`, bindings are included in the `env` parameter,
// which we don't have access to in tests. Miniflare therefore provides a custom
// global method to access these.
const { COUNTER_NAMESPACE } = getMiniflareBindings();

test("should increment the count", async () =&gt; {
  // Seed the KV namespace
  await COUNTER_NAMESPACE.put("a", "3");

  // Perform the increment
  const newValue = await increment(COUNTER_NAMESPACE, "a");
  const storedValue = await COUNTER_NAMESPACE.get("a");

  // Check the return value of increment
  expect(newValue).toBe(4);
  // Check increment had the side effect of updating KV
  expect(storedValue).toBe("4");
});

test("should return new count", async () =&gt; {
  // Note we're using Worker APIs in our test, without importing anything extra
  const request = new Request("http://localhost/a");
  const response = await worker.fetch(request, { COUNTER_NAMESPACE });

  // Each test gets its own isolated storage environment, so the changes to "a"
  // are *undone* automatically. This means at the start of this test, "a"
  // wasn't in COUNTER_NAMESPACE, so it defaulted to 0, and the count is now 1.
  expect(await response.text()).toBe("count for /a is now 1");
});</code></pre>
            
            <pre><code>// jest.config.js
const { defaults } = require("jest-config");

module.exports = {
  testEnvironment: "miniflare", // ✨
  // Tell Jest to look for tests in .mjs files too
  testMatch: [
    "**/__tests__/**/*.?(m)[jt]s?(x)",
    "**/?(*.)+(spec|test).?(m)[tj]s?(x)",
  ],
  moduleFileExtensions: ["mjs", ...defaults.moduleFileExtensions],
};</code></pre>
            <p>...and run them with:</p>
            <pre><code># Install dependencies
$ npm install -D jest jest-environment-miniflare
# Run tests with experimental ES modules support
$ NODE_OPTIONS=--experimental-vm-modules npx jest</code></pre>
            <p>For more details about the custom test environment and isolated storage, see the <a href="https://miniflare.dev/testing/jest">Miniflare docs</a> or <a href="https://github.com/mrbbot/miniflare-typescript-esbuild-jest">this example project</a> that also uses TypeScript and Durable Objects.</p><p>Not using Jest? Miniflare lets you write your own integration tests with vanilla Node.js or any other test framework. For an example using AVA, see the <a href="https://miniflare.dev/testing/ava">Miniflare docs</a> or <a href="https://github.com/mrbbot/miniflare-esbuild-ava">this repository</a>.</p>
    <div>
      <h2><b>How Miniflare works</b></h2>
      <a href="#how-miniflare-works">
        
      </a>
    </div>
    <p>Let's now dig deeper into how some interesting parts of Miniflare work.</p><p>Miniflare is powered by Node.js, a JavaScript runtime built on Chrome's V8 JavaScript engine. V8 is the same engine that powers the Cloudflare Workers runtime, but Node and Workers implement different runtime APIs on top of it. To ensure Node's APIs aren't visible to users' worker code and to inject Workers' APIs, Miniflare uses the <a href="https://nodejs.org/api/vm.html">Node.js <code>vm</code> module</a>. This lets you run arbitrary code in a custom V8 context.</p><p>A core part of Workers are the <code>Request</code> and <code>Response</code> classes. Miniflare gets these from <a href="https://github.com/nodejs/undici"><code>undici</code></a>, a project written by the Node team to bring <code>fetch</code> to Node. For service workers, we also need a way to <code>addEventListener</code>s and dispatch events using the <code>EventTarget</code> API, which was added in Node 15.</p><p>With that we can build a <i>mini</i>-miniflare:</p>
            <pre><code>import vm from "vm";
import { Request, Response } from "undici";

// An instance of this class will become the global scope of our Worker,
// extending EventTarget for addEventListener and dispatchEvent
class ServiceWorkerGlobalScope extends EventTarget {
  constructor() {
    super();

    // Add Worker runtime APIs
    this.Request = Request;
    this.Response = Response;

    // Make sure this is bound correctly when EventTarget methods are called
    this.addEventListener = this.addEventListener.bind(this);
    this.removeEventListener = this.removeEventListener.bind(this);
    this.dispatchEvent = this.dispatchEvent.bind(this);
  }
}

// An instance of this class will be passed as the event parameter to "fetch"
// event listeners
class FetchEvent extends Event {
  constructor(type, init) {
    super(type);
    this.request = init.request;
  }

  respondWith(response) {
    this.response = response;
  }
}

// Create a V8 context to run user code in
const globalScope = new ServiceWorkerGlobalScope();
const context = vm.createContext(globalScope);

// Example user worker code, this could be loaded from the file system
const workerCode = `
addEventListener("fetch", (event) =&gt; {
  event.respondWith(new Response("Hello mini-miniflare!"));
})
`;
const script = new vm.Script(workerCode);

// Run the user's code, registering the "fetch" event listener
script.runInContext(context);

// Create an example request, this could come from an incoming HTTP request
const request = new Request("http://localhost:8787/");
const event = new FetchEvent("fetch", { request });

// Dispatch the event and log the response
globalScope.dispatchEvent(event);
console.log(await event.response.text()); // Hello mini-miniflare!</code></pre>
            
    <div>
      <h3><b>Plugins</b></h3>
      <a href="#plugins">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6qYQfyfQqHPj6BmnflgsJV/ff80edc724c00d644bd40a0765bd1f19/image1-108.png" />
            
            </figure><p>Dependency graph of the Miniflare monorepo.</p><p>There are a lot of Workers runtime APIs, so adding and configuring them all manually as above would be tedious. Therefore, Miniflare 2 has a plugin system that allows each package to export globals and bindings to be included in the sandbox. Options have annotations describing their type, CLI flag, and where to find them in Wrangler configuration files:</p>
            <pre><code>@Option({
  // Define type for runtime validation of the CLI flag
  type: OptionType.ARRAY,
  // Use --kv instead of auto-generated --kv-namespace for the CLI flag
  name: "kv",
  // Define -k as an alias
  alias: "k",
  // Displayed in --help
  description: "KV namespace to bind",
  // Where to find this option in wrangler.toml
  fromWrangler: (config) =&gt; config.kv_namespaces?.map(({ binding }) =&gt; binding),
})
kvNamespaces?: string[];</code></pre>
            
    <div>
      <h3><b>Durable Objects</b></h3>
      <a href="#durable-objects">
        
      </a>
    </div>
    <p>Before input and output gates were added, you usually needed to use the <code>transaction()</code> method to ensure consistency:</p>
            <pre><code>async function incrementCount() {
  let value;
  await this.storage.transaction(async (txn) =&gt; {
    value = await txn.get("count");
    await txn.put("count", value + 1);
  });
  return value;
}</code></pre>
            <p>Miniflare implements this using <a href="https://dl.acm.org/doi/10.1145/319566.319567">optimistic-concurrency control (OCC)</a>. However, input and output gates are now available, so to avoid race conditions when simulating newly-written Durable Object code, Miniflare 2 needed to implement them.</p><p>From the description in the <a href="/durable-objects-easy-fast-correct-choose-three/#part1inputgates">gates announcement blog post</a>:</p><blockquote><p><b>Input gates:</b> While a storage operation is executing, no events shall be delivered to the object except for storage completion events. Any other events will be deferred until such a time as the object is no longer executing JavaScript code and is no longer waiting for any storage operations. We say that these events are waiting for the "input gate" to open.</p></blockquote><p>...we can see input gates need to have two methods, one for closing the gate while a storage operation is running and one for waiting until the input gate is open:</p>
            <pre><code>class InputGate {
  async runWithClosed&lt;T&gt;(closure: () =&gt; Promise&lt;T&gt;): Promise&lt;T&gt; {
    // 1. Close the input gate
    // 2. Run the closure and store the result
    // 3. Open the input gate
    // 4. Return the result
  }

  async waitForOpen(): Promise&lt;void&gt; {
    // 1. Check if the input gate is open
    // 2. If it is, return
    // 3. Otherwise, wait until it is
  }
}</code></pre>
            <p>Each Durable Object has its own <code>InputGate</code>. In the storage implementation, we call <code>runWithClosed</code> to defer other events until the storage operation completes:</p>
            <pre><code>class DurableObjectStorage {
  async get&lt;Value&gt;(key: string): Promise&lt;Value | undefined&gt; {
    return this.inputGate.runWithClosed(() =&gt; {
      // Get key from storage
    });
  }
}</code></pre>
            <p>...and whenever we're ready to deliver another event, we call <code>waitForOpen</code>:</p>
            <pre><code>import { fetch as baseFetch } from "undici";

async function fetch(input, init) {
  const response = await baseFetch(input, init);
  await inputGate.waitForOpen();
  return response;
}</code></pre>
            <p>You may have noticed a problem here. Where does <code>inputGate</code> come from in <code>fetch</code>? We only have one global scope for the entire Worker and all its Durable Objects, so we can't have a <code>fetch</code> per Durable Object <code>InputGate</code>. We also can't ask the user to pass it around as another parameter to all functions that need it. We need some way of storing it in a <i>context</i> that's passed around automatically between potentially <code><i>async</i></code> functions. For this, we can use another lesser-known Node module, <a href="https://nodejs.org/api/async_context.html"><code>async_hooks</code></a>, which includes the <a href="https://nodejs.org/api/async_context.html#class-asynclocalstorage"><code>AsyncLocalStorage</code> class</a>:</p>
            <pre><code>import { AsyncLocalStorage } from "async_hooks";

const inputGateStorage = new AsyncLocalStorage&lt;InputGate&gt;();

const inputGate = new InputGate();
await inputGateStorage.run(inputGate, async () =&gt; {
  // This closure will run in an async context with inputGate
  await fetch("https://example.com");
});

async function fetch(input: RequestInfo, init: RequestInit): Promise&lt;Response&gt; {
  const response = await baseFetch(input, init);
  // Get the input gate in the current async context
  const inputGate = inputGateStorage.getStore();
  await inputGate.waitForOpen();
  return response;
}</code></pre>
            <p>Durable Objects also include a <code>blockConcurrencyWhile(closure)</code> method that defers events until the <code>closure</code> completes. This is exactly the <code>runWithClosed()</code> method:</p>
            <pre><code>class DurableObjectState {
  // ...

  blockConcurrencyWhile&lt;T&gt;(closure: () =&gt; Promise&lt;T&gt;): Promise&lt;T&gt; {
    return this.inputGate.runWithClosed(closure);
  }
}</code></pre>
            <p>However, there's a problem with what we've got at the moment. Consider the following code:</p>
            <pre><code>export class CounterObject {
  constructor(state: DurableObjectState) {
    state.blockConcurrencyWhile(async () =&gt; {
      const res = await fetch("https://example.com");
      this.data = await res.text();
    });
  }
}</code></pre>
            <p><code>blockConcurrencyWhile</code> closes the input gate, but <code>fetch</code> won't return until the input gate is open, so we're deadlocked! To fix this, we need to make <code>InputGate</code>s nested:</p>
            <pre><code>class InputGate {
  constructor(private parent?: InputGate) {}

  async runWithClosed&lt;T&gt;(closure: () =&gt; Promise&lt;T&gt;): Promise&lt;T&gt; {
    // 1. Close the input gate, *and any parents*
    // 2. *Create a new child input gate with this as its parent*
    const childInputGate = new InputGate(this);
    // 3. Run the closure, *under the child input gate's context*
    // 4. Open the input gate, *and any parents*
    // 5. Return the result
  }
}</code></pre>
            <p>Now the input gate outside of <code>blockConcurrencyWhile</code> will be closed, so fetches to the Durable Object will be deferred, but the input gate inside the closure will be open, so the <code>fetch</code> can return.</p><p>This glosses over some details, but you can check out the <a href="https://github.com/cloudflare/miniflare/blob/v2.0.0/packages/shared/src/sync/gate.ts">gates implementation</a> for additional context and comments. ?</p>
    <div>
      <h3><b>HTMLRewriter</b></h3>
      <a href="#htmlrewriter">
        
      </a>
    </div>
    <p><code>HTMLRewriter</code> is another novel class that allows parsing and transforming HTML streams. In the edge Workers runtime, it's powered by C-bindings to the <a href="https://github.com/cloudflare/lol-html">lol-html</a> Rust library. Luckily, <a href="/author/ivan-nikulin/">Ivan Nikulin</a> built <a href="https://github.com/cloudflare/lol-html/issues/38">WebAssembly bindings</a> for this, so we're able to use the same library in Node.js.</p><p>However, these were missing support for <code>async</code> handlers that allow you to access external resources when rewriting:</p>
            <pre><code>class UserElementHandler {
  async element(node) {
    const response = await fetch("/user");
    // ...
  }
}</code></pre>
            <p>The WebAssembly bindings Rust code includes something like:</p>
            <pre><code>macro_rules! make_handler {
  ($handler:ident, $JsArgType:ident, $this:ident) =&gt; {
    move |arg: &amp;mut _| {
      // `js_arg` here is the `node` parameter from above
      let js_arg = JsValue::from(arg);
      // $handler here is the `element` method from above
      match $handler.call1(&amp;$this, &amp;js_arg) {
        Ok(res) =&gt; {
          // Check if this is an async handler
          if let Some(promise) = res.dyn_ref::&lt;JsPromise&gt;() {
            await_promise(promise);
          }
          Ok(())
        }
        Err(e) =&gt; ...,
      }
    }
  };
}</code></pre>
            <p>The key thing to note here is that the Rust <code>move |...| { ... }</code> closure is synchronous, but handlers can be asynchronous. This is like trying to <code>await</code> a <code>Promise</code> in a non-<code>async</code> function.</p><p>To solve this, we use the <a href="https://github.com/WebAssembly/binaryen/blob/main/src/passes/Asyncify.cpp">Asyncify</a> feature of <a href="https://github.com/WebAssembly/binaryen">Binaryen</a>, a set of tools for working with WebAssembly modules. Whenever we call <code>await_promise</code>, Asyncify unwinds the current WebAssembly stack into some temporary storage. Then in JavaScript, we <code>await</code> the <code>Promise</code>. Finally, we rewind the stack from the temporary storage to the previous state and continue rewriting where we left off.</p><p>You can find the full implementation in the <a href="https://github.com/mrbbot/html-rewriter-wasm"><code>html-rewriter-wasm</code> package</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2yhaL0yMZ6KwV2oKVvZEgd/92d6c0add7832053ea38f97c3ecf9bb8/image4-4.png" />
            
            </figure>
    <div>
      <h2><b>The future of Miniflare</b></h2>
      <a href="#the-future-of-miniflare">
        
      </a>
    </div>
    <p>As mentioned earlier, Miniflare is now included in wrangler 2.0. Try it out and let us know what you think!</p><p>I'd like to thank everyone on the Workers team at Cloudflare for building such an amazing platform and supportive community. Special thanks to anyone who's contributed to Miniflare, opened issues, given suggestions, or asked questions in the Discord server.</p><p>Maybe now I can finish off my original workers project... ?</p> ]]></content:encoded>
            <category><![CDATA[Miniflare]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">3MNyxnrt1lWfxkbUQQF8nA</guid>
            <dc:creator>Brendan Coll</dc:creator>
        </item>
        <item>
            <title><![CDATA[Automatically generating types for Cloudflare Workers]]></title>
            <link>https://blog.cloudflare.com/automatically-generated-types/</link>
            <pubDate>Tue, 16 Nov 2021 13:58:45 GMT</pubDate>
            <description><![CDATA[ Every time the Workers runtime code is built, a script runs over the public APIs and generates the Rust and TypeScript types as well as a JSON file containing an intermediate representation of the static types. The types are sent to the appropriate repositories and the JSON file is uploaded as well. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Historically, keeping our Rust and TypeScript type repos up to date has been hard. They were manually generated, which means they ran the risk of being inaccurate or out of date. Until recently, the workers-types repository needed to be manually updated whenever the types changed. We also used to add type information for mostly complete browser APIs. This led to confusion when people would try to use browser APIs that aren’t supported by the Workers runtime they would compile but throw errors.</p><p>That all changed this summer when Brendan Coll, whilst he was interning with us, built an automated pipeline for generating them. It runs every time we build the Workers runtime, generating types for our TypeScript and Rust repositories. Now everything is up-to-date and accurate.</p>
    <div>
      <h2>A quick overview</h2>
      <a href="#a-quick-overview">
        
      </a>
    </div>
    <p>Every time the Workers runtime code is built, a script runs over the public APIs and generates the Rust and TypeScript types as well as a JSON file containing an <a href="https://en.wikipedia.org/wiki/Intermediate_representation">intermediate representation</a> of the static types. The types are sent to the appropriate repositories and the JSON file is uploaded as well in case people want to create their own types packages. More on that later.</p><p>This means the static types will always be accurate and up to date. It also allows projects running Workers in other, statically-typed languages to generate their own types from our intermediate representation. Here is an example PR from our Cloudflare bot. It’s detected a change in the runtime types and is updating the TypeScript files as well as the intermediate representation.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7gGG9WJuWteHvOu7Gurphb/2c69778b60fc0be7b05de74620adc5ee/image2-12.png" />
            
            </figure>
    <div>
      <h2>Using the auto-generated types</h2>
      <a href="#using-the-auto-generated-types">
        
      </a>
    </div>
    <p>To get started, use wrangler to generate a new TypeScript project:</p>
            <pre><code>$ wrangler generate my-typescript-worker https://github.com/cloudflare/worker-typescript-template</code></pre>
            <p>If you already have a TypeScript project, you can install the latest version of <a href="https://github.com/cloudflare/workers-types">workers-types</a> with:</p>
            <pre><code>$ npm install --save-dev @cloudflare/workers-types</code></pre>
            <p>And then add <code>@cloudflare/workers-types</code> to your project's tsconfig.json file.</p>
            <pre><code>{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "lib": ["ES2020"],
    "types": ["@cloudflare/workers-types"]
  }
}</code></pre>
            <p>After that, you should get automatic type completion in your IDE of choice.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4qwl2tjaM5QenHDZi4Tat7/194c992e5b9bb9a35fbd4b94dcceb007/image3-19.png" />
            
            </figure>
    <div>
      <h2>How it works</h2>
      <a href="#how-it-works">
        
      </a>
    </div>
    <p>Here is some example code from the Workers runtime codebase.</p>
            <pre><code>class Blob: public js::Object {
public:
  typedef kj::Array&lt;kj::OneOf&lt;kj::Array&lt;const byte&gt;, kj::String, js::Ref&lt;Blob&gt;&gt;&gt; Bits;
  struct Options {
    js::Optional&lt;kj::String&gt; type;
    JS_STRUCT(type);
  };

  static js::Ref&lt;Blob&gt; constructor(js::Optional&lt;Bits&gt; bits, js::Optional&lt;Options&gt; options);
  
  int getSize();
  js::Ref&lt;Blob&gt; slice(js::Optional&lt;int&gt; start, js::Optional&lt;int&gt; end);

  JS_RESOURCE_TYPE(Blob) {
    JS_READONLY_PROPERTY(size, getSize);
    JS_METHOD(slice);
  }
};</code></pre>
            <p>A Python script runs over this code during each build and generates an <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">Abstract Syntax Tree</a> containing information about the function including an identifier, any argument types and any return types.</p>
            <pre><code>{
  "name": "Blob",
  "kind": "class",
  "members": [
    {
      "name": "size",
      "type": {
        "name": "integer"
      },
      "readonly": true
    },
    {
      "name": "slice",
      "type": {
        "params": [
          {
            "name": "start",
            "type": {
              "name": "integer",
              "optional": true
            }
          },
          {
            "name": "end",
            "type": {
              "name": "integer",
              "optional": true
            }
          }
        ],
        "returns": {
          "name": "Blob"
        }
      }
    }
  ]
}</code></pre>
            <p>Finally, the <a href="https://github.com/cloudflare/workers-types">TypeScript types</a> repositories are automatically sent PRs with the updated types.</p>
            <pre><code>declare type BlobBits = (ArrayBuffer | string | Blob)[];

interface BlobOptions {
  type?: string;
}

declare class Blob {
  constructor(bits?: BlobBits, options?: BlobOptions);
  readonly size: number;
  slice(start?: number, end?: number, type?: string): Blob;
}</code></pre>
            
    <div>
      <h3>Overrides</h3>
      <a href="#overrides">
        
      </a>
    </div>
    <p>In some cases, TypeScript supports concepts that our C++ runtime does not. Namely, generics and function overloads. In these cases, we override the generated types with partial declarations. For example, <code>DurableObjectStorage</code> makes heavy use of generics for its getter and setter functions.</p>
            <pre><code>declare abstract class DurableObjectStorage {
	 get&lt;T = unknown&gt;(key: string, options?: DurableObjectStorageOperationsGetOptions): Promise&lt;T | undefined&gt;;
	 get&lt;T = unknown&gt;(keys: string[], options?: DurableObjectStorageOperationsGetOptions): Promise&lt;Map&lt;string, T&gt;&gt;;
	 
	 list&lt;T = unknown&gt;(options?: DurableObjectStorageOperationsListOptions): Promise&lt;Map&lt;string, T&gt;&gt;;
	 
	 put&lt;T&gt;(key: string, value: T, options?: DurableObjectStorageOperationsPutOptions): Promise&lt;void&gt;;
	 put&lt;T&gt;(entries: Record&lt;string, T&gt;, options?: DurableObjectStorageOperationsPutOptions): Promise&lt;void&gt;;
	 
	 delete(key: string, options?: DurableObjectStorageOperationsPutOptions): Promise&lt;boolean&gt;;
	 delete(keys: string[], options?: DurableObjectStorageOperationsPutOptions): Promise&lt;number&gt;;
	 
	 transaction&lt;T&gt;(closure: (txn: DurableObjectTransaction) =&gt; Promise&lt;T&gt;): Promise&lt;T&gt;;
	}</code></pre>
            <p>You can also write type overrides using Markdown. <a href="https://github.com/cloudflare/workers-types/blob/master/docs/kv.md">Here</a> is an example of overriding types of <code>KVNamespace</code>.</p>
    <div>
      <h2>Creating your own types</h2>
      <a href="#creating-your-own-types">
        
      </a>
    </div>
    <p>The JSON IR (<a href="https://en.wikipedia.org/wiki/Intermediate_representation">intermediate representation</a>) has been open sourced alongside the TypeScript types and can be found <a href="https://github.com/cloudflare/workers-types/blob/master/src/workers.json">in this GitHub repository</a>. We’ve also open sourced the <a href="https://github.com/cloudflare/workers-types/blob/master/src/schema.json">type schema</a> itself, which describes the format of the IR. If you’re interested in generating Workers types for your own language, you can take the IR, which describes the declaration in a "normalized" data structure, and generate types from it.</p><p>The declarations inside <code>workers.json</code> contain the elements to derive function signatures and other elements needed for code generation such as identifiers, argument types, return types and error management. A concrete use-case would be to generate external function declarations for a language that compiles to WebAssembly, to import precisely the set of available function calls available from the Workers runtime.</p>
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>Cloudflare cares deeply about supporting the TypeScript and Rust ecosystems. Brendan created a tool which will ensure the type information for both languages is always up-to-date and accurate. We also are open-sourcing the type information itself in JSON format, so that anyone interested can create type data for any language they’d like!</p>
    <div>
      <h3>Watch on Cloudflare TV</h3>
      <a href="#watch-on-cloudflare-tv">
        
      </a>
    </div>
    <div></div><p></p> ]]></content:encoded>
            <category><![CDATA[Full Stack Week]]></category>
            <category><![CDATA[Cloudflare Workers]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <guid isPermaLink="false">5s0jPmxdqjgqU9MVoG8A0w</guid>
            <dc:creator>Brendan Coll</dc:creator>
            <dc:creator>Jonathan Kuperman</dc:creator>
        </item>
    </channel>
</rss>