diff --git a/.changeset/short-candles-give.md b/.changeset/short-candles-give.md new file mode 100644 index 00000000000..92662db2d41 --- /dev/null +++ b/.changeset/short-candles-give.md @@ -0,0 +1,7 @@ +--- +"wrangler": patch +--- + +Add experimental support for using the open-source Workers runtime [`workerd`](https://github.com/cloudflare/workerd) in `wrangler dev`. +Use `wrangler dev --experimental-local` to try it out! 🚀 +Note this feature is still under active development. diff --git a/package-lock.json b/package-lock.json index db62db0a2ae..0578d7dce27 100644 --- a/package-lock.json +++ b/package-lock.json @@ -866,6 +866,70 @@ "resolved": "packages/prerelease-registry", "link": true }, + "node_modules/@cloudflare/workerd-darwin-64": { + "version": "1.20220926.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20220926.0.tgz", + "integrity": "sha512-NbZ+NOviUvMHv4FLB2dlTIOp8Vh86qVCZEeQjaZ9NHjqKh9uyUEsKDuLIjea5XW+i9jHhyTlh3UQ4r2zcVhB3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-darwin-arm64": { + "version": "1.20220926.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20220926.0.tgz", + "integrity": "sha512-MwaAX/16YSu797/QhYU+x+Ddlk/JquTWD7vCtmhf+VeG+4Tt8/ru03MyRnnoI3vgXizox2yfQnfqI1YVlJOR8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-64": { + "version": "1.20220926.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20220926.0.tgz", + "integrity": "sha512-zk9t5RG9GmcSayh2mMPLSItKCu/EPiHIog5Spmfc5Qsr/GHhA0/X2LISjgvozGTNLFiVSyoUL9jegG4xvLMRSw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, + "node_modules/@cloudflare/workerd-linux-arm64": { + "version": "1.20220926.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20220926.0.tgz", + "integrity": "sha512-1s8fwDOWPdHiTmEiZDgQLyEBwi5IA191Uy7vxfLvC0rOpbNqEo4MVNJ4TiVf7xjiS7X6mJ0SFyz8aDf+lrgcQA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16" + } + }, "node_modules/@cloudflare/workers-types": { "version": "3.16.0", "license": "BSD-3-Clause" @@ -2713,6 +2777,58 @@ "node": ">=16.13" } }, + "node_modules/@miniflare/tre": { + "version": "3.0.0-next.1", + "resolved": "https://registry.npmjs.org/@miniflare/tre/-/tre-3.0.0-next.1.tgz", + "integrity": "sha512-y2K4VuM8AuMkuwWbEpA5CAZb4mc+KrLxiHBQ+HwJYMCfds7Og5nAEJZ11V9lEY8OhOaFDWBHrW0PH0MFvH1MzA==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-walk": "^8.2.0", + "capnp-ts": "^0.7.0", + "exit-hook": "^2.2.1", + "get-port": "^5.1.1", + "glob-to-regexp": "^0.4.1", + "kleur": "^4.1.5", + "stoppable": "^1.1.0", + "undici": "^5.10.0", + "workerd": "^1.20220926.0", + "zod": "^3.18.0" + }, + "engines": { + "node": ">=16.13" + } + }, + "node_modules/@miniflare/tre/node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@miniflare/tre/node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@miniflare/tre/node_modules/undici": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.10.0.tgz", + "integrity": "sha512-c8HsD3IbwmjjbLvoZuRI26TZic+TSEe8FPMLLOkN1AfYRhdjnKBU6yL+IwcSCbdZiX4e5t0lfMDLDCqj4Sq70g==", + "dev": true, + "engines": { + "node": ">=12.18" + } + }, "node_modules/@miniflare/watcher": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/@miniflare/watcher/-/watcher-2.9.0.tgz", @@ -4287,8 +4403,9 @@ } }, "node_modules/acorn": { - "version": "8.7.0", - "license": "MIT", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "bin": { "acorn": "bin/acorn" }, @@ -5386,6 +5503,22 @@ "url": "https://opencollective.com/browserslist" } }, + "node_modules/capnp-ts": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/capnp-ts/-/capnp-ts-0.7.0.tgz", + "integrity": "sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==", + "dev": true, + "dependencies": { + "debug": "^4.3.1", + "tslib": "^2.2.0" + } + }, + "node_modules/capnp-ts/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, "node_modules/capture-exit": { "version": "2.0.0", "license": "ISC", @@ -14176,8 +14309,9 @@ } }, "node_modules/kleur": { - "version": "4.1.4", - "license": "MIT", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", "engines": { "node": ">=6" } @@ -19231,6 +19365,16 @@ "node": ">= 0.8" } }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "dev": true, + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, "node_modules/stream-browserify": { "version": "2.0.2", "dev": true, @@ -21348,6 +21492,24 @@ "errno": "~0.1.7" } }, + "node_modules/workerd": { + "version": "1.20220926.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20220926.0.tgz", + "integrity": "sha512-pJmF9adeO0/Utbs3Fq/u9H6can6SxtWtSEKGpxPekBlUECwNhUoVYxjFFx1aS6BpIa1bgugvc1JMJA+td6QTcQ==", + "dev": true, + "bin": { + "workerd": "bin/workerd" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "@cloudflare/workerd-darwin-64": "1.20220926.0", + "@cloudflare/workerd-darwin-arm64": "1.20220926.0", + "@cloudflare/workerd-linux-64": "1.20220926.0", + "@cloudflare/workerd-linux-arm64": "1.20220926.0" + } + }, "node_modules/workers-chat-demo": { "resolved": "fixtures/workers-chat-demo", "link": true @@ -21621,6 +21783,15 @@ "commander": "^2.20.3" } }, + "node_modules/zod": { + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.19.1.tgz", + "integrity": "sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/zwitch": { "version": "2.0.2", "dev": true, @@ -21722,6 +21893,7 @@ "@databases/sql": "^3.2.0", "@iarna/toml": "^3.0.0", "@microsoft/api-extractor": "^7.28.3", + "@miniflare/tre": "3.0.0-next.1", "@types/better-sqlite3": "^7.6.0", "@types/busboy": "^1.5.0", "@types/command-exists": "^1.2.0", @@ -21767,7 +21939,7 @@ "jest-websocket-mock": "^2.3.0", "mime": "^3.0.0", "msw": "^0.47.1", - "npx-import": "^1.0.2", + "npx-import": "^1.1.3", "open": "^8.4.0", "p-queue": "^7.2.0", "pretty-bytes": "^6.0.0", @@ -23542,6 +23714,34 @@ "typescript": "^4.5.5" } }, + "@cloudflare/workerd-darwin-64": { + "version": "1.20220926.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20220926.0.tgz", + "integrity": "sha512-NbZ+NOviUvMHv4FLB2dlTIOp8Vh86qVCZEeQjaZ9NHjqKh9uyUEsKDuLIjea5XW+i9jHhyTlh3UQ4r2zcVhB3Q==", + "dev": true, + "optional": true + }, + "@cloudflare/workerd-darwin-arm64": { + "version": "1.20220926.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20220926.0.tgz", + "integrity": "sha512-MwaAX/16YSu797/QhYU+x+Ddlk/JquTWD7vCtmhf+VeG+4Tt8/ru03MyRnnoI3vgXizox2yfQnfqI1YVlJOR8Q==", + "dev": true, + "optional": true + }, + "@cloudflare/workerd-linux-64": { + "version": "1.20220926.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20220926.0.tgz", + "integrity": "sha512-zk9t5RG9GmcSayh2mMPLSItKCu/EPiHIog5Spmfc5Qsr/GHhA0/X2LISjgvozGTNLFiVSyoUL9jegG4xvLMRSw==", + "dev": true, + "optional": true + }, + "@cloudflare/workerd-linux-arm64": { + "version": "1.20220926.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20220926.0.tgz", + "integrity": "sha512-1s8fwDOWPdHiTmEiZDgQLyEBwi5IA191Uy7vxfLvC0rOpbNqEo4MVNJ4TiVf7xjiS7X6mJ0SFyz8aDf+lrgcQA==", + "dev": true, + "optional": true + }, "@cloudflare/workers-types": { "version": "3.16.0" }, @@ -24790,6 +24990,45 @@ "@miniflare/shared": "2.9.0" } }, + "@miniflare/tre": { + "version": "3.0.0-next.1", + "resolved": "https://registry.npmjs.org/@miniflare/tre/-/tre-3.0.0-next.1.tgz", + "integrity": "sha512-y2K4VuM8AuMkuwWbEpA5CAZb4mc+KrLxiHBQ+HwJYMCfds7Og5nAEJZ11V9lEY8OhOaFDWBHrW0PH0MFvH1MzA==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-walk": "^8.2.0", + "capnp-ts": "^0.7.0", + "exit-hook": "^2.2.1", + "get-port": "^5.1.1", + "glob-to-regexp": "^0.4.1", + "kleur": "^4.1.5", + "stoppable": "^1.1.0", + "undici": "^5.10.0", + "workerd": "^1.20220926.0", + "zod": "^3.18.0" + }, + "dependencies": { + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true + }, + "undici": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.10.0.tgz", + "integrity": "sha512-c8HsD3IbwmjjbLvoZuRI26TZic+TSEe8FPMLLOkN1AfYRhdjnKBU6yL+IwcSCbdZiX4e5t0lfMDLDCqj4Sq70g==", + "dev": true + } + } + }, "@miniflare/watcher": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/@miniflare/watcher/-/watcher-2.9.0.tgz", @@ -25960,7 +26199,9 @@ } }, "acorn": { - "version": "8.7.0" + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==" }, "acorn-globals": { "version": "6.0.0", @@ -26670,6 +26911,24 @@ "caniuse-lite": { "version": "1.0.30001306" }, + "capnp-ts": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/capnp-ts/-/capnp-ts-0.7.0.tgz", + "integrity": "sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==", + "dev": true, + "requires": { + "debug": "^4.3.1", + "tslib": "^2.2.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + } + } + }, "capture-exit": { "version": "2.0.0", "requires": { @@ -32277,7 +32536,9 @@ "version": "6.0.3" }, "kleur": { - "version": "4.1.4" + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==" }, "legacy-site-app": { "version": "file:fixtures/legacy-site-app" @@ -35583,6 +35844,12 @@ "version": "2.0.1", "dev": true }, + "stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "dev": true + }, "stream-browserify": { "version": "2.0.2", "dev": true, @@ -37045,6 +37312,18 @@ "errno": "~0.1.7" } }, + "workerd": { + "version": "1.20220926.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20220926.0.tgz", + "integrity": "sha512-pJmF9adeO0/Utbs3Fq/u9H6can6SxtWtSEKGpxPekBlUECwNhUoVYxjFFx1aS6BpIa1bgugvc1JMJA+td6QTcQ==", + "dev": true, + "requires": { + "@cloudflare/workerd-darwin-64": "1.20220926.0", + "@cloudflare/workerd-darwin-arm64": "1.20220926.0", + "@cloudflare/workerd-linux-64": "1.20220926.0", + "@cloudflare/workerd-linux-arm64": "1.20220926.0" + } + }, "workers-chat-demo": { "version": "file:fixtures/workers-chat-demo" }, @@ -37061,6 +37340,7 @@ "@miniflare/core": "2.9.0", "@miniflare/d1": "2.9.0", "@miniflare/durable-objects": "2.9.0", + "@miniflare/tre": "3.0.0-next.1", "@types/better-sqlite3": "^7.6.0", "@types/busboy": "^1.5.0", "@types/command-exists": "^1.2.0", @@ -37112,7 +37392,7 @@ "miniflare": "2.9.0", "msw": "^0.47.1", "nanoid": "^3.3.3", - "npx-import": "^1.0.2", + "npx-import": "^1.1.3", "open": "^8.4.0", "p-queue": "^7.2.0", "path-to-regexp": "^6.2.0", @@ -38127,6 +38407,12 @@ "validator": "^13.7.0" } }, + "zod": { + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.19.1.tgz", + "integrity": "sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==", + "dev": true + }, "zwitch": { "version": "2.0.2", "dev": true diff --git a/packages/wrangler/package.json b/packages/wrangler/package.json index 979e337b92c..fce4d2c78f9 100644 --- a/packages/wrangler/package.json +++ b/packages/wrangler/package.json @@ -112,6 +112,7 @@ "@databases/sql": "^3.2.0", "@iarna/toml": "^3.0.0", "@microsoft/api-extractor": "^7.28.3", + "@miniflare/tre": "3.0.0-next.1", "@types/better-sqlite3": "^7.6.0", "@types/busboy": "^1.5.0", "@types/command-exists": "^1.2.0", @@ -157,7 +158,7 @@ "jest-websocket-mock": "^2.3.0", "mime": "^3.0.0", "msw": "^0.47.1", - "npx-import": "^1.0.2", + "npx-import": "^1.1.3", "open": "^8.4.0", "p-queue": "^7.2.0", "pretty-bytes": "^6.0.0", diff --git a/packages/wrangler/scripts/deps.ts b/packages/wrangler/scripts/deps.ts index 59e6d45f187..acdc4dd45f7 100644 --- a/packages/wrangler/scripts/deps.ts +++ b/packages/wrangler/scripts/deps.ts @@ -12,6 +12,7 @@ export const EXTERNAL_DEPENDENCIES = [ "miniflare", "@miniflare/core", "@miniflare/durable-objects", + "@miniflare/tre", // TODO: remove once Miniflare 3 moved in miniflare package // todo - bundle miniflare too "selfsigned", "source-map", diff --git a/packages/wrangler/src/bundle.ts b/packages/wrangler/src/bundle.ts index 9495e974261..0fb33eefb00 100644 --- a/packages/wrangler/src/bundle.ts +++ b/packages/wrangler/src/bundle.ts @@ -79,6 +79,7 @@ export async function bundleWorker( targetConsumer: "dev" | "publish"; local: boolean; testScheduled?: boolean | undefined; + experimentalLocalStubCache: boolean | undefined; } ): Promise { const { @@ -99,6 +100,7 @@ export async function bundleWorker( firstPartyWorkerDevFacade, targetConsumer, testScheduled, + experimentalLocalStubCache, } = options; // We create a temporary directory for any oneoff files we @@ -233,12 +235,20 @@ export async function bundleWorker( // At this point, inputEntry points to the entry point we want to build. + const inject: string[] = []; + if (checkFetch) inject.push(checkedFetchFileToInject); + if (experimentalLocalStubCache) { + inject.push( + path.resolve(getBasePath(), "templates/experimental-local-cache-stubs.js") + ); + } + const result = await esbuild.build({ entryPoints: [inputEntry.file], bundle: true, absWorkingDir: entry.directory, outdir: destination, - inject: checkFetch ? [checkedFetchFileToInject] : [], + inject, external: ["__STATIC_CONTENT_MANIFEST"], format: entry.format === "modules" ? "esm" : "iife", target: "es2020", diff --git a/packages/wrangler/src/dev.tsx b/packages/wrangler/src/dev.tsx index 17931b0e2fb..33e1efa6598 100644 --- a/packages/wrangler/src/dev.tsx +++ b/packages/wrangler/src/dev.tsx @@ -62,6 +62,7 @@ interface DevArgs { "jsx-fragment"?: string; tsconfig?: string; local?: boolean; + "experimental-local"?: boolean; minify?: boolean; var?: string[]; define?: string[]; @@ -234,6 +235,20 @@ export function devOptions(yargs: Argv): Argv { type: "boolean", default: false, // I bet this will a point of contention. We'll revisit it. }) + .option("experimental-local", { + describe: "Run on my machine using the Cloudflare Workers runtime", + type: "boolean", + default: false, + }) + .check((argv) => { + if (argv.local && argv["experimental-local"]) { + throw new Error( + "--local and --experimental-local are mutually exclusive. " + + "Please select one or the other." + ); + } + return true; + }) .option("minify", { describe: "Minify the script", type: "boolean", @@ -405,7 +420,9 @@ export async function startDev(args: StartDevOptions) { nodeCompat={nodeCompat} build={configParam.build || {}} define={{ ...configParam.define, ...cliDefines }} - initialMode={args.local ? "local" : "remote"} + initialMode={ + args.local || args.experimentalLocal ? "local" : "remote" + } jsxFactory={args["jsx-factory"] || configParam.jsx_factory} jsxFragment={args["jsx-fragment"] || configParam.jsx_fragment} tsconfig={args.tsconfig ?? configParam.tsconfig} @@ -444,6 +461,7 @@ export async function startDev(args: StartDevOptions) { firstPartyWorker={configParam.first_party_worker} sendMetrics={configParam.send_metrics} testScheduled={args["test-scheduled"]} + experimentalLocal={args.experimentalLocal} /> ); } @@ -560,6 +578,7 @@ export async function startApiDev(args: StartDevOptions) { firstPartyWorker: configParam.first_party_worker, sendMetrics: configParam.send_metrics, testScheduled: args.testScheduled, + experimentalLocal: undefined, }); } diff --git a/packages/wrangler/src/dev/dev.tsx b/packages/wrangler/src/dev/dev.tsx index 616479e5731..6dc0e09c61f 100644 --- a/packages/wrangler/src/dev/dev.tsx +++ b/packages/wrangler/src/dev/dev.tsx @@ -153,6 +153,7 @@ export type DevProps = { firstPartyWorker: boolean | undefined; sendMetrics: boolean | undefined; testScheduled: boolean | undefined; + experimentalLocal: boolean | undefined; }; export function DevImplementation(props: DevProps): JSX.Element { @@ -213,6 +214,7 @@ function InteractiveDevSession(props: DevProps) { type DevSessionProps = DevProps & { local: boolean; + experimentalLocal?: boolean; }; function DevSession(props: DevSessionProps) { @@ -274,6 +276,7 @@ function DevSession(props: DevSessionProps) { // Enable the bundling to know whether we are using dev or publish targetConsumer: "dev", testScheduled: props.testScheduled ?? false, + experimentalLocalStubCache: props.local && props.experimentalLocal, }); return props.local ? ( @@ -300,6 +303,7 @@ function DevSession(props: DevSessionProps) { inspect={props.inspect} onReady={props.onReady} enablePagesAssetsServiceBinding={props.enablePagesAssetsServiceBinding} + experimentalLocal={props.experimentalLocal} /> ) : ( { + return Object.fromEntries(values.map((value) => [value, value])); +} + function useLocalWorker({ name: workerName, bundle, @@ -88,9 +103,11 @@ function useLocalWorker({ onReady, logPrefix, enablePagesAssetsServiceBinding, + experimentalLocal, }: LocalProps) { // TODO: pass vars via command line const local = useRef(); + const experimentalLocalRef = useRef(); const removeSignalExitListener = useRef<() => void>(); const [inspectorUrl, setInspectorUrl] = useState(); @@ -187,6 +204,40 @@ function useLocalWorker({ enablePagesAssetsServiceBinding, }); + if (experimentalLocal) { + // TODO: refactor setupMiniflareOptions so we don't need to parse here + const miniflare2Options: MiniflareOptions = JSON.parse(forkOptions[0]); + const options: Miniflare3Options = { + ...miniflare2Options, + // Miniflare 3 distinguishes between binding name and namespace/bucket + // IDs. For now, just use the same value as we did in Miniflare 2. + // TODO: use defined KV preview ID if any + kvNamespaces: arrayToObject(miniflare2Options.kvNamespaces), + r2Buckets: arrayToObject(miniflare2Options.r2Buckets), + // TODO: pass-through collected modules instead of getting Miniflare + // to collect them again + }; + + logger.log("⎔ Starting an experimental local server..."); + + if (Miniflare === undefined) { + ({ Miniflare } = await npxImport< + // eslint-disable-next-line @typescript-eslint/consistent-type-imports + typeof import("@miniflare/tre") + >("@miniflare/tre")); + } + + const mf = new Miniflare(options); + experimentalLocalRef.current = mf; + removeSignalExitListener.current = onExit((_code, _signal) => { + logger.log("⎔ Shutting down experimental local server."); + mf.dispose(); + experimentalLocalRef.current = undefined; + }); + await mf.ready; + return; + } + const nodeOptions = setupNodeOptions({ inspect, ip, inspectorPort }); logger.log("⎔ Starting a local server..."); @@ -279,9 +330,16 @@ function useLocalWorker({ logger.log("⎔ Shutting down local server."); local.current?.kill(); local.current = undefined; - removeSignalExitListener.current && removeSignalExitListener.current(); - removeSignalExitListener.current = undefined; } + if (experimentalLocalRef.current) { + logger.log("⎔ Shutting down experimental local server."); + // Initialisation errors are also thrown asynchronously by dispose(). + // The catch() above should've caught them though. + experimentalLocalRef.current?.dispose().catch(() => {}); + experimentalLocalRef.current = undefined; + } + removeSignalExitListener.current?.(); + removeSignalExitListener.current = undefined; }; }, [ bundle, @@ -314,6 +372,7 @@ function useLocalWorker({ logPrefix, onReady, enablePagesAssetsServiceBinding, + experimentalLocal, ]); return { inspectorUrl }; } @@ -458,7 +517,10 @@ export function setupMiniflareOptions({ logPrefix, workerDefinitions, enablePagesAssetsServiceBinding, -}: SetupMiniflareOptionsProps): MiniflareOptions { +}: SetupMiniflareOptionsProps): { + miniflareCLIPath: string; + forkOptions: string[]; +} { // It's now getting _really_ messy now with Pages ASSETS binding outside and the external Durable Objects inside. const options = { name: workerName, diff --git a/packages/wrangler/src/dev/start-server.ts b/packages/wrangler/src/dev/start-server.ts index 27e4cea45cc..7ca8ff82cfc 100644 --- a/packages/wrangler/src/dev/start-server.ts +++ b/packages/wrangler/src/dev/start-server.ts @@ -91,6 +91,7 @@ export async function startDevServer( services: props.bindings.services, firstPartyWorkerDevFacade: props.firstPartyWorker, testScheduled: props.testScheduled, + experimentalLocalStubCache: props.experimentalLocal, }); //run local now @@ -159,6 +160,7 @@ async function runEsbuild({ services, firstPartyWorkerDevFacade, testScheduled, + experimentalLocalStubCache, }: { entry: Entry; destination: string | undefined; @@ -176,6 +178,7 @@ async function runEsbuild({ workerDefinitions: WorkerRegistry; firstPartyWorkerDevFacade: boolean | undefined; testScheduled?: boolean; + experimentalLocalStubCache: boolean | undefined; }): Promise { if (!destination) return; @@ -213,6 +216,7 @@ async function runEsbuild({ targetConsumer: "dev", // We are starting a dev server local: false, testScheduled, + experimentalLocalStubCache, }); return { diff --git a/packages/wrangler/src/dev/use-esbuild.ts b/packages/wrangler/src/dev/use-esbuild.ts index b7d096d1ff9..7ee1fec52db 100644 --- a/packages/wrangler/src/dev/use-esbuild.ts +++ b/packages/wrangler/src/dev/use-esbuild.ts @@ -40,6 +40,7 @@ export function useEsbuild({ local, targetConsumer, testScheduled, + experimentalLocalStubCache, }: { entry: Entry; destination: string | undefined; @@ -61,6 +62,7 @@ export function useEsbuild({ local: boolean; targetConsumer: "dev" | "publish"; testScheduled: boolean; + experimentalLocalStubCache: boolean | undefined; }): EsbuildBundle | undefined { const [bundle, setBundle] = useState(); const { exit } = useApp(); @@ -128,6 +130,7 @@ export function useEsbuild({ local, targetConsumer, testScheduled, + experimentalLocalStubCache, }); // Capture the `stop()` method to use as the `useEffect()` destructor. @@ -188,6 +191,7 @@ export function useEsbuild({ local, targetConsumer, testScheduled, + experimentalLocalStubCache, ]); return bundle; } diff --git a/packages/wrangler/src/publish.ts b/packages/wrangler/src/publish.ts index 83c283c8ff8..f5f04fcb998 100644 --- a/packages/wrangler/src/publish.ts +++ b/packages/wrangler/src/publish.ts @@ -434,6 +434,7 @@ See https://developers.cloudflare.com/workers/platform/compatibility-dates for m // This could potentially cause issues as we no longer have identical behaviour between dev and publish? targetConsumer: "publish", local: false, + experimentalLocalStubCache: false, } ); diff --git a/packages/wrangler/templates/experimental-local-cache-stubs.js b/packages/wrangler/templates/experimental-local-cache-stubs.js new file mode 100644 index 00000000000..a0e51e1c0f2 --- /dev/null +++ b/packages/wrangler/templates/experimental-local-cache-stubs.js @@ -0,0 +1,27 @@ +// `workerd` currently throws on any use of the Cache API. Workers Sites +// requires the Cache API to function though, so stub it out to no-ops, like in +// regular `wrangler dev`. + +class Cache { + async put(req, res) {} + + async match(req, options) {} + + async delete(req, options) { + return false; + } +} + +class CacheStorage { + #cache = new Cache(); + + get default() { + return this.#cache; + } + + async open(cacheName) { + return this.#cache; + } +} + +globalThis.caches = new CacheStorage();