Skip to content

Rearchitect Router so it's more modular #42953

Closed

Description

@atscott

Which @angular/* package(s) are relevant/releated to the feature request?

router

Description

The Angular router's current architecture is problematic for a couple big reasons:

  • It is not extensible. Developers cannot easily extend or change the Router's functionality to support features that would be useful to their applications. Instead, these features have to be built in to the core Router code and exposed through some endpoint (i.e. RouteReuseStrategy, some option on ExtraOptions which is used as an switch in the internal code, etc.)
  • It is not tree shakeable. Due to its non-modular nature, almost all features (lazy loading, guards, resolvers) are generally baked in to the Router's internals unless explicitly configurable through a Strategy that can provide a no-op implementation. Simple applications that do not use these features still incur the bundle size cost.

Proposed solution

Because of the above two problems, we're often quite limited on what features we can implement. The router should be rearchitected with the following goals in mind:

Alternatives considered

N/A

Activity

  1. added
    featureLabel used to distinguish feature request from other issues
    refactoringIssue that involves refactoring or code-cleanup
    on Jul 23, 2021
  2. modified the milestone: Backlog on Jul 23, 2021
  3. angular-robot commented on Jul 24, 2021

    @angular-robot
    Contributor

    This feature request is now candidate for our backlog! In the next phase, the community has 60 days to upvote. If the request receives more than 20 upvotes, we'll move it to our consideration list.

    You can find more details about the feature request process in our documentation.

  4. PieterjanDeClippel commented on Jul 25, 2021

    @PieterjanDeClippel
  5. added
    feature: under considerationFeature request for which voting has completed and the request is now under consideration
    and removed on Jul 25, 2021
  6. SchnWalter commented on Aug 25, 2021

    @SchnWalter
    Contributor

    Adding a note about the need to redirect from data resolver instances, for 403/404 pages.

    We currently have a feature request for it, #29089, but this will actually cause confusion among developers, a better solution is needed (and I've provided one in a comment):

  7. micru commented on Dec 3, 2021

    @micru

    Any news on this? Would be really great to have more flexibilty with the router, especially to change the execution order of guards and resolvers as its often nearly impossible use them both in conjucation as it should be

  8. atscott commented on May 4, 2022

    @atscott
    ContributorAuthor

    @micru It's on our radar and I'm trying to slowly chip away at some smaller complexities in the router that would make this more difficult to accomplish. Some of these items include #45735, #45240, #45877. Special cases and unpredictability in how the Router internals operate make it harder to expose swappable parts because it's harder to match the expectations or even know what those are.

    There's no additional information at the moment though. We haven't started work on taking a deep dive into what APIs we want to make pluggable.

  9. PowerKiKi commented on Nov 13, 2023

    @PowerKiKi
    Contributor

    I'd like to reiterate the need expressed in #10556. That is to have resolvers capable to wait for first emission of an observable, not unsubscribe, and forward the observable to the component. So the component would be able to have immediate access to the first (replayed) emission and also all future emissions, without the need to handle complex mechanism of subscribe/unsubscribe across resolver and component.

    It would be awesome if it was baked in. Or at least there should be a reasonable way to configure/add/implement this behavior.

  10. denisyilmaz commented on Apr 25, 2024

    @denisyilmaz

    We have a complex project where the paths of the different page types don't follow a specific order. Thus, only when the data from the backend is resolved we know which component should be used to show the content.

    Based on the discussion here (#24187) its not possible to run a resolver on the root of the application before the canMatch guards of the children. Is there any plan that this will be possible in the near future?

    With withComponentInputBinding() its already possible to pass the resolved data to all child components, but there is no way to switch on a router level. We are currently using a "dynamic-page-loader" component that creates the components on the fly via ViewContainerRef. But this means all components are already loaded beforehand or loaded async which breaks SSR.

    Given this routes:

    export const routes: Routes = [
      {
        path: '',
        resolve: {
          page: pageResolver,
        },
        children: [
          {
            path: '',
            loadComponent: () => import('./pages/page-type-one.component'),
            canMatch: [canMatchPageTypeOne]
          },
          {
            path: '',
            loadComponent: () => import('./pages/page-type-two.component'),
            canMatch: [canMatchPageTypeTwo]
          },
    
        ]
      }
    ]

    It would be great to be able to do this (pseudo code):

    const canMatchPageTypeOne: CanMatchFn = (route: Route, segments: UrlSegment[]) => {
      const { page } = route.parent.data; 
      return page.type == 'one';
    };

    is anyone else having a solution that does not require to use a dynamic page/component loader?

  11. AndreasHae commented on May 6, 2024

    @AndreasHae

    Any update on this? If we had a way to not make child resolvers block parent routes from rendering (#837), this would make our app's logic so much simpler as we could have loading states akin to React's Suspense components. Right now we cannot use Resolvers if we want our app to feel snappy because when navigating via URL it just shows a white screen as long as resolvers are not finished. This forces us to use shared services for state management which increases complexity.

  12. PowerKiKi commented on May 6, 2024

    @PowerKiKi
    Contributor

    a way to not make child resolvers block parent routes from rendering

    This seems to go against the whole point of resolver of "data to be resolved before the route is finally activated". A route cannot be rendered without being activated, and resolvers must be resolved before the route is activated. I think you are using the wrong tool for the job. If you want to not wait, then don't use resolvers at all.

  13. gaborszekely commented on Jul 13, 2024

    @gaborszekely
    Contributor

    is anyone else having a solution that does not require to use a dynamic page/component loader?

    The way I solved this is to add a canMatch function at the root level that essentially just loads the required data and returns true. This will always run before the child canMatch, ensuring the data is available. It's not pretty, but it will get the job done.

  14. EinfachHans commented on Mar 28, 2025

    @EinfachHans

    I see & love the progress on the router over the last years! ❤️

    What really is missing for me is some way of rearchitect the order of resolvers/guards, as described in #24187

  15. JeanMeche commented on Apr 27, 2026

    @JeanMeche
    Member

    Closing as we'll probably not achieve full modularity (it would be too breaking).
    We'll re-open issues that aren't fix though.

  16. angular-automatic-lock-bot commented on May 28, 2026

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  17. locked and limited conversation to collaborators on May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: routerfeatureLabel used to distinguish feature request from other issuesfeature: under considerationFeature request for which voting has completed and the request is now under considerationrefactoringIssue that involves refactoring or code-cleanup

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions