diff --git a/__tests__/test-server-workerd.js b/__tests__/test-server-workerd.js index 4e9b2a9..13b197a 100644 --- a/__tests__/test-server-workerd.js +++ b/__tests__/test-server-workerd.js @@ -10,7 +10,7 @@ // build step for it. Instead, we're getting by configuring the worker in vitest.config.ts by // just specifying the raw JS modules. -import { newWorkersRpcResponse } from "../dist/index.js"; +import { newWorkersRpcResponse } from "../dist/index-workers.js"; import { RpcTarget, DurableObject } from "cloudflare:workers"; // TODO(cleanup): At present we clone the implementation of Counter and TestTarget because diff --git a/__tests__/workerd.test.ts b/__tests__/workerd.test.ts index 980a9b3..9f52a74 100644 --- a/__tests__/workerd.test.ts +++ b/__tests__/workerd.test.ts @@ -5,7 +5,7 @@ /// import { expect, it, describe } from "vitest"; import { RpcStub as NativeRpcStub, RpcTarget as NativeRpcTarget, env, DurableObject } from "cloudflare:workers"; -import { newHttpBatchRpcSession, newWebSocketRpcSession, RpcStub, RpcTarget } from "../src/index.js"; +import { newHttpBatchRpcSession, newWebSocketRpcSession, RpcStub, RpcTarget } from "../src/index-workers.js"; import { Counter, TestTarget } from "./test-util.js"; class JsCounter extends RpcTarget { diff --git a/package.json b/package.json index 89f6ee6..3f9a7b3 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,10 @@ ], "exports": { ".": { - "import": "./dist/index.js", + "import": { + "workerd": "./dist/index-workers.js", + "default": "./dist/index.js" + }, "types": "./dist/index.d.ts" } }, diff --git a/src/core.ts b/src/core.ts index ef98a7f..81ff88a 100644 --- a/src/core.ts +++ b/src/core.ts @@ -3,6 +3,7 @@ // https://opensource.org/license/mit import type { RpcTargetBranded, __RPC_TARGET_BRAND } from "./types.js"; +import { WORKERS_MODULE_SYMBOL } from "./symbols.js" // Polyfill Symbol.dispose for browsers that don't support it yet if (!Symbol.dispose) { @@ -12,11 +13,7 @@ if (!Symbol.asyncDispose) { (Symbol as any).asyncDispose = Symbol.for('asyncDispose'); } -let workersModuleName = navigator.userAgent === "Cloudflare-Workers" ? "cloudflare:workers" : null; -let workersModule: any; -if (workersModuleName) { - workersModule = await import(/* @vite-ignore */workersModuleName); -} +let workersModule: any = (globalThis as any)[WORKERS_MODULE_SYMBOL]; export interface RpcTarget { [__RPC_TARGET_BRAND]: never; diff --git a/src/index-workers.ts b/src/index-workers.ts new file mode 100644 index 0000000..840ecb8 --- /dev/null +++ b/src/index-workers.ts @@ -0,0 +1,8 @@ +// Copyright (c) 2025 Cloudflare, Inc. +// Licensed under the MIT license found in the LICENSE.txt file or at: +// https://opensource.org/license/mit + +// When building for Cloudflare Workers, this file is the top-level module, instead of index.ts. +// This ensures that inject-workers-module.js gets imported before the rest of the library. +import "./inject-workers-module.js"; +export * from "./index.js"; diff --git a/src/inject-workers-module.ts b/src/inject-workers-module.ts new file mode 100644 index 0000000..24f714e --- /dev/null +++ b/src/inject-workers-module.ts @@ -0,0 +1,14 @@ +// Copyright (c) 2025 Cloudflare, Inc. +// Licensed under the MIT license found in the LICENSE.txt file or at: +// https://opensource.org/license/mit + +import { WORKERS_MODULE_SYMBOL } from "./symbols.js"; + +// Import cloudflare:workers and stick it in the global scope where in can be used conditionally. +// As long as inject-workers-module.ts is imported before the rest of the library, this allows the +// library to set up automatic interoperability with Cloudflare Workers' built-in RPC. +// +// Meanwhile, we define our `exports` in package.json such that when building on Workers, this +// module is in fact imported first. +import * as cfw from "cloudflare:workers"; +(globalThis as any)[WORKERS_MODULE_SYMBOL] = cfw; diff --git a/src/symbols.ts b/src/symbols.ts new file mode 100644 index 0000000..d810ed6 --- /dev/null +++ b/src/symbols.ts @@ -0,0 +1,5 @@ +// Copyright (c) 2025 Cloudflare, Inc. +// Licensed under the MIT license found in the LICENSE.txt file or at: +// https://opensource.org/license/mit + +export let WORKERS_MODULE_SYMBOL = Symbol("workers-module"); diff --git a/tsup.config.ts b/tsup.config.ts index 39cdb17..1246f77 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -5,8 +5,9 @@ import { defineConfig } from 'tsup' export default defineConfig({ - entry: ['src/index.ts'], + entry: ['src/index.ts', 'src/index-workers.ts'], format: ['esm'], + external: ['cloudflare:workers'], dts: true, sourcemap: true, clean: true, diff --git a/vitest.config.ts b/vitest.config.ts index ad0c203..9a65677 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -49,7 +49,7 @@ export default defineConfig({ }, { type: "ESModule", - path: "./dist/index.js", + path: "./dist/index-workers.js", }, ], durableObjects: {