Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Challenges and Solutions for Using Types in Turborepo with Service Bindings #3113

Open
j4tmr opened this issue Nov 14, 2024 · 7 comments
Open
Assignees
Labels
types Related to @cloudflare/workers-types

Comments

@j4tmr
Copy link

j4tmr commented Nov 14, 2024

I am using Cloudflare Workers with tRPC and Turborepo. I wrote a service with Workers and created an API using Service Bindings.

// @package/cfw-services
import { WorkerEntrypoint } from 'cloudflare:workers';
export class ServiceWorker extends WorkerEntrypoint<Env> {
        // Currently, entrypoints without a named handler are not supported
	async fetch(request: Request) {
		return new Response(null, { status: 404 });
	}
}
// api env
import type { ServiceWorker } from '@packages/cfw-services';
export interface Env {
	SERVICES: Service<ServiceWorker>;
}

My issue is that when compiling the tRPC client, it references 'cloudflare:workers', which is defined in @cloudflare/workers-types but is not an exported module. My solution is, in the project where the tRPC client adding

"compilerOptions": {
    "types": [
      "@cloudflare/workers-types"
    ]
}

in the tsconfig.json.

This temporarily solves the issue, but in the future, any other app that needs to use the tRPC API will also need to add a reference to @cloudflare/workers-types in their tsconfig. So I’m considering whether it would be better to directly add an export for types like WorkerEntrypoint in the 'cloudflare:workers' module.

@j4tmr j4tmr added the types Related to @cloudflare/workers-types label Nov 14, 2024
@github-project-automation github-project-automation bot moved this to Untriaged in workers-sdk Nov 14, 2024
@petebacondarwin
Copy link
Contributor

Is the problem here that your tRPC server has an import on cloudflare:workers that is somehow being pulled into the tRPC client typings where that module has no typings? Can you flesh out the tRPC server side of the example above so it is concrete what is happening? Or perhaps provide a reproduction we could play with?

@j4tmr
Copy link
Author

j4tmr commented Nov 15, 2024

@petebacondarwin In short, tRPC server imports cloudflare:workers because types like WorkerEntrypoint can’t be directly referenced from @cloudflare/workers-types as they aren’t exported.

@j4tmr
Copy link
Author

j4tmr commented Nov 15, 2024

@petebacondarwin https://github.com/j4tmr/test-cfw-types. The project is still a bit complex. To put it simply, both the API and services are Cloudflare Workers, while the frontend is a Next.js project. You just need to cd apps/frontend and then npm run build to get a general idea. To fix it: in the tsconfig of the frontend project, add:

"types": [
      "@cloudflare/workers-types"
    ]

Then, start the API project, and the build should pass. The main issue is what I mentioned above, which aligns with your understanding—using cloudflare:workers in Turborepo has some optimization challenges.

@penalosa
Copy link
Collaborator

penalosa commented Dec 9, 2024

@j4tmr—to clarify here, are you trying to use the WorkerEntrypoint type in a non-Workers environment?

@j4tmr
Copy link
Author

j4tmr commented Dec 10, 2024

@penalosa
To start with a simple reply, I just need this type to be used in other places. Actually, there are a few things here that confuse me:
First, when using service bindings, how do you export a type from one worker to be used by another worker? In my Turborepo setup, I create a package that uses worker types. Then, in the apps directory, I create worker1 and import the WorkerEntrypoint class from the package I created. This becomes worker1, and at the same time, worker2 can also use this type. This way, I can directly leverage TypeScript’s features.
However, the problem arises when using RPC (e.g., tRPC). These types may require the use of types that you want to ensure are only used in workers, such as the cloudflare:workers type, which isn’t exported. At this point, since it can’t be exported, I have to also reference your types in my tRPC project, such as a Next.js project.

@penalosa
Copy link
Collaborator

penalosa commented Dec 16, 2024

For worker-to-worker communication you should be able to treat Service as a generic, and pass in your entrypoint class, i.e.

// worker-a/index.ts
export class WorkerA extends WorkerEntrypoint {
  helloWorld() {
    return "Hello World"
  }
}
// worker-configuration.d.ts in worker-b
interface Env {
  ...
  WORKER_A: Service<typeof import("../worker-a/index.ts)").WorkerA>
  ...
}

However, this does get complicated with RPC client-server boundaries, since using types that extend WorkerEntrypoint directly in client code won't work (and the Service generic that does e.g. promise pipelining won't be available or relevant). I think in that case the best option would be to create a shared interface that your entrypoint class implements, which can then be used in both client and server?

I'd be curious to know more about your use case though—are you directly exposing a worker entrypoint over trpc? How does that work?

@j4tmr
Copy link
Author

j4tmr commented Dec 17, 2024

@penalosa I have many workers for handling different services, and one worker for the API (api-worker) using tRPC to call other service workers, which communicate via RPC. The issue appears to be related to TypeScript types. For example, a service worker method that has a TypeScript return type causes the API worker to depend on these types. This results in the entire service type being dependent on WorkerEntrypoint, which causes tRPC to eventually require the WorkerEntrypoint type. This means that these types might eventually be used outside of the Cloudflare Worker environment. However, in the creation of @cloudflare/workers-types, these types are not exported because they are intended to be used only within the Cloudflare Worker environment. I'm considering whether these types should be exported when creating this package, allowing people to import them, because using these types doesn’t necessarily mean they are using in the Cloudflare environment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
types Related to @cloudflare/workers-types
Projects
Status: Untriaged
Development

No branches or pull requests

4 participants