Skip to content

Conversation

@parsonsmatt
Copy link
Contributor

@parsonsmatt parsonsmatt commented Jul 30, 2025

Nested Route Separation

We have almost 2,000 total routes in our codebase now, with 1,100 of them on the top-level.
We have been leveraging nested routes to organize the routes and make certain things easier - namely, reducing the overall size of the Route WebApp which makes pattern matching more efficient in compilation.

However, compiling mkYesodData for our application is a large bottleneck.
Compilation takes a significant amount of time and much work must be redone, even when most of the routing information could have been saved.
One thing that would significantly help is the ability to separate out the sub-route datatypes, generate the instance for these separately, and refer to them elsewhere.

Another thing that would help is having a finer grained YesodDispatch facility - allowing us to, in tests, specify more precisely which parts of the route structure we actually need to deal with.
Currently, we need almost 7k modules in order to compile a test that refers to YesodDispatch, since this brings in the transitive dependencies of every web handler.
With a finer grained YesodDispatch, able to refer to route fragments, we'd be able to avoid depending on more of the website than we really need to.
We expect this to yield significant benefits when we move more testing infrastructure to buck2 - right now, changing anything used by any part of the web app would require running all tests that exercise anything in the webapp!
With more granular YesodDispatch, we gain the ability to only run tests on parts of the app that actually use the route structure in question.


This PR is a breaking change, and so will be yesod-core-0.2.0.0. When I tried this branch on our package, it required 0 modifications to upgrade - most of the breaking changes here are breaking "advanced power user" type functions, like the ability to customize the MkDispatchSettings to have highly custom route behaviors. We don't use any of those, and I have no idea how widespread their use is. I will admit to finding them very difficult to use and adapt, which is part of why I ended up scrapping their use in the ParseRoute generation (the class isn't even used).

For the most part, though, all prior behavior remains unchanged. The performance of routing may be slightly worse - YesodDispatchNested returns a Maybe Application (but with the Request pulled out - only the "send response" side is in the Maybe) to support fallthrough. And if you enable fallthrough, then the app will do more checking (proportional to the number of routes and nested routes) rather than early-404ing. But IMO for perf, we're better off coming up with a trie-based router than trying to optimize this one much more.

For an example of the testing facilities this provides, see parsonsmatt/hspec-yesod#7 - particularly, this file has an introduction to how the tests are separated and defined.


Fix for #1880

Before submitting your PR, check that you've:

After submitting your PR:

  • Update the Changelog.md file with a link to your PR
  • Check that CI passes (or if it fails, for reasons unrelated to your change, like CI timeouts)

@parsonsmatt parsonsmatt marked this pull request as draft December 24, 2025 21:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants