VeryGoodOpenSource / dart_frog

A fast, minimalistic backend framework for Dart 🎯
https://dartfrog.vgv.dev
MIT License
1.79k stars 150 forks source link

[RFC] Integrating Dart Frog with Dart Edge #541

Open Ehesp opened 1 year ago

Ehesp commented 1 year ago

The dart_frog dev command currently generates a .dart_frog/server.dart file with all logic contained in the single file, including the createServer logic which returns a HttpServer.

I've been experimenting with running Dart Frog via Dart Edge, which of course does not require a server implementation. I believe it should be possible to get it running on all providers, however it'd require some changes for it to be a friendly developer experience:

I could create a command within the Edge CLI to generate a file, similar to what server.dart has, but without the HttpServer and hot reload part. I've already experimented with this and it works, however I feel that I'm just reimplementing what's already been done within the Frog CLI.

Essentially for it to work with Dart Edge, I just need a Handler from Shelf, and internally I can make it work. Would it be possible provide another Frog CLI command, maybe dart_frog gen --watch (or whatever really) which outputs a .dart_frog/handler.dart file, exposing the cascade handler? E.g:

import '../routes/index.dart' as index;
// ... etc

final handler = Cascade().add(buildRootHandler()).handler;

Handler buildRootHandler() {
  final pipeline = const Pipeline().addMiddleware(middleware.middleware);
  final router = Router()
    ..mount('/posts', (context) => buildPostsHandler()(context))
    ..mount('/', (context) => buildHandler()(context));
  return pipeline.addHandler(router);
}

// ... etc

This would allow me to pull in the handler and run it via the various Edge Providers.

I'm not entirely sure what the best DX on the Edge side of things would be, however it is then possible we could expose something in our CLI which builds specifically for Dart Frog.

Step 1 - integrated CLI

edge build vercel_edge --dev --integration=dart_frog
edge build cloudflare_workers --dev --integration=dart_frog

The user wouldn't need to know about this, as the commands are extracted away within the config files for those providers. However internally, if --integration=dart_frog is provided, we'd generate the handler.dart file from the Frog CLI, generate our own provider specific entry file (which would be really minimal) which imports and executes the handler.

Step 2 - custom package / entrypoint

Additionally we could allow the user to define their own provider entry point, e.g:

/routes
  /index.dart
/main.dart

That file could look something like:

import 'dart_frog_edge/cloudflare_workers.dart';

void main() {
  CloudflareWorkers(
    // optional fetch handler
    fetch: (req) {
      if (req.url.toString() === '/ignore') {
        return Response('Ignore');
      }

      // otherwise pipe through dart frog
    },
    schedule: () {
       // usual implementation
    },
    durableObjects: [...],
  );
}

Step 3 - extension on RequestContext

We could also export a custom extension on-top of RequestContext, which would allow the user to access the platforms APIs of Dart Edge within routes:

Response onRequest(RequestContext context) async {
  final todos = context.env.getKvNamespace('...');
  await todos.put('foo', 'bar');

  return Response(body: 'Welcome to Dart Frog!');
}

Let me know what you think. The main thing here would be enabling Dart Frog to generate the handler as a standalone file/output and Dart Edge can do the rest with integration.

felangel commented 1 year ago

Hi @Ehesp 👋 Thanks for opening an issue!

This is a very cool idea and it doesn't sound like it would be a difficult lift on Dart Frog. That being said, I propose holding off on this until we have closed https://github.com/VeryGoodOpenSource/dart_frog/issues/474 since imo this functionality could be exposed via a separate library (dart_frog_edge). Let me know what you think and thanks again for the detailed proposal 👍

Looking forward to the collaboration! 🚀

Ehesp commented 1 year ago

Awesome. Yeah that sounds like a better long term approach. Hopefully this issue gives you some more insight into what else is a good candidate for integration.

Have you made any progress in terms of spec'ing out what those hooks would look like? Happy to give some feedback from my side if that helps.

felangel commented 1 year ago

Awesome. Yeah that sounds like a better long term approach. Hopefully this issue gives you some more insight into what else is a good candidate for integration.

Have you made any progress in terms of spec'ing out what those hooks would look like? Happy to give some feedback from my side if that helps.

Awesome, we haven't formally started investigating this yet so any feedback/suggestions would be much appreciated! 👍

Ehesp commented 1 year ago

I'll put some thoughts together. Might be worth pulling ideas from some popular JS Frameworks, or at least get a discussion going 👍