-
Notifications
You must be signed in to change notification settings - Fork 778
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(miniflare): Implement KV/Assets plugin and Workers Assets simula…
…tor (#6403) This commit adds a new KV/Assets plugin and an Assets Worker in Miniflare, that are meant to emulate Workers with Assets in local development.
- Loading branch information
1 parent
37dc86f
commit 00f340f
Showing
17 changed files
with
494 additions
and
8 deletions.
There are no files selected for viewing
This file contains 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 @@ | ||
--- | ||
"miniflare": minor | ||
"@cloudflare/workers-shared": minor | ||
--- | ||
|
||
feat: Extend KV plugin behaviour to support Workers assets | ||
|
||
This commit extends Miniflare's KV plugin's behaviour to support Workers assets, and therefore enables the emulation of Workers with assets in local development. |
This file contains 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 @@ | ||
<p>Learn more about Workers with Assets soon!</p> |
This file contains 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 |
---|---|---|
@@ -1 +1 @@ | ||
<h1>Hello Workers + Assets World!</h1> | ||
<h1>Hello Workers + Assets World 🚀!</h1> |
This file contains 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
This file contains 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
This file contains 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,99 @@ | ||
import { KVOptionsSchema } from "miniflare"; | ||
import SCRIPT_KV_ASSETS from "worker:kv/assets"; | ||
import { z } from "zod"; | ||
import { Service, Worker_Binding } from "../../runtime"; | ||
import { getAssetsBindingsNames, SharedBindings } from "../../workers"; | ||
import { kProxyNodeBinding } from "../shared"; | ||
import { KV_PLUGIN_NAME } from "./constants"; | ||
|
||
export interface AssetsOptions { | ||
assetsPath: string; | ||
assetsKVBindingName?: string; | ||
assetsManifestBindingName?: string; | ||
} | ||
|
||
export function isWorkersWithAssets( | ||
options: z.infer<typeof KVOptionsSchema> | ||
): options is AssetsOptions { | ||
return options.assetsPath !== undefined; | ||
} | ||
|
||
const SERVICE_NAMESPACE_ASSET = `${KV_PLUGIN_NAME}:asset`; | ||
|
||
export function buildAssetsManifest(): Uint8Array { | ||
const buffer = new ArrayBuffer(20); | ||
const assetManifest = new Uint8Array(buffer); // [0, 0, 0, ..., 0, 0] | ||
// this will signal to Asset Server Worker that its running in a | ||
// local dev "context" | ||
assetManifest.set([1], 0); // [1, 0, 0, ..., 0, 0] | ||
|
||
return assetManifest; | ||
} | ||
|
||
export async function getAssetsBindings( | ||
options: AssetsOptions | ||
): Promise<Worker_Binding[]> { | ||
const assetsBindings = getAssetsBindingsNames( | ||
options?.assetsKVBindingName, | ||
options?.assetsManifestBindingName | ||
); | ||
|
||
const assetsManifest = buildAssetsManifest(); | ||
|
||
return [ | ||
{ | ||
// this is the binding to the KV namespace that the assets are in. | ||
name: assetsBindings.ASSETS_KV_NAMESPACE, | ||
kvNamespace: { name: SERVICE_NAMESPACE_ASSET }, | ||
}, | ||
{ | ||
// this is the binding to an ArrayBuffer containing the binary-encoded | ||
// assets manifest. | ||
name: assetsBindings.ASSETS_MANIFEST, | ||
data: assetsManifest, | ||
}, | ||
]; | ||
} | ||
|
||
export async function getAssetsNodeBindings( | ||
options: AssetsOptions | ||
): Promise<Record<string, unknown>> { | ||
const assetsManifest = buildAssetsManifest(); | ||
const assetsBindings = getAssetsBindingsNames( | ||
options?.assetsKVBindingName, | ||
options?.assetsManifestBindingName | ||
); | ||
|
||
return { | ||
[assetsBindings.ASSETS_KV_NAMESPACE]: kProxyNodeBinding, | ||
[assetsBindings.ASSETS_MANIFEST]: assetsManifest, | ||
}; | ||
} | ||
|
||
export function getAssetsServices(options: AssetsOptions): Service[] { | ||
const storageServiceName = `${SERVICE_NAMESPACE_ASSET}:storage`; | ||
const storageService: Service = { | ||
name: storageServiceName, | ||
disk: { path: options.assetsPath, writable: true }, | ||
}; | ||
const namespaceService: Service = { | ||
name: SERVICE_NAMESPACE_ASSET, | ||
worker: { | ||
compatibilityDate: "2023-07-24", | ||
compatibilityFlags: ["nodejs_compat"], | ||
modules: [ | ||
{ | ||
name: "assets.worker.js", | ||
esModule: SCRIPT_KV_ASSETS(), | ||
}, | ||
], | ||
bindings: [ | ||
{ | ||
name: SharedBindings.MAYBE_SERVICE_BLOBS, | ||
service: { name: storageServiceName }, | ||
}, | ||
], | ||
}, | ||
}; | ||
return [storageService, namespaceService]; | ||
} |
This file contains 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
This file contains 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,33 @@ | ||
import { SharedBindings } from "miniflare:shared"; | ||
import { KVParams } from "./constants"; | ||
|
||
interface Env { | ||
[SharedBindings.MAYBE_SERVICE_BLOBS]: Fetcher; | ||
} | ||
|
||
export default <ExportedHandler<Env>>{ | ||
async fetch(request, env) { | ||
// Only permit reads | ||
if (request.method !== "GET") { | ||
const message = `Cannot ${request.method.toLowerCase()}() with Workers Assets namespace`; | ||
return new Response(message, { status: 405, statusText: message }); | ||
} | ||
|
||
// Decode key | ||
const url = new URL(request.url); | ||
let key = url.pathname.substring(1); // Strip leading "/" | ||
|
||
if (url.searchParams.get(KVParams.URL_ENCODED)?.toLowerCase() === "true") { | ||
key = decodeURIComponent(key); | ||
} | ||
|
||
const blobsService = env[SharedBindings.MAYBE_SERVICE_BLOBS]; | ||
if (key === "" || key === "/") { | ||
return new Response("Not Found", { | ||
status: 404, | ||
}); | ||
} else { | ||
return blobsService.fetch(new URL(key, "http://placeholder")); | ||
} | ||
}, | ||
}; |
This file contains 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
14 changes: 14 additions & 0 deletions
14
packages/miniflare/test/fixtures/assets/worker-with-custom-assets-bindings.ts
This file contains 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,14 @@ | ||
interface Env { | ||
// custom kv binding name | ||
CUSTOM_ASSETS_NAMESPACE: KVNamespace; | ||
} | ||
|
||
export default { | ||
async fetch(request: Request, env: Env) { | ||
const url = new URL(request.url); | ||
const { pathname } = url; | ||
|
||
const content = await env.CUSTOM_ASSETS_NAMESPACE.get(pathname); | ||
return new Response(content); | ||
}, | ||
}; |
14 changes: 14 additions & 0 deletions
14
packages/miniflare/test/fixtures/assets/worker-with-default-assets-bindings.ts
This file contains 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,14 @@ | ||
interface Env { | ||
// this is the default kv binding name | ||
__STATIC_ASSETS_CONTENT: KVNamespace; | ||
} | ||
|
||
export default { | ||
async fetch(request: Request, env: Env) { | ||
const url = new URL(request.url); | ||
const { pathname } = url; | ||
|
||
const content = await env.__STATIC_ASSETS_CONTENT.get(pathname); | ||
return new Response(content); | ||
}, | ||
}; |
Oops, something went wrong.