Skip to content

Commit

Permalink
Modify router-worker logic to allow for running user-worker ahead of …
Browse files Browse the repository at this point in the history
…assets

- Adds logic to run user-worker ahead of assets
- Moves vitest from worker-shared root into asset-worker
- Creates new vitest unit suite for router-worker
  • Loading branch information
WillTaylorDev committed Nov 20, 2024
1 parent f1f508e commit 3ab8173
Show file tree
Hide file tree
Showing 11 changed files with 231 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/funny-dingos-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/workers-shared": minor
---

Option to invoke user worker ahead of assets
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { defineProject, mergeConfig } from "vitest/config";
import configShared from "../../vitest.shared";
import configShared from "../../../vitest.shared.js";

export default mergeConfig(
configShared,
defineProject({
test: {
include: ["asset-worker/tests/**.{test,spec}.{ts,js}"],
include: ["tests/**.{test,spec}.{ts,js}"],
globals: true,
},
})
Expand Down
7 changes: 5 additions & 2 deletions packages/workers-shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@
"deploy:asset-worker": "CLOUDFLARE_API_TOKEN=$WORKERS_DEPLOY_AND_CONFIG_CLOUDFLARE_API_TOKEN pnpx wrangler versions upload --experimental-versions -c asset-worker/wrangler.toml",
"deploy:router-worker": "CLOUDFLARE_API_TOKEN=$WORKERS_DEPLOY_AND_CONFIG_CLOUDFLARE_API_TOKEN pnpx wrangler versions upload --experimental-versions -c router-worker/wrangler.toml",
"dev": "pnpm run clean && concurrently -n bundle:asset-worker,bundle:router-worker -c blue,magenta \"pnpm run bundle:asset-worker --watch\" \"pnpm run bundle:router-worker --watch\"",
"test": "vitest",
"test:ci": "vitest run",
"test": "CI=true concurrently --group -n router-worker,asset-worker \"pnpm run test:router-worker\" \"pnpm run test:asset-worker\"",
"test:asset-worker": "vitest -c asset-worker/vitest.config.mts --dir asset-worker",
"test:ci": "pnpm run test",
"test:router-worker": "vitest -c router-worker/vitest.config.mts --dir router-worker",
"types:emit": "tsc index.ts --declaration --emitDeclarationOnly --declarationDir ./dist"
},
"dependencies": {
Expand All @@ -46,6 +48,7 @@
},
"devDependencies": {
"@cloudflare/eslint-config-worker": "workspace:*",
"@cloudflare/vitest-pool-workers": "latest",
"@cloudflare/workers-tsconfig": "workspace:*",
"@cloudflare/workers-types": "^4.20241106.0",
"@types/mime": "^3.0.4",
Expand Down
66 changes: 66 additions & 0 deletions packages/workers-shared/router-worker/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { createExecutionContext } from "cloudflare:test";
import { describe, expect, it } from "vitest";
import { default as worker } from "../src/index";

describe("unit tests", async () => {
it("fails if specify running user worker ahead of assets, without user worker", async () => {
const request = new Request("https://example.com");
const ctx = createExecutionContext();

const env = {
CONFIG: {
invoke_user_worker_ahead_of_assets: true,
has_user_worker: false,
},
} as typeof env;

void expect(
async () => await worker.fetch(request, env, ctx)
).rejects.toThrowError(
"Fetch for user worker without having a user worker binding"
);
});

it("it returns fetch from user worker when invoke_user_worker_ahead_of_assets true", async () => {
const request = new Request("https://example.com");
const ctx = createExecutionContext();

const env = {
CONFIG: {
invoke_user_worker_ahead_of_assets: true,
has_user_worker: true,
},
USER_WORKER: {
async fetch(_: Request): Promise<Response> {
return new Response("hello from user worker");
},
},
} as typeof env;

const response = await worker.fetch(request, env, ctx);
expect(await response.text()).toEqual("hello from user worker");
});

it("it returns fetch from asset worker when matching existing asset path", async () => {
const request = new Request("https://example.com");
const ctx = createExecutionContext();

const env = {
CONFIG: {
invoke_user_worker_ahead_of_assets: false,
has_user_worker: false,
},
ASSET_WORKER: {
async fetch(_: Request): Promise<Response> {
return new Response("hello from asset worker");
},
async unstable_canFetch(_: Request): Promise<boolean> {
return true;
},
},
} as typeof env;

const response = await worker.fetch(request, env, ctx);
expect(await response.text()).toEqual("hello from asset worker");
});
});
15 changes: 15 additions & 0 deletions packages/workers-shared/router-worker/__tests__/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"lib": ["ES2020"],
"types": [
"@cloudflare/workers-types/experimental",
"@cloudflare/vitest-pool-workers"
],
"moduleResolution": "bundler",
"noEmit": true,
"skipLibCheck": true
},
"include": ["**/*.ts"]
}
13 changes: 13 additions & 0 deletions packages/workers-shared/router-worker/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ export default {
}

const maybeSecondRequest = request.clone();

// User's configuration indicates they want user-Worker to run ahead of any
// assets. Do not provide any fallback logic.
if (env.CONFIG.invoke_user_worker_ahead_of_assets) {
if (!env.CONFIG.has_user_worker) {
throw new Error(
"Fetch for user worker without having a user worker binding"
);
}
return env.USER_WORKER.fetch(maybeSecondRequest);
}

// Otherwise, we try to first fetch assets, falling back to user-Worker.
if (env.CONFIG.has_user_worker) {
if (await env.ASSET_WORKER.unstable_canFetch(request)) {
analytics.setData({ dispatchtype: DISPATCH_TYPE.ASSETS });
Expand Down
13 changes: 13 additions & 0 deletions packages/workers-shared/router-worker/vitest.config.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";

export default defineWorkersConfig({
test: {
poolOptions: {
workers: {
wrangler: {
configPath: "./wrangler.toml",
},
},
},
},
});
1 change: 1 addition & 0 deletions packages/workers-shared/router-worker/wrangler.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ account_id = "0f1b8aa119a907021f659042f95ea9ba"
workers_dev = false
main = "src/index.ts"
compatibility_date = "2024-07-31"
compatibility_flags = ["nodejs_compat"]

[version_metadata]
binding = "VERSION_METADATA"
Expand Down
2 changes: 1 addition & 1 deletion packages/workers-shared/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"sourceMap": true,
"forceConsistentCasingInFileNames": true,
"useUnknownInCatchVariables": false,
"types": ["@cloudflare/workers-types/experimental"]
"types": ["@cloudflare/workers-types/experimental", "@types/node"]
},
"include": ["**/*.ts", "vitest.config.mts"],
"exclude": ["node_modules", "dist", "**/tests", "**/*.test.ts"]
Expand Down
1 change: 1 addition & 0 deletions packages/workers-shared/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { z } from "zod";

export const RoutingConfigSchema = z.object({
has_user_worker: z.boolean().optional(),
invoke_user_worker_ahead_of_assets: z.boolean().optional(),
});

export const AssetConfigSchema = z.object({
Expand Down
109 changes: 109 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 3ab8173

Please sign in to comment.