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

feat(deploy): add cloudflare context to platform object #872

Conversation

rmarscher
Copy link
Contributor

@rmarscher rmarscher commented Sep 11, 2024

Example usage from a server component:

import { unstable_getPlatformObject } from 'waku/server';

const getData = async () => {
  const { env, executionCtx } = unstable_getPlatformObject() as { env: Env; executionCtx: ExecutionContext };
  executionCtx?.waitUntil(
    new Promise<void>((resolve) => {
      console.log("Waiting for 5 seconds")
      setTimeout(() => {
        console.log("OK, done waiting")
        resolve()
      }, 5000)
    }),
  )
  const { results } = await env.DB.prepare(
    "SELECT * FROM users WHERE user_id = ?",
  )
    .bind(userId)
    .all();
  return results;
};

Server console output:

Waiting for 5 seconds
[wrangler:inf] GET /about 200 OK (30ms)
[wrangler:inf] GET /assets/jsx-runtime-BjG_zV1W.js 304 Not Modified (6ms)
[wrangler:inf] GET /assets/index-CbskofAj.js 304 Not Modified (7ms)
[wrangler:inf] GET /assets/_layout-Shb4QlRw.css 304 Not Modified (9ms)
[wrangler:inf] GET /assets/rsc2-c69df7b3e.js 200 OK (11ms)
[wrangler:inf] GET /assets/client-kczTGGZ_.js 304 Not Modified (16ms)
[wrangler:inf] GET /assets/indexHtml-DCalQi_d.js 304 Not Modified (18ms)
[wrangler:inf] GET /assets/client-CMyJdxTj.js 304 Not Modified (21ms)
[wrangler:inf] GET /assets/rsc0-ba005381c.js 304 Not Modified (4ms)
[wrangler:inf] GET /images/favicon.png 304 Not Modified (3ms)
OK, done waiting

The page was already sent to the client and loaded while the promise was still executing.

It is necessary to cast the Cloudflare types. See https://developers.cloudflare.com/workers/languages/typescript/#generate-types-that-match-your-workers-configuration-experimental for info on generating types for your project.

Copy link

vercel bot commented Sep 11, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
waku ✅ Ready (Inspect) Visit Preview Sep 14, 2024 11:02pm

Copy link

codesandbox-ci bot commented Sep 11, 2024

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

@dai-shi
Copy link
Owner

dai-shi commented Sep 12, 2024

Using the getEnv API until #827 is resolved

#860 was my answer. Can you try it? getEnv is for strings.

@rmarscher rmarscher marked this pull request as draft September 13, 2024 19:47
@rmarscher rmarscher force-pushed the feat/cloudflare-adapter-execution-context branch from 5e66745 to 9d9d5a7 Compare September 14, 2024 21:26
@rmarscher rmarscher force-pushed the feat/cloudflare-adapter-execution-context branch from 9d9d5a7 to be9cedb Compare September 14, 2024 22:27
@rmarscher rmarscher changed the title Expose Cloudflare execution context to server components feat(deploy): add cloudflare context to platform object Sep 14, 2024
@rmarscher rmarscher force-pushed the feat/cloudflare-adapter-execution-context branch from be9cedb to 1992a35 Compare September 14, 2024 22:31
@rmarscher rmarscher force-pushed the feat/cloudflare-adapter-execution-context branch from 1992a35 to 006eeca Compare September 14, 2024 22:36
@rmarscher
Copy link
Contributor Author

I'm getting close. I just need to do testing on this latest implementation. Does https://github.com/dai-shi/waku/pull/872/files#diff-cd6a8e530f81183dc69573add03d2338dfb64976b74eec5eb387e66a713e6522R45-R53 look good? I'm trying to remove non-string vars that Cloudflare puts in env before passing to the runner.

In addition to the bindings, I found that cloudflare allows JSON in env vars: https://developers.cloudflare.com/workers/configuration/environment-variables/#add-environment-variables-via-wrangler

@rmarscher
Copy link
Contributor Author

There are some typescript issues due to differences in workerd built-in types like Request/Response but I worked around them with casting.

Example usage from a server component:

```ts
import { unstable_getPlatformObject } from 'waku/server';

const getData = async () => {
  const { env, executionCtx } = unstable_getPlatformObject() as { env: Env; executionCtx: ExecutionContext };
  executionCtx?.waitUntil(
    new Promise<void>((resolve) => {
      console.log("Waiting for 5 seconds");
      setTimeout(() => {
        console.log("OK, done waiting");
        resolve();
      }, 5000);
    }),
  );
  const { results } = await env.DB.prepare(
    "SELECT * FROM users WHERE user_id = ?",
  )
    .bind(userId)
    .all();
  return results;
};
```
@@ -1,41 +1,75 @@
import { Hono } from 'hono';
import { unstable_getPlatformObject } from 'waku/server';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might not change anything real, but for consistency. (Will be refactored anyway.)

Suggested change
import { unstable_getPlatformObject } from 'waku/server';
import { unstable_getPlatformObject } from '../../server.js';

import { runner } from '../hono/runner.js';
import type {
ExportedHandler,
fetch,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing. So:

Suggested change
fetch,
fetch as CloudflareFetch,

throw new Error('serveWaku is not initialized');
}
const platform = unstable_getPlatformObject();
platform.honoContext = c;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not good.
The platform object is something stable all the time. It shouldn't change for each request.
unstable_getCustomContext is for each request. And, the hono context is already exposed. #852

Comment on lines +178 to +180
export function unstable_getPlatformObject<
T = Record<string, unknown>,
>(): PlatformObject<T> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe asserting types is more appropriate than annotating types, because it never be type safe.

},
// TODO ability to add other handlers or Durable Objects?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless we do this, this PR doesn't provide any more capability than #852.

@rmarscher
Copy link
Contributor Author

@dai-shi Thank you reviewing the PR. You mentioned the context API before and I saw #852 but I hadn't found unstable_getCustomContext yet.

Is it correct to access it like this? unstable_getCustomContext().__hono_context

import type { ExecutionContext } from '@cloudflare/workers-types/experimental';
import { unstable_getCustomContext } from 'waku/server';

const getData = async ({ userId }: { userId: string }) => {
  const { env, executionCtx } = unstable_getCustomContext().__hono_context as {
    env: Env
    executionCtx: ExecutionContext
  };
  executionCtx?.waitUntil(
    new Promise<void>((resolve) => {
      console.log("Waiting for 5 seconds");
      setTimeout(() => {
        console.log("OK, done waiting");
        resolve();
      }, 5000);
    }),
  );
  const { results } = await env.DB.prepare("SELECT * FROM users WHERE user_id = ?")
    .bind(userId)
    .all();
  return results;
}

I think I will close this PR.

Re:
#872 (comment)
#879 (comment)

How could we allow a developer to inject handlers and export Durable Object classes from their worker index file?

The way I have been doing it is to build waku and then copy in a custom index.js file to the dist folder.

We could make that an option to the cloudflare deploy vite plugin - a path to an alternate worker entry file.

Maybe a cloudflare deploy vite plugin option could point to an alternate worker entry file that would be used instead of the default.

Or could there be another way to implement it using getPlatformObject()?

@dai-shi
Copy link
Owner

dai-shi commented Sep 16, 2024

Is it correct to access it like this?

Looks good.
I wasn't aware that the db was in the hono context.
https://developers.cloudflare.com/d1/examples/d1-and-hono/

How could we allow a developer to inject handlers and export Durable Object classes from their worker index file?

Oh, I think I misunderstood something.
Please note that I have zero experience with Cloudflare.
Would you create a new discussion and describe the goal briefly?
(It sounds somewhat related to the idea of say adding another Vercel function, which is impossible for now.)

@dai-shi dai-shi closed this Sep 16, 2024
@dai-shi
Copy link
Owner

dai-shi commented Sep 16, 2024

@rmarscher see #884

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature Request: An API for accessing platform specific data/information/APIs (e.g. the Cloudflare ones)
2 participants