skymethod / denoflare

Develop, test, and deploy Cloudflare Workers with Deno.
https://denoflare.dev
MIT License
678 stars 31 forks source link

Pages + Functions support? #11

Open mcraiha opened 2 years ago

mcraiha commented 2 years ago

I tried to find information about if Denoflare supports Pages + Functions combination. I didn't find any command, so now I am asking is that supported? https://developers.cloudflare.com/pages/platform/functions/

johnspurlock-skymethod commented 2 years ago

Hmm, how would you envision that working?

I suppose via Advanced Mode, where Denoflare could generate a module worker like it does for normal workers?

We'd also have to figure out the undocumented endpoint for setting bindings for Pages Functions deployments. Do you have any experience with this?

It's probably worth waiting until Pages Functions is out of beta. If I recall correctly, it has already gone through some changes in functionality, and it will be interesting to see the delta of available workers features between Functions and normal workers once it goes GA.

mcraiha commented 2 years ago

Basically I would like to have replacement for wrangler (to be more specific, replacement for npx wrangler pages dev ./dist command), but in my case just to be able to test out those functions locally (that are in functions folder) would be enough.

johnspurlock-skymethod commented 2 years ago

I see - anything in particular you don't like about npx wrangler pages dev?

Serving functions as is (in the functions folder) locally would be a bit tricky, as none of the Deno specifics like remote imports would work, and even local imports would have to be import mapped somehow, the syntax is different (no trailing .ts).

Serving a module worker using Advanced Mode would probably be doable however, both locally and then saved to _worker.js for deployment.

mcraiha commented 2 years ago

Sorry for response delay.

Biggest issue for wrangler use is dependencies count. It is not huge, but it is still too much to get it vetted for company usage.

johnspurlock-skymethod commented 2 years ago

Ah ok - interesting.

Well in general, yes I would like to have a similar support for pages repos in serve once pages functions is GA, modulo the concerns mentioned above about the different bundler environments (cf uses esbuild with a hardcoded tsconfig).

threepointone commented 2 years ago

Hiya! I'm on the wrangler(2) team. These are our dependencies https://github.com/cloudflare/wrangler2/blob/664803e6636785103336333999c2ae784b60463f/packages/wrangler/package.json#L38-L45 (and we're planning on reducing it even further, specifically miniflare with it's dependency tree will get flattened into our build) Will that help?

bebraw commented 2 years ago

I've been exploring functions within CF pages lately and I would definitely benefit from having denoflare available there as well. Right now I have to repackage my code so that I can consume it through npm to bring it to wrangler.

I can see the following challenges at least:

  1. Routing - there are conventions for naming like [name] and [[name]] and more
  2. Deployment - probably what would have to happen is that Deno could would have to be bundled or packaged before pushing it to Cloudflare infrastructure. I think dnt might help here as it takes Deno code as input and it's transpiling it into something compatible with Node

@threepointone Do you think it would be realistic to share/package the router portion of Wrangler so that other tools could leverage it? I imagine it's not a lot of code in the end.

@threepointone When it comes to deployment, do you plan to support third parties somehow at Cloudflare side? I wonder what the process should look like. Maybe it would be enough to be able to transform the code (say with dnt like I hinted above) just before you deploy and push the compiled code to your infrastructure. Assuming you have support for third party CIs already, this could be possible already as long as the compilation result matches your conventions and uses regular Node for imports.

IshanKBG commented 1 year ago

I actually think this feature should be supported after cloudflare pages now supports functions properly. I have some projects in workers that i would like to shift to functions and those projects uses denoflare locally

bebraw commented 7 months ago

A small update on this. Recently I had to figure out how to mesh Deno and Node code in my codebase. Here's what I did:

  1. I packaged the Deno portions I wanted to consume using dnt. Note that you should write your Node imports with node: prefix and make sure you are running a recent enough Node (18 or above I believe) on Cloudflare for this to work. The current version of dnt removes the prefixes so you'll have to use something like patch-package to fix them but the issue has already been resolved and the fix will be included in the next version of dnt.
  2. At worker-side, the difficulty lies in how to normalize imports since in my use case I use some of the code for Deno and Node still (SSG happens via Deno, server bits through CF). I ended up using node: prefix convention for imports since Deno supports that and to make Node support the same, I added the following configuration to my tsconfig.json:
{
   ...
    /* Specify the base directory to resolve non-relative module names. */
    "baseUrl": "./",
    /* Specify a set of entries that re-map imports to additional lookup locations. */
    "paths": {
      /* For some reason marked doesn't resolve otherwise on CF */
      "npm:marked": ["node_modules/marked/lib/marked.esm.js"],
      "npm:*": ["node_modules/*"]
    },
}

As you can see, I had to resort to some hackery to make marked work as otherwise it would return an empty module and I have no idea why. I also don't know if you could do something like this with vanilla JavaScript/npm.

During the work, I struggled a lot with Deno import maps as I tried to keep the imports Node compatible and then rewrite at Deno but in my use case I have portions of code behind an import() and based on what I was reading import maps don't work there as there's no specification.

Another important thing to note is that you simply cannot use node:fs at Cloudflare so if you have to read files, it can be a good idea to push that sort of work to a pre-process you run before Cloudflare builds. In my work I generate a manifest module that contains all the portions I have to read as doing this reduces the problem to a simple module import.

I hope some of these insights help in making Denoflare Cloudflare Pages compatible as that would make Deno development on CF context with Deno much easier than it is now.

It's possible jsr will make some of this work easier but I didn't try it yet. My understanding is that it will make it easier to publish to one place and then consume from multiple environments. In essence using jsr might drop dnt from my workflow which would be a nice win.