-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Add miniflare docs #18690
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Add miniflare docs #18690
Changes from 4 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
b4b138a
initial import
penalosa 8399376
Adapt to v3 & current state
penalosa 58f0dd6
Apply suggestions from code review
penalosa 23ec47d
Add get started back
penalosa 43cf3e8
fix links
penalosa e0ee190
Move to testing folder
penalosa 9c11445
change link
penalosa 5262d96
fix links
penalosa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| --- | ||
| order: 8 | ||
| title: "📅 Compatibility Dates" | ||
| --- | ||
|
|
||
| - [Compatibility Dates Reference](/workers/platform/compatibility-dates) | ||
|
|
||
| ## Compatibility Dates | ||
|
|
||
| Miniflare uses compatibility dates to opt-into backwards-incompatible changes | ||
| from a specific date. If one isn't set, it will default to some time far in the | ||
| past. | ||
|
|
||
| ```js | ||
| const mf = new Miniflare({ | ||
| compatibilityDate: "2021-11-12", | ||
| }); | ||
| ``` | ||
|
|
||
| ## Compatibility Flags | ||
|
|
||
| Miniflare also lets you opt-in/out of specific changes using compatibility | ||
| flags: | ||
|
|
||
| ```js | ||
| const mf = new Miniflare({ | ||
| compatibilityFlags: [ | ||
| "formdata_parser_supports_files", | ||
| "durable_object_fetch_allows_relative_url", | ||
| ], | ||
| }); | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| --- | ||
| order: 0 | ||
| title: "📨 Fetch Events" | ||
| --- | ||
|
|
||
| - [`FetchEvent` Reference](/workers/runtime-apis/fetch-event) | ||
| - [`FetchEvent` Lifecycle](/workers/learning/fetch-event-lifecycle) | ||
| - [`addEventListener` Reference](/workers/runtime-apis/add-event-listener) | ||
|
|
||
| ## HTTP Requests | ||
|
|
||
| Whenever an HTTP request is made, a `Request` object is dispatched to your worker, then the generated `Response` is returned. The | ||
hyperlint-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| `Request` object will include a | ||
| [`cf` object](/workers/runtime-apis/request#incomingrequestcfproperties). | ||
| Miniflare will log the method, path, status, and the time it took to respond. | ||
|
|
||
| If the Worker throws an error whilst generating a response, an error page | ||
| containing the stack trace is returned instead. You can use | ||
| [🗺 Source Maps](/developing/source-maps) to make these point to your source | ||
| files. | ||
|
|
||
| ## Dispatching Events | ||
|
|
||
| When using the API, the `dispatchFetch` function can be used to dispatch `fetch` | ||
| events to your Worker. This can be used for testing responses. `dispatchFetch` | ||
| has the same API as the regular `fetch` method: it either takes a `Request` | ||
| object, or a URL and optional `RequestInit` object: | ||
|
|
||
| ```js | ||
| import { Miniflare, Request } from "miniflare"; | ||
|
|
||
| const mf = new Miniflare({ | ||
| modules: true, | ||
| script: ` | ||
| export default { | ||
| async fetch(request, env, ctx) { | ||
| const body = JSON.stringify({ | ||
| url: event.request.url, | ||
| header: event.request.headers.get("X-Message"), | ||
| }); | ||
| return new Response(body, { | ||
| headers: { "Content-Type": "application/json" }, | ||
| }); | ||
| }) | ||
| } | ||
| `, | ||
| }); | ||
|
|
||
| let res = await mf.dispatchFetch("http://localhost:8787/"); | ||
| console.log(await res.json()); // { url: "http://localhost:8787/", header: null } | ||
|
|
||
| res = await mf.dispatchFetch("http://localhost:8787/1", { | ||
| headers: { "X-Message": "1" }, | ||
| }); | ||
| console.log(await res.json()); // { url: "http://localhost:8787/1", header: "1" } | ||
|
|
||
| res = await mf.dispatchFetch( | ||
| new Request("http://localhost:8787/2", { | ||
| headers: { "X-Message": "2" }, | ||
| }), | ||
| ); | ||
| console.log(await res.json()); // { url: "http://localhost:8787/2", header: "2" } | ||
| ``` | ||
|
|
||
| When dispatching events, you are responsible for adding | ||
| [`CF-*` headers](https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-) | ||
| and the | ||
| [`cf` object](/workers/runtime-apis/request#incomingrequestcfproperties). | ||
| This lets you control their values for testing: | ||
|
|
||
| ```js | ||
| const res = await mf.dispatchFetch("http://localhost:8787", { | ||
| headers: { | ||
| "CF-IPCountry": "GB", | ||
| }, | ||
| cf: { | ||
| country: "GB", | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| ## Upstream | ||
|
|
||
| Miniflare will call each `fetch` listener until a response is returned. If no | ||
| response is returned, or an exception is thrown and `passThroughOnException()` | ||
| has been called, the response will be fetched from the specified upstream | ||
| instead: | ||
|
|
||
| ```js | ||
| import { Miniflare } from "miniflare"; | ||
|
|
||
| const mf = new Miniflare({ | ||
| script: ` | ||
| addEventListener("fetch", (event) => { | ||
| event.passThroughOnException(); | ||
| throw new Error(); | ||
| }); | ||
| `, | ||
| upstream: "https://miniflare.dev", | ||
| }); | ||
| // If you don't use the same upstream URL when dispatching, Miniflare will | ||
| // rewrite it to match the upstream | ||
| const res = await mf.dispatchFetch("https://miniflare.dev/core/fetch"); | ||
| console.log(await res.text()); // Source code of this page | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| --- | ||
| title: Core | ||
| order: 2 | ||
| --- | ||
|
|
||
| import { DirectoryListing } from "~/components"; | ||
|
|
||
| <DirectoryListing path="/core" /> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| --- | ||
| order: 3 | ||
| title: "📚 Modules" | ||
| --- | ||
|
|
||
| - [Modules Reference](/workers/cli-wrangler/configuration#modules) | ||
|
|
||
| ## Enabling Modules | ||
|
|
||
| Miniflare supports both the traditional `service-worker` and the newer `modules` formats for writing workers. To use the `modules` format, enable it with: | ||
hyperlint-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ```js | ||
| const mf = new Miniflare({ | ||
| modules: true, | ||
| }); | ||
| ``` | ||
|
|
||
| You can then use `modules` worker scripts like the following: | ||
|
|
||
| ```js | ||
| export default { | ||
| async fetch(request, env, ctx) { | ||
| // - `request` is the incoming `Request` instance | ||
| // - `env` contains bindings, KV namespaces, Durable Objects, etc | ||
| // - `ctx` contains `waitUntil` and `passThroughOnException` methods | ||
| return new Response("Hello Miniflare!"); | ||
| }, | ||
| async scheduled(controller, env, ctx) { | ||
| // - `controller` contains `scheduledTime` and `cron` properties | ||
| // - `env` contains bindings, KV namespaces, Durable Objects, etc | ||
| // - `ctx` contains the `waitUntil` method | ||
| console.log("Doing something scheduled..."); | ||
| }, | ||
| }; | ||
| ``` | ||
|
|
||
| <Aside type="warning" header="Warning"> | ||
|
|
||
| String scripts via the `script` option are supported using | ||
| the `modules` format, but you cannot import other modules using them. You must | ||
| use a script file via the `scriptPath` option for this. | ||
|
|
||
| </Aside> | ||
|
|
||
| ## Module Rules | ||
|
|
||
| Miniflare supports all module types: `ESModule`, `CommonJS`, `Text`, `Data` and | ||
| `CompiledWasm`. You can specify additional module resolution rules as follows: | ||
|
|
||
| ```js | ||
| const mf = new Miniflare({ | ||
| modulesRules: [ | ||
| { type: "ESModule", include: ["**/*.js"], fallthrough: true }, | ||
| { type: "Text", include: ["**/*.txt"] }, | ||
| ], | ||
| }); | ||
| ``` | ||
|
|
||
| ### Default Rules | ||
|
|
||
| The following rules are automatically added to the end of your modules rules | ||
| list. You can override them by specifying rules matching the same `globs`: | ||
|
|
||
| ```js | ||
| [ | ||
| { type: "ESModule", include: ["**/*.mjs"] }, | ||
| { type: "CommonJS", include: ["**/*.js", "**/*.cjs"] }, | ||
| ]; | ||
| ``` | ||
122 changes: 122 additions & 0 deletions
122
src/content/docs/workers/miniflare/core/multiple-workers.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| --- | ||
| order: 9 | ||
| title: "🔌 Multiple Workers" | ||
| --- | ||
|
|
||
| Miniflare allows you to run multiple workers in the same instance. All Workers can be defined at the same level, using the `workers` option. | ||
hyperlint-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
hyperlint-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Here's an example that uses a service binding to increment a value in a shared KV namespace: | ||
|
|
||
| ```js | ||
| import { Miniflare, Response } from "miniflare"; | ||
|
|
||
| const message = "The count is "; | ||
| const mf = new Miniflare({ | ||
| // Options shared between workers such as HTTP and persistence configuration | ||
| // should always be defined at the top level. | ||
| host: "0.0.0.0", | ||
| port: 8787, | ||
| kvPersist: true, | ||
|
|
||
| workers: [ | ||
| { | ||
| name: "worker", | ||
| kvNamespaces: { COUNTS: "counts" }, | ||
| serviceBindings: { | ||
| INCREMENTER: "incrementer", | ||
| // Service bindings can also be defined as custom functions, with access | ||
| // to anything defined outside Miniflare. | ||
| async CUSTOM(request) { | ||
| // `request` is the incoming `Request` object. | ||
| return new Response(message); | ||
| }, | ||
| }, | ||
| modules: true, | ||
| script: `export default { | ||
| async fetch(request, env, ctx) { | ||
| // Get the message defined outside | ||
| const response = await env.CUSTOM.fetch("http://host/"); | ||
| const message = await response.text(); | ||
|
|
||
| // Increment the count 3 times | ||
| await env.INCREMENTER.fetch("http://host/"); | ||
| await env.INCREMENTER.fetch("http://host/"); | ||
| await env.INCREMENTER.fetch("http://host/"); | ||
| const count = await env.COUNTS.get("count"); | ||
|
|
||
| return new Response(message + count); | ||
| } | ||
| }`, | ||
| }, | ||
| { | ||
| name: "incrementer", | ||
| // Note we're using the same `COUNTS` namespace as before, but binding it | ||
| // to `NUMBERS` instead. | ||
| kvNamespaces: { NUMBERS: "counts" }, | ||
| // Worker formats can be mixed-and-matched | ||
| script: `addEventListener("fetch", (event) => { | ||
| event.respondWith(handleRequest()); | ||
| }) | ||
| async function handleRequest() { | ||
| const count = parseInt((await NUMBERS.get("count")) ?? "0") + 1; | ||
| await NUMBERS.put("count", count.toString()); | ||
| return new Response(count.toString()); | ||
| }`, | ||
| }, | ||
| ], | ||
| }); | ||
| const res = await mf.dispatchFetch("http://localhost"); | ||
| console.log(await res.text()); // "The count is 3" | ||
| await mf.dispose(); | ||
| ``` | ||
|
|
||
| ## Routing | ||
|
|
||
| You can enable routing by specifying `routes` via the API, | ||
| using the | ||
| [standard route syntax](/workers/configuration/routing/routes/#matching-behavior). | ||
| Note port numbers are ignored: | ||
|
|
||
| ```js | ||
| const mf = new Miniflare({ | ||
| workers: [ | ||
| { | ||
| scriptPath: "./api/worker.js", | ||
| routes: ["http://127.0.0.1/api*", "api.mf/*"], | ||
| }, | ||
| ], | ||
| }); | ||
| ``` | ||
|
|
||
| When using hostnames that aren't `localhost` or `127.0.0.1`, you | ||
| may need to edit your computer's `hosts` file, so those hostnames resolve to | ||
| `localhost`. On Linux and macOS, this is usually at `/etc/hosts`. On Windows, | ||
| it's at `C:\Windows\System32\drivers\etc\hosts`. For the routes above, we would | ||
| need to append the following entries to the file: | ||
|
|
||
| ``` | ||
| 127.0.0.1 miniflare.test | ||
| 127.0.0.1 api.mf | ||
| ``` | ||
|
|
||
| Alternatively, you can customise the `Host` header when sending the request: | ||
|
|
||
| ```sh | ||
| # Dispatches to the "api" worker | ||
| $ curl "http://localhost:8787/todos/update/1" -H "Host: api.mf" | ||
| ``` | ||
|
|
||
| When using the API, Miniflare will use the request's URL to determine which | ||
| Worker to dispatch to. | ||
|
|
||
| ```js | ||
| // Dispatches to the "api" worker | ||
| const res = await mf.dispatchFetch("http://api.mf/todos/update/1", { ... }); | ||
| ``` | ||
|
|
||
| ## Durable Objects | ||
|
|
||
| Miniflare supports the `script_name` option for accessing Durable Objects | ||
| exported by other scripts. See | ||
| [📌 Durable Objects](/workers/miniflare/storage/durable-objects#using-a-class-exported-by-another-script) | ||
| for more details. | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.