Stage | Start Date | Release Date | Release Versions | Relevant Team(s) | RFC PR | ||||
---|---|---|---|---|---|---|---|---|---|
Accepted |
2022-05-12 |
Unreleased |
|
Ember.js |
This RFC proposes adding a public import for RouterService
making it extensible by addons, removing the external link assertion from <LinkTo />
and rebuilding the <LinkTo />
component
to rely entirely on the public routing service instead of the internal -router
.
Today, users of ember-engines
are required to utilize separate
custom components, helpers and services for linking. This leaves the experience feeling sub-par, in addition to introducing
extra maintenance friction attempting to keep these primitives aligned with those in ember-source
.
By providing a public import for RouterService
, ember-engines
would be able to provide its own router service
implementation extending from the base implementation. Combined with minor changes to the engines-specific behavior of
link-to
, this change would allow us to fill the existing DX gap when it comes to navigating between an Engine
and a host App and allow engines to eliminate use of the legacy components required to support 4.x versions of Ember.
These proposed changes would further allow ember-engines
to deprecate the <LinkToExternal />
component provided by ember-engines
package. As a result, there will be less
engine specific concepts and code would be more portable between regular applications and engines.
Once this RFC gets implemented, following will be possible in user defined Ember Engines:
-
links to external routes in templates within the engine rendered via
<LinkTo />
component: -
using
RouterService
methods for redirects to the external routes:# addon/components/my-component.js export default class extends Component { @service router; @action clickLink () { this.router.transitionTo('external-route'); } }
Bonus: improved DX for addons
This RFC seeks to provide a solution that also solves another DX issue faced by engines developers.
Authors of large scale applications often create an addon(s) to contain reusable components that can
be rendered either in the context of the host App or Engine. In such scenarios an extra guard needs
to be introduced as the <LinkToExternal />
component is available only in the context of an Engine
and does not exist in the context of regular applications, so it is common to see patterns such as the following:
Once this RFC gets implemented, above snippet could be replaced with
This proposal does not seek to make any changes to the default blueprint.
App author may or may not introduce overridden RouterService
via app/services/router.js
.
If app author decide to do so and provide extended RouterService
, it may look like:
// app/services/router.js
import RouterService from '@ember/routing/service';
export default class extends RouterService {
// ...
}
In order to make this possible, method buildRegistry
of Application
class will be updated to have logic like so:
import { RouterService } from '@ember/-internals/routing';
// ...
if (!registry.has('service:router')) {
registry.register('service:router', RouterService);
}
The use of -routing
service in <LinkTo />
component would be replaced with the router
service.
Currently, those properties being pulled from -routing
service:
currentState
currentRouteName
Currently, those methods of -routing
service used:
generateURL
transitionTo
isActiveForRoute
Additionally, any engines specific code or assertions for url and path generation would be removed, delegating
these responsibilities instead to the router service. For instance, <LinkTo />
should not be aware of mountPoint
.
Provide public import via @ember/routing/service
.
The changes outlined here improve the DX for engines for the not-yet implemented url helpers specified by RFC#391. Since those helpers will also utilize the routing service, they would be compatible with both internal and external engines paths immediately.
While not the scope of this RFC to detail the exact specifics, once these changes are implemented, ember-engines
will provide a router
service that extends from @ember/routing/service
.
// ember-engines/addon/services/router.js
import RouterService from '@ember/routing/service';
export default class extends RouterService {
// ...
}
The extended RouterService
would override or extend any necessary public methods and properties to provide a great DX
for engines developers.
Ember Engines documentation provided at ember-engines.com
should be updated with <LinkTo />
replacing all the references of <LinkToExternal />
component.
Transition path needs to be published on ember-engines.com containing following steps:
- Replace use of
<LinkToExternal @route="external-route" />
component with<LinkTo @route="external-route" />
in every engine codebase. - Users using
ember-engines-router-service
would need to replace any of its usage with theRouterService
provided byember-engines
. This addon was created to solve part of this problem previously, and would likely be updated to become a true polyfill for the ember-engines routing service.
Ember Guides should be updated to rationalize and explain the difference between app/router.js
and app/services/router.js
.
The confusion between those two distinct yet different entities exists even today.
However, it's less a problem today as there is only one thing named router.js
can exist in the app today and
ability to create another such file (even with different purpose and semantics) may be confusing.
The removal of assertions within <LinkTo />
specific to ensuring that external paths are properly mapped means that
it is now the responsibility of the routing service provided by ember-engines to enforce that encapsulation is not
broken unintentionally, since a user can now provide any fully qualified path to <LinkTo />
.
A similar issue arises with the routing service's transitionTo
method when invoked with a url. For instance:
router.transitionTo('/');
Some prior discussion on this point is viewable here. In the case of this RFC, it would similarly become the responsibility of the engine's routing service to prefix such a url with the engine's mount path as appropriate, or decide to error, to preserve encapsulation.
In practice, we feel the flexibility and improved DX of this solution outweighs these drawbacks, and intend to continue enforcing the same constraints via the engines provided service.
-
Utilize
@ember/legacy-built-in-components
to keep<LinkToExternal />
a thin wrapper around legacy implementation of<LinkTo />
component.As this may be considered temporary solution to solve Ember 4 compatibility for
ember-engines
, this is not viable long term solution as any changes made to<LinkTo />
component in the Ember.js codebase will need to be backported to@ember/legacy-built-in-components
. -
Re-implement
<LinkTo />
functionality inember-engine
.This is not viable long term solution as any changes made to
<LinkTo />
component in the Ember.js codebase would need to be backported toember-engines
. -
Deprecate and remove
externalRoutes
mapping.This would require providing full route name to
<LinkTo />
component including engine mount point within the engine code. This option is not viable as it breaks isolation principle of Ember Engines whereas every engine should be self-scoped micro-frontend. -
Introduce
{{path-for}}
Engine Router helpers.This option was discussed in RFC #806 "Engine Router Helpers" which was considered as partial solution to teh problems discussed in this RFC.
-
Make ember-source handle all of the engine specific logic for routing itself.
To this point engines have only minimally been accounted for in the code of ember-source, this would digress from that. This integration could be done at a later time, but it seems unnecessary to currently hoist engines specific logic into applications that may not have any engines.
None.