nitrojs / nitro-cloudflare-dev

Enable access to the Cloudflare runtime bindings in development server of Nitro and Nuxt
MIT License
79 stars 4 forks source link

No `cloudflare` object exposed to `context` in local environment #42

Closed serban-mihai closed 2 weeks ago

serban-mihai commented 2 months ago

I'm trying to set up for local development a SolidStart App deployed to Cloudflare Pages that need to access some Bindings on SSR (server), KV, Durable Objects, and D1 in my case. I followed a blog post that helped me get good binding types set up about this specific use case here: https://ryanjc.com/blog/solidstart-cloudflare-pages/

If deployed on Cloudflare Pages it works just fine and context gets the cloudflare.env that I'm collecting in a function to then use it in a "use server" function in a Solid component.

{
    "_nitro": {
        "routeRules": {}
      },
      "nitro": {
        "errors": []
      },
      "cf": {
        <ALL_CF_GEOLOCATION_AND_REQUEST_INFO>
        ...
      },
      "cloudflare": {
        "request": {},
        "env": {
          "ASSETS": {},
          <ALL_THE_BINDINGS_AND_VARIABLES_SET_IN_WRANGLER_TOML_ARE_HERE>
          ...
        },
        "context": {}
      }
    }

But in the local environment, no matter what I cannot get anything appearing in event.nativeEvent.context.

{ "_nitro": { "routeRules": {} } }

The local fallback of process.env mentioned in the article above has never been working for the same reason, so I turned out to this package. Still, it looks like nothing changed besides the run of wrangler at dev startup and the creation of /.wrangler/ folder where the local state is supposed to be kept during development.

Ideally, I would like to bind the Cloudflare Pages Functions (worker) to another Cloudflare Workers (worker) that I have locally run needed for the creation of Durable Objects since the Pages project cannot do it by itself. Still, there is no clear guideline to use without proxies, and the docs from all, Cloudflare, SolidStart, Nitro, and Discord discussions... are not of much help.

My use-case:

import { getRequestEvent } from "solid-js/web";
import { CfPagesEnv } from "~/global.d";

export const cloudflare = (): CfPagesEnv => {
  const event = getRequestEvent();
  return event?.nativeEvent.context.cloudflare?.env as CfPagesEnv
};
const getRooms = cache(async () => {
  "use server";
  const kv: KVNamespace = cloudflare().KV_NAMESPACE as KVNamespace;
  const rooms: RoomEntryType[] | null = await kv.get("rooms", "json");

  return rooms ?? [];
}, "lobby");

On deployed Cloudflare Pages Functions: All Good! On local build command or dev command: Cannot read properties of undefined (reading 'KV_NAMESPACE') I can't even build locally because of this.

My config:

import { defineConfig } from "@solidjs/start/config";
import nitroCloudflareBindings from "nitro-cloudflare-dev";

export default defineConfig({
server: {
    preset: "cloudflare_pages",
    rollupConfig: {
      external: ["__STATIC_CONTENT_MANIFEST", "node:async_hooks"],
    },
    modules: [nitroCloudflareBindings],
  },
})

All the bindings are correctly declared in wrangler.toml and referenced in globals.d.ts in the Pages project, autocomplete recognizes them.

Do you have any idea what I'm doing wrong?

atinux commented 2 weeks ago

Would you mind sharing a small reproduction please?

serban-mihai commented 2 weeks ago

Would you mind sharing a small reproduction please?

Since I wasn't able to find a solution, I abandoned the idea of using the nitro-cloudflare-dev entirely. Instead, I've been able to make it work with a hack-ish strategy that is not somewhere near ideal nor feasible but it works for now using the getPlatformProxy from wrangler:

/global.d

/// <reference types="@solidjs/start/env" />
import type {
  Request as CfRequest,
  ExecutionContext,
  KVNamespace,
  DurableObjectNamespace,
} from "@cloudflare/workers-types";

export interface CfPagesEnv {
  ASSETS: { fetch: (request: CfRequest) => Promise<Response> };
  CF_PAGES: "1";
  CF_PAGES_BRANCH: string;
  CF_PAGES_COMMIT_SHA: string;
  CF_PAGES_URL: string;

  // Bindings
  LOBBY: KVNamespace;
  ROOM: DurableObjectNamespace;
  ...
}

declare module "vinxi/http" {
  interface H3EventContext {
    cf: CfRequest["cf"];
    cloudflare: {
      request: CfRequest;
      env: CfPagesEnv;
      context: ExecutionContext;
    };
  }
}

cloudflare.ts

import { getRequestEvent } from "solid-js/web";
import { CfPagesEnv } from "~/global.d";
import { getPlatformProxy } from "wrangler";

export const cloudflare = async (): Promise<CfPagesEnv> => {
  const event = getRequestEvent();
  const { env }: { env: CfPagesEnv } = await getPlatformProxy();  // comment before deploying on remote cloudflare pages

  if (!event?.nativeEvent.context.cloudflare) return env;   // comment before deploying on remote cloudflare pages
  return event?.nativeEvent.context.cloudflare?.env as CfPagesEnv;
};

Just use the (await cloudflare().<anything> as <anythin_type>) with <anything> being the binging anywhere you need to access some ENV variable or any other such as D1 or KV (it also works with Service Bindings). The major inconvenience is that you need to comment on the lines marked before deploying to remote or it will crash the build, and you also need to keep them uncommented during development to make the context available.

I'm sorry that I cannot provide you with an example of the library not working right now, but if you have other questions let me know.

atinux commented 2 weeks ago

When I say reproduction, I mean a minimal Solid Start repository using this module with your server function not working locally (I don't have the time to create it myself sorry).

serban-mihai commented 2 weeks ago

I'm sorry but I'm also running out of time. Anyway, this module won't work in SolidStart until some changes are made as Ryan describes here

atinux commented 2 weeks ago

Oh I see 😅

Well I don't know what to say, not sure to understand why SolidStart decided to not leverage Nitro server in development... This creates a gap between dev & prod experience.

pi0 commented 2 weeks ago

This module is intended to work with an unmodified Nitro dev server and SolidStart (vinxi) does not leverage it. I hope at some point soon it will be solved let's track via https://github.com/solidjs/solid-start/issues/1394