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

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

Closed
dario-piotrowicz opened this issue Aug 11, 2024 · 8 comments · Fixed by #884

Comments

@dario-piotrowicz
Copy link

Hello 👋

I'm opening this issue to ask if there is any intention or plan to support platform specific APIs (and I am specifically thinking of the Cloudflare APIs).

I think it might be worth clarifying the above: There is a Cloudflare deployment option to allow Waku applications to be deployed to Cloudflare Pages, this is already very nice, but one of the main reasons/incentives for developers to deploy to Cloudflare Workers/Pages is so that their application can make use of the various resources that the Cloudflare network provides (mainly bindings and waitUntil). So ideally Waku should provide an API to access such platform specific APIs (I would also imagine that other hosting platforms would have similar APIs but I haven't really looked into that to be honest).

I could not see this mentioned in the roadmap so I figured I could ask 🙂

Additionally I think @rmarscher already started experimenting with this in PR #795 + gist. But from what I can tell:

  • his dev plugin hasn't been included in his PR, is this something that should not built-in into Waku itself?
  • it seems like he's taking the executionContext and simply making it available through getEnv (source), is that really the cleanest/best API? (for one, if would override any pre-existing env variable called executionContext)
  • either way, he didn't provide a production build solution (e.g. he's exposing executionContext only in dev mode)

(@rmarscher please do correct me if I got any of the above wrong 🙏)

So I would imagine that some extra work/thoughts needs to be put into it 🤔

Personally I think a new getPlatform utility (equivalent to the existing getEnv) would make sense, it could expose the platform specific APIs plus any other useful data/information regarding the current platform.


Other meta-framework examples

Most meta-frameworks do provide such APIs.

As React meta-frameworks go:

  • Remix natively supports this, providing a context object in their loaders API (docs)

  • @cloudflare/next-on-pages, Cloudflare's official adapter for Next.js applications also provides an API for this (docs) (Next.js by itself doesn't have such API, since it doesn't really have a built-in Cloudflare deployment solution)

as for non-react meta-frameworks, most of them do provide such APIs built-in, for example qwik, svelte-kit, astro and nuxt/nitro.

@dai-shi
Copy link
Owner

dai-shi commented Aug 12, 2024

Thanks for asking.

There's no explicit plan, but I know there's a need.
I wonder if we keep using getEnv for this purpose, instead of adding getPlatform. (getEnv had to return serializable values, but it's no longer the case after #762.)
FYI, we plan to make it extensible with vite plugins. #806

@dai-shi
Copy link
Owner

dai-shi commented Aug 12, 2024

cc @jkhaui

@dario-piotrowicz
Copy link
Author

Thanks for asking.

There's no explicit plan, but I know there's a need. I wonder if we keep using getEnv for this purpose, instead of adding getPlatform. (getEnv had to return serializable values, but it's no longer the case after #762.) FYI, we plan to make it extensible with vite plugins. #806

I see, I'm glad you know that there's a need and are willing to enable it 🫶

Yes reusing getEnv (similarly to @rmarscher's POC) would work, potentially I would prefer getPlatform for a more clear API, but I understand that maybe not introducing an extra API can help keep the Waku API more concise/lighter 👍

@rmarscher
Copy link
Contributor

either way, he didn't provide a production build solution (e.g. he's exposing executionContext only in dev mode)

Hi! Cloudflare injects those bindings into the environment automatically on their servers so my solution is only needed for the dev server.

I wasn't sure how to handle the wrangler peer dependency which is why I just posted an example instead of a package for now.

@jkhaui
Copy link

jkhaui commented Aug 17, 2024

@dario-piotrowicz as was mentioned, feel free to include your suggestions for an adapter system in #806

Would be great to hear more about how other frameworks like Remix implement their adapter systems

@dai-shi
Copy link
Owner

dai-shi commented Aug 19, 2024

I wonder if we keep using getEnv for this purpose, instead of adding getPlatform.

On second thought, getEnv should be kept for string. So, I would add a new API. As it would be used for #815 and others, getPlatform might not be the right name. 🤔

@rmarscher
Copy link
Contributor

rmarscher commented Aug 25, 2024

Since Cloudflare injects the bindings into the environment variables, the runtime adapter would need to move them from env to the new API location. Cloudflare also has a context object with a waitUntil method that can be useful. https://developers.cloudflare.com/workers/runtime-apis/context/

Hono adds the Cloudflare context to Hono's context as the "executionContext" - https://hono.dev/docs/api/context#executionctx

I like the idea of a context API for server components that adapters can populate.

@dai-shi
Copy link
Owner

dai-shi commented Aug 25, 2024

we already have "context" which changes for each request, so I need a different name for things that are consistent between requests.

rmarscher added a commit to rmarscher/waku that referenced this issue Sep 11, 2024
Using the getEnv API for now until dai-shi#827 is resolved

Example usage:

```ts
  const ctx = getEnv("ctx") as unknown as ExecutionContext | undefined;
  ctx?.waitUntil(
    new Promise<void>((resolve) => {
      console.log("Waiting for 5 seconds")
      setTimeout(() => {
        console.log("OK, done waiting")
        resolve()
      }, 5000)
    }),
  )
```

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.
rmarscher added a commit to rmarscher/waku that referenced this issue Sep 11, 2024
Using the getEnv API for now until dai-shi#827 is resolved

Example usage:

```ts
  const ctx = getEnv("ctx") as unknown as ExecutionContext | undefined;
  ctx?.waitUntil(
    new Promise<void>((resolve) => {
      console.log("Waiting for 5 seconds")
      setTimeout(() => {
        console.log("OK, done waiting")
        resolve()
      }, 5000)
    }),
  )
```

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 for now.
See https://developers.cloudflare.com/workers/languages/typescript/#generate-types-that-match-your-workers-configuration-experimental
for info on generating types for your project.
rmarscher added a commit to rmarscher/waku that referenced this issue Sep 11, 2024
Using the getEnv API for now until dai-shi#827 is resolved

Example usage:

```ts
  const ctx = getEnv("executionContext") as unknown as ExecutionContext | undefined;
  ctx?.waitUntil(
    new Promise<void>((resolve) => {
      console.log("Waiting for 5 seconds")
      setTimeout(() => {
        console.log("OK, done waiting")
        resolve()
      }, 5000)
    }),
  )
```

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 for now.
See https://developers.cloudflare.com/workers/languages/typescript/#generate-types-that-match-your-workers-configuration-experimental
for info on generating types for your project.
rmarscher added a commit to rmarscher/waku that referenced this issue Sep 11, 2024
Using the getEnv API for now until dai-shi#827 is resolved

Example usage:

```ts
  const ctx = getEnv("executionContext") as unknown as ExecutionContext | undefined;
  ctx?.waitUntil(
    new Promise<void>((resolve) => {
      console.log("Waiting for 5 seconds")
      setTimeout(() => {
        console.log("OK, done waiting")
        resolve()
      }, 5000)
    }),
  )
```

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 for now.
See https://developers.cloudflare.com/workers/languages/typescript/#generate-types-that-match-your-workers-configuration-experimental
for info on generating types for your project.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants