Skip to content

Implement the Route Manager API (RFC #1169) - #21460

Merged
ef4 merged 138 commits into
emberjs:mainfrom
mainmatter:rfc-1169-route-manager
Sep 22, 2026
Merged

ef4 merged 138 commits into
emberjs:mainfrom
mainmatter:rfc-1169-route-manager

Conversation

@evoactivity

@evoactivity evoactivity commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

This is a big PR for a big feature.

Introduces a Route Manager layer between the router and route base classes so the router drives routes through a well-defined manager interface instead of calling classic Route methods directly. This decouples the router from the classic Route and is the stepping stone toward alternative route base classes and a future router. The classic Route behaves exactly as before, there are no changes to app authoring.

Three layers, top to bottom:

  • @ember/routing public re-exports of the authoring API
  • @ember/-internals/routing/route-managers The classic route manager and route manager infrastructure
  • router_js Drives the routes lifecycle through the manager, and owns the route manager contract

Why does the outlet have a legacy path?

A handful of tests directly set the outlet state, one in particular is testing something for liquid-fire. If there are addons or user code that expects to be able to create their own render state, they will not include the route wrapper and invokable we expect from the route manager, the legacy path path lets them continue working.

Query Params

The current implementation of query params is driven by the router, I have gated the parts that directly reach into routes behind the classic interop capability of route managers. I have left the "machinery" in place in the router. When we come to replace the router, a decision will need to be made if we bridge the classic router manager to use whatever new QP implementation we come up with, or if we fully migrate the router.js QP implementation to be fully encapsulated by the classic route manager.


RFC #1169

Introduce a Route Manager layer between the router and route base classes so the router drives routes through a well-defined manager interface instead of calling classic Route methods directly. This decouples the router from the classic Route and is the stepping stone toward alternative route base classes and a future router.

Add the manager interface, capabilities, and registration, implement a ClassicRouteManager that encapsulates today's classic Route behaviour behind it, and make router_js dispatch lifecycle, rendering, model resolution, and the classic-interop surface through the manager.
@evoactivity
evoactivity force-pushed the rfc-1169-route-manager branch from 37bd3e6 to 7582a9f Compare June 15, 2026 08:44
johanrd added a commit to johanrd/ember.js that referenced this pull request Jun 15, 2026
…s on emberjs#21460

Reverts the outlet.ts compute-ref guard to the current ember-7.0.0 behavior,
demonstrating that the @model-during-willDestroy instability (emberjs#18987)
still reproduces on top of the Route Manager RFC implementation (emberjs#21460).

The smoke-test job's '@model stability during route transitions' tests are
expected to fail here. Not for merge.
@BobrImperator
BobrImperator force-pushed the rfc-1169-route-manager branch 2 times, most recently from 1d418f9 to 8c96f1e Compare September 8, 2026 14:42
@mansona
mansona requested a review from ef4 September 10, 2026 14:10
const CAPABILITIES: InternalComponentCapabilities = {
dynamicLayout: false,
// Every route has its own template; `getDynamicLayout` supplies it.
dynamicLayout: true,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is concerning. dynamicLayout was created for backward compatibility and isn't really in-step with a modern understanding of components.

It exists because of the way a classic Ember component can set its own layout property to pick different templates on the fly.

I expect we don't really need this anyway because I think we're already making a new Component per route anyway. In that case you can replace getDynamicLayout with a one-time call to setComponentTemplate.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to have been a leftover from the time when the current outlet-component didn't exist. This is now replaced by a setComponentTemplate in a makeRouteTemplate helper

wrapped: false,
willDestroy: false,
hasSubOwner: false,
hasSubOwner: true,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is surprising. Why do we need this?

@BobrImperator BobrImperator Sep 16, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to have been an another leftover... initial version when migrating from the -outlet helper needed this.
Right now the outet-component is the only place that needs this capability

@@ -0,0 +1,219 @@
diff --git a/dist/setup-rendering-context.js b/dist/setup-rendering-context.js

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this patch, and if so: why is it safe for us to test against an @ember/test-helpers that users won't have?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well yes, but the patch keeps the fallback for pre-route manager testing so it should be ready to actually open upstream

@BobrImperator are you able to open that PR with the changes?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was there to highlight the need for this change since the removal of RootView crashed the test suite. There's a draft PR open for the test-helpers already which I'll update shortly.

BobrImperator and others added 2 commits September 16, 2026 13:39
this was a leftover from the time when the wrapper/outlet components weren't static but dynamic
@ef4
ef4 merged commit 4b5d79a into emberjs:main Sep 22, 2026
58 checks passed
@github-actions github-actions Bot mentioned this pull request Sep 22, 2026
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.

5 participants