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

Code splitting is not easy if at all possible #336

Closed
campbellcole opened this issue Jan 22, 2025 · 3 comments
Closed

Code splitting is not easy if at all possible #336

campbellcole opened this issue Jan 22, 2025 · 3 comments

Comments

@campbellcole
Copy link

I've been using rspc in a large project for quite some time now and it's become very difficult to maintain my app's router because I can't easily split the sub-routers into separate functions. I've identified a single change that could fix this in a way that doesn't require exposing internal traits.

Ideally, I'd be able to write functions that return either RouterBuilder or Router instances and simply call RouterBuilder::merge using that function's return value, but I understand the complexity of types produced via a long chain of various builder methods could be result in a poor DX if exposed to developers. However, another technique I've attempted to use results in a much better DX but is impossible due to the MiddlewareBuilderLike trait being private:

use rspc::{internal::MiddlewareBuilderLike, Router, RouterBuilder};

pub fn merge_sub_router<Ctx, Meta, Middleware, Lc>(
    builder: RouterBuilder<Ctx, Meta, Middleware>,
) -> RouterBuilder<Ctx, Meta, Middleware>
where
    Ctx: Send + Sync + 'static,
    Meta: Send + 'static,
    Middleware: MiddlewareBuilderLike<Ctx, LayerContext = Lc> + Send + 'static,
    Lc: Send + Sync + 'static,
{
    builder.merge(
        "example/",
        Router::<Lc, Meta>::new().query("subroute", |q| q(|_, _: ()| Ok("subroute".to_string()))),
    )
}

Ultimately, I'd prefer to see all of the internal traits exposed to those who dare use them because sometimes it's just the only way to accomplish something and many use cases have been unnecessarily ruled out by making them private. If the intention was to keep people from implementing them, there are ways to seal traits without making it impossible to refer to them in downstream code. It's clear this change is useful given the spacedrive fork of rspc has all of these traits public.

However, I can understand that exposing these types may not be desirable, so the modification I referred to in the example is one line of code and could dramatically increase code cleanliness in users' crates.

I'm happy to implement either fix. Please let me know which (if any) of these changes would be preferred and I'll get to it. Thank you.

@oscartbeaumont
Copy link
Member

When you are actively applying middleware route merging does become a major problem with no real solution in the current version. You could fork and apply a patch to expose those types if you need them although I would reccomend just not using middleware and you should be fine.

The new syntax (if I ever have the time to finish and release it) solves this problem by removing the concept of router-level middleware in favor of some much better patterns. The code for this new stuff is on #326 but it's not ready to release yet.

@campbellcole
Copy link
Author

How would I do this if I wasn't using middleware? Just rely on the default value of the type parameter?

@oscartbeaumont
Copy link
Member

oscartbeaumont commented Feb 3, 2025

I'm closing this as it should be fixed by the new syntax in v0.4.0.

v0.4.0 is still pretty new so there is a lot to iron out, let me know if you run into any issues with it and I can look into getting them fixed.

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

No branches or pull requests

2 participants