diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index 3223c3722..a92243b64 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -48,6 +48,8 @@ module.exports = { { text: "๐Ÿ—บ Source Maps", link: "/source-maps.html" }, { text: "๐Ÿ•ธ Web Standards", link: "/standards.html" }, { text: "๐Ÿ“„ HTMLRewriter", link: "/html-rewriter.html" }, + { text: "โšก๏ธ Live Reload", link: "/live-reload.html" }, + { text: "๐Ÿ“… Compatibility Dates", link: "/compatibility.html" }, { text: "๐Ÿคน Jest Environment", link: "/jest.html" }, ], }, diff --git a/docs/api.md b/docs/api.md index 5bbb76522..ce76b1812 100644 --- a/docs/api.md +++ b/docs/api.md @@ -98,6 +98,46 @@ const mf = new Miniflare({ ... }); await mf.reload(); ``` +Miniflare will emit a `reload` event whenever it reloads too: + +```js +const mf = new Miniflare({ ... }); +mf.addEventListener("reload", (event) => { + console.log("Worker reloaded!"); +}); +``` + +### Updating Options and the Global Scope + +You can use the `setOptions` method to update the options of an existing +`Miniflare` instance. This accepts the same options object as the +`new Miniflare` constructor, applies those options, then reloads the worker. + +```js +const mf = new Miniflare({ + script: "...", + kvNamespaces: ["TEST_NAMESPACE"], + bindings: { KEY: "value1" }, +}); + +// Only updates `bindings`, leaves `script` and `kvNamespaces` alone +await mf.setOptions({ + bindings: { KEY: "value2" }, +}); +``` + +You can also access the global scope of the sandbox directly using the +`getGlobalScope` method. Ideally, use should use the `setOptions` method when +updating the environment dynamically though: + +```js +const mf = new Miniflare({ + globals: { KEY: "value1" }, +}); +const globalScope = await mf.getGlobalScope(); +globalScope.KEY = "value2"; +``` + ### Dispatching Events `dispatchFetch` and `dispatchScheduled` dispatch `fetch` and `scheduled` events @@ -138,7 +178,7 @@ returns a [Node.js `http.Server`](https://nodejs.org/api/http.html#http_class_http_server) instance: -```js{10} +```js{11} import { Miniflare } from "miniflare"; const mf = new Miniflare({ @@ -153,6 +193,52 @@ const server = await mf.startServer(); console.log("Listening on :5000"); ``` +You can also just create the server with `createServer` and start it yourself. +Note that you're then responsible for setting the correct host and port: + +```js +const mf = new Miniflare({ + script: "...", + port: 5000, +}); +const server = await mf.createServer(); +const { HTTPPlugin } = await mf.getPlugins(); +server.listen(HTTPPlugin.port, () => { + console.log(`Listening on :${HTTPPlugin.port}`); +}); +``` + +#### `Request#cf` Object + +By default, Miniflare will fetch the `Request#cf` object from a trusted +Cloudflare endpoint. You can disable this behaviour, using the `cfFetch` option: + +```js +const mf = new Miniflare({ + cfFetch: false, +}); +``` + +You can also provide a custom request metadata provider, which takes the +incoming Node request and may look-up information in a geo-IP database: + +```js +const mf = new Miniflare({ + async metaProvider(req) { + return { + forwardedProto: req.headers["X-Forwarded-Proto"], + realIp: req.headers["X-Forwarded-For"], + cf: { + // Could get these from a geo-IP database + colo: "SFO", + country: "US", + // ... + }, + }; + }, +}); +``` + ### HTTPS Server To start an HTTPS server instead, set the `https` option. To use an @@ -197,6 +283,21 @@ const mf = new Miniflare({ If both a string and path are specified for an option (e.g. `httpsKey` and `httpsKeyPath`), the string will be preferred. +### CRON Scheduler + +To start a CRON scheduler like the CLI's, use the `startScheduler` method. This +will dispatch `scheduled` events according to the specified CRON expressions: + +```js +const mf = new Miniflare({ + crons: ["30 * * * *"], +}); +const scheduler = await mf.startScheduler(); +// ... +// Stop dispatching events +await scheduler.dispose(); +``` + ### Logging By default, `[mf:*]` logs as seen in the CLI are disabled when using the API. To diff --git a/docs/builds.md b/docs/builds.md index 46524ae60..a1eefb158 100644 --- a/docs/builds.md +++ b/docs/builds.md @@ -8,9 +8,9 @@ Custom builds can be enabled by specifying a build command. You can also specify a path to run the build in, and a path to watch: ```shell -$ miniflare --build-command "npm run build" +$ miniflare --build-command "npm run build" # or -B $ miniflare --build-command "npm run build" --build-base-path "build" -$ miniflare --build-command "npm run build" --build-watch-path "source" +$ miniflare --build-command "npm run build" --build-watch-path "source1" --build-watch-path "source2" ``` ```toml @@ -27,7 +27,7 @@ const mf = new Miniflare({ buildCommand: "npm run build", // Below options are optional buildBasePath: "build", - buildWatchPath: "source", // Defaults to "src" if command set + buildWatchPaths: ["source1", "source2"], // Defaults to "src" if command set }); ``` @@ -49,6 +49,14 @@ assumed. ::: + +::: tip +When running your custom build script, Miniflare will set the environment +variable `MINIFLARE=1`. You can use this to customise build behaviour during +local development. +::: + + ## Wrangler Builds Miniflare supports building `webpack` and `rust` type Wrangler projects too. diff --git a/docs/cache.md b/docs/cache.md index 40caa257e..8d86fe442 100644 --- a/docs/cache.md +++ b/docs/cache.md @@ -58,10 +58,19 @@ When using Redis, each key will be prefixed with the namespace. If you're using this with the API, make sure you call `dispose` on your `Miniflare` instance to close database connections. + +::: warning +Redis support is not included by default. You must install an optional peer dependency: +``` +$ npm install -D @miniflare/storage-redis +``` +::: + + ## Manipulating Outside Workers For testing, it can be useful to put/match data from cache outside a worker. You -can do this with the `getCache` method: +can do this with the `getCaches` method: ```js{23-33} import { Miniflare, Response } from "miniflare"; diff --git a/docs/cli.md b/docs/cli.md index 6dab07e39..eeecd1c9b 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -18,6 +18,16 @@ You can also install and invoke the CLI using `npx`: $ npx miniflare ``` + +::: warning +Miniflare requires at least **Node.js 16.7.0**, as it makes extensive use of +recently added web standards. You should use the latest Node.js version if +possible, as Cloudflare Workers use a very up-to-date version of V8. Consider +using a Node.js version manager such as https://volta.sh/ or +https://github.com/nvm-sh/nvm. +::: + + ## Usage If `worker.js` contains the following worker script: @@ -123,6 +133,18 @@ main = "./worker.js" } ``` +### `Request#cf` Object + +For a more accurate development experience, Miniflare automatically fetches the +`cf` object for incoming requests (containing IP and location data) from a +trusted Cloudflare endpoint, caching it for 30 days. You can disable this +behaviour, falling back to a default `cf` object, using the `--no-cf-fetch` +flag: + +```shell +$ miniflare worker.js --no-cf-fetch +``` + ### HTTPS Server By default, Miniflare starts an HTTP server. To start an HTTPS server instead, diff --git a/docs/compatibility.md b/docs/compatibility.md new file mode 100644 index 000000000..5b86546af --- /dev/null +++ b/docs/compatibility.md @@ -0,0 +1,56 @@ +# ๐Ÿ“… Compatibility Dates + +- [Compatibility Dates Reference](https://developers.cloudflare.com/workers/platform/compatibility-dates) + +## Compatibility Dates + +Like the Workers runtime, 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. + +```shell +$ miniflare --compat-date 2021-11-12 +``` + +```toml +# wrangler.toml +compatibility_date = "2021-11-12" +``` + +```js +const mf = new Miniflare({ + compatibilityDate: "2021-11-12", +}); +``` + +## Compatibility Flags + +Miniflare also lets you opt-in/out of specific changes using compatibility +flags: + +```shell +$ miniflare --compat-flag formdata_parser_supports_files --compat-flag durable_object_fetch_allows_relative_url +``` + +```toml +# wrangler.toml +compatibility_flags = [ + "formdata_parser_supports_files", + "durable_object_fetch_allows_relative_url" +] +``` + +```js +const mf = new Miniflare({ + compatibilityFlags: [ + "formdata_parser_supports_files", + "durable_object_fetch_allows_relative_url", + ], +}); +``` + +Specifically Miniflare supports the following flags: + +- [`durable_object_fetch_requires_full_url`/`durable_object_fetch_allows_relative_url`](https://developers.cloudflare.com/workers/platform/compatibility-dates#durable-object-stubfetch-requires-a-full-url) +- [`fetch_refuses_unknown_protocols`/`fetch_treats_unknown_protocols_as_http`](https://developers.cloudflare.com/workers/platform/compatibility-dates#fetch-improperly-interprets-unknown-protocols-as-http) +- [`formdata_parser_supports_files`/`formdata_parser_converts_files_to_strings`](https://developers.cloudflare.com/workers/platform/compatibility-dates#formdata-parsing-supports-file) diff --git a/docs/durable-objects.md b/docs/durable-objects.md index 1e8a85713..b85a2f127 100644 --- a/docs/durable-objects.md +++ b/docs/durable-objects.md @@ -79,6 +79,35 @@ When using Redis, each key will be prefixed with the object name and instance. If you're using this with the API, make sure you call `dispose` on your `Miniflare` instance to close database connections. + +::: warning +Redis support is not included by default. You must install an optional peer dependency: +``` +$ npm install -D @miniflare/storage-redis +``` +::: + + +## Validation + +Like the real Workers runtime, Miniflare will throw errors when: + +- The string passed to `DurableObjectNamespace#idFromString(hexId)` is not 64 + hex digits +- The hex-ID passed to `DurableObjectNamespace#idFromString(hexId)` is for a + different Durable Object +- The ID passed to `DurableObjectNamespace#get(id)` is for a different Durable + Object +- Keys are greater than `2KiB` or `undefined` +- Values are greater than `32KiB` +- Attempting to `get`, `put` or `delete` more than `128` keys +- Attempting to modify more than `128` keys in a transaction +- Attempting to `put` an `undefined` value +- Attempting to list keys with a negative `limit` +- Attempting to perform an operation in a rolledback transaction or in a + transaction that has already committed +- Attempting to call `deleteAll()` in a transaction + ## Manipulating Outside Workers For testing, it can be useful to put/get data from Durable Object storage diff --git a/docs/jest.md b/docs/jest.md index 4daf332d0..97d41fb65 100644 --- a/docs/jest.md +++ b/docs/jest.md @@ -13,7 +13,7 @@ $ npm install -D jest-environment-miniflare jest In the following examples, we'll assume your `package.json` contains `"type": "module"`, and that you're using a tool to bundle your worker. See -[โšก๏ธ Developing with esbuild](/esbuild.html) for an example. +[โšก๏ธ Developing with esbuild](/recipes/esbuild.html) for an example. To enable the Miniflare environment, set the [`testEnvironment` option](https://jestjs.io/docs/configuration#testenvironment-string) diff --git a/docs/kv.md b/docs/kv.md index 768aa9c31..97e6508a5 100644 --- a/docs/kv.md +++ b/docs/kv.md @@ -84,6 +84,31 @@ Metadata will be prefixed with the namespace and `:meta:`. If you're using this with the API, make sure you call `dispose` on your `Miniflare` instance to close database connections. + +::: warning +Redis support is not included by default. You must install an optional peer dependency: +``` +$ npm install -D @miniflare/storage-redis +``` +::: + + +## Validation + +Like the real Workers runtime, Miniflare will throw errors when: + +- Keys are empty, `.`, `..`, `undefined`, or greater than `512B` when UTF-8 + encoded +- Values are greater than `25MiB` +- Metadata is greater than `1KiB` +- The `cacheTtl` option is less than `60s` +- The `expirationTtl` option is non-numeric, less than or equal 0, or less than + `60s` +- The `expiration` option is non-numeric, less than or equal the current time, + or less than `60s` in the future +- The `limit` passed to `KVNamespace#list()` is non-numeric, less than or equal + `0`, or greater than `1000` + ## Manipulating Outside Workers For testing, it can be useful to put/get data from KV outside a worker. You can diff --git a/docs/live-reload.md b/docs/live-reload.md new file mode 100644 index 000000000..f94b3c806 --- /dev/null +++ b/docs/live-reload.md @@ -0,0 +1,51 @@ +# โšก๏ธ Live Reload + +## Enabling Live Reload + +Miniflare can automatically refresh your browser when your worker script +changes. + +```shell +$ miniflare --live-reload +``` + +```toml +# wrangler.toml +[miniflare] +live_reload = true +``` + +```js +const mf = new Miniflare({ + liveReload: true, +}); +``` + + +::: tip +When using the CLI, if `--live-reload` is set, `--watch` is automatically +assumed. +::: + + +Miniflare will only inject the `