-
-
Notifications
You must be signed in to change notification settings - Fork 407
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
Template Tag In Routes #1046
Template Tag In Routes #1046
Conversation
7738818
to
51c419b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
### ember-route-template addon | ||
|
||
This RFC replaces the [ember-route-template](https://github.com/discourse/ember-route-template) addon. If you're already using it, it would continue to work without breaking, but you can simply delete all the calls to its `RouteTemplate` function and remove it. The popularity of that addon among teams who are already adopting Template Tag is an argument in favor of this RFC. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+100 and thanks for bringing this into Ember directly!
Co-authored-by: MrChocolatine <[email protected]>
Broadly 👍🏼 I think we should also:
This is similar to the application template wrapper optional feature/transition. For most apps, the recommendation shouldn't be just setting the feature to disabled, but to actually convert the templates to components – just change The motivation behind this is to more strongly align with the component model everywhere else. In the component folder, if you have a bare |
I don't think we should touch the existing hbs behavior, even with a flag -- benefit too little |
I think the hard part about this is that there are quite a lot of places that have to make assumptions about which folders are allowed to do template colocation. We're likely to be chasing down bugs for a while. A partial list:
|
I guess I was assuming that some/all of these tools don't care about folders (some may not even have the concept about folders), and blindly assumes adjacent .js/.hbs = component. In my mind that would be the simpler thing to do (considering pods layout also), and arguably the intention of the co-location RFC, but empirically you may be right that they do care somewhat. |
Also, I was mostly coming from thinking about the implementation in ember-source, we have access to the flag at runtime and can implement the proposed behavior without build tool support. But I do think you are correct that we need to consider whether it will work out in language servers, etc. |
Co-authored-by: Ignace Maes <[email protected]>
Yeah lots of stuff actually blows up if you blindly assume colocation. The most problematic case is not when both js and hbs are present, but when only hbs is.
This would be a radical departure from how it works today and I would not be in favor. Template colocation is an entirely build-time phenomenon today. ember-source knows nothing about it. |
I will be more precise about what I meant: My assumption (apparently not entirely accurate) was that the current build tools more-or-less blindly see co-located pairs and smoosh them down to a single js module, but otherwise leave single hbs files alone. Then, at runtime, if ember-source encounters a template module it'll, at runtime, convert it to a template-only component. I am pretty sure this was at one point how it had to work, since that behavior was an optional feature for transitional purposes (similar to here), but perhaps that has changed since the flag has been removed. We still seem to have kept the code around in ember-source though. Not sure how that is managed in the build tool side, maybe they also stopped supporting older versions with the flag? Anyway I didn't mean to say that we shouldn't do this in build tools. In fact I was assuming that's what we already do (when there is a pair). What I mean is that if the build tool didn't take care of the lone hbs files (and my assumption was that they don't today, thus requiring an upgrade), we can still make it work at runtime without hard-requiring build-tool upgrades which we typically don't do. In any case, I can't really say that much about how hard/easy it is to implement across the ecosystem, but I do think it is an attractive proposition that should be seriously considered, and if rejected, the drawbacks noted in the RFC. If we do this, then we have a consistent behavior across the board – The drawbacks of not doing this is a bunch of odd inconsistencies – as mentioned the divergent behavior between what lone .hbs file means is one thing, but also, if the build tools doesn't do what I assumed, then we also have to define what it means when you have a .js+.hbs pair in this context, at least making it an error. Ultimately, I think this fits so well into the new programming model that it's only natural for someone to try the usual patterns in the templates folder, and the failure mode is quite surprising (and subtle). Keeping these divergent behavior also complicate things for tools in the long run, so it's ultimately a balancing act. I think either way we are going to be chasing down bugs for a while – because of the odd behavior of route templates the "natural" handling wouldn't work for those (e.g. if you are writing a new codemod, if you just write one set of behavior it likely won't work for route templates). This basically gives us a path to get off that weird behavior by running a one time codemod and be done with it, and new tools can require to be already done and not have to worry about the divergent behavior. But I can be convinced that we think we already hunted down most bugs in that direction and would rather leave it alone. Because the actual difference we are talking about is very small, another alternative to explore would be to make it work both ways with deprecation:
This eliminates the need for a flag, and you can always treat route templates as components. It's just that if you happen to have legacy route templates that refers to I haven't thought that much about how it would be implemented on the ember-source side, but I think if we are willing to put up with some dirty dark magic for a little bit (hidden inside ember-source/glimmer-vm), it can be done regardless of what the build tool does. |
Put it a different way: the proposal is to stop treating the route templates folder as special in any way. In the abstract, that should be a attractive proposition, both for learning and for implementation reasons, it also eliminates another place where file placement is significant (and so you/tools have to care about it) The obstacles seem to be that currently tools do have to sometimes special case it, and is already implanted to behave that way. If we can, I think it’s worth exploring in the direction of what can we do here to make it possible to opt out of those special treatment. It does take some work to update the existing implementation, but it would be in the direction of where we want to end up anyway. |
I think making Some things to remember come implementation time:
|
I'm probably missing a bunch of context here, but why couldn't a Route specify the template instead of putting it in a separate e.g. import Route from 'component-route';
interface HelloModel {
world: string;
}
export default class Hello extends Route<HelloModel> {
<template>Hello {{@model.world}}!</template>
override model(): HelloModel {
return { world: 'Earth' };
}
} I have this almost working using something similar to the code below. // component-route/index.ts
import { getComponentTemplate } from '@ember/component';
import { getOwner } from '@ember/owner';
import Route from '@ember/routing/route';
export default class ComponentRoute<Model = unknown> extends Route<Model> {
override _setRouteName(name: string): void {
super._setRouteName(name);
const template = getComponentTemplate(this.constructor);
if (template != undefined) {
getOwner(this)?.register(`template:${name}`, template);
}
}
} The only problem is that
|
That would be an example of what I meant by:
I definitely want us to do that too. It's just demonstrably a lot more complex, which is why it isn't done yet. My intent with this RFC is to do a thing that we can ship immediately by targeting one very specific spot in the implementation. An example like the one you showed would require a new Route base class. But if we commit to a new Route base class, we're really going to want it to solve not just the problem of how to route to GTS, but also the problems of having the correct lifetime, fully eliminating controllers (which means designing better query params), allowing data-loading hooks to run in parallel, eliminating confusing old behaviors around parameter serialization, and ideally also providing strong typescript types for routes. All while correctly inter-operating with today's Route and its quirky timing and transition behaviors, since people can't be expected to convert all their routes simultaneously. Also, the designs people tend to intuitively reach for here all make the problem of route-based code-splitting worse by putting the data-fetching code and the component hierarchy in the same module, where they can't be split apart without JS-spec-violating behaviors. I am still hoping our design will allow the data for a route and the component hierarchy for a route to load in parallel, but that is a point where reasonable people can disagree (and hence why "Route Manager" would be the first stop, since like Component Manager it would let people do their own implementations on stable public API to demonstrate how they think routing should work). |
But it's not where we want to end up. We want to end up with no more I really, really do not want to spend time going around the ecosystem conditionally changing how
That code doesn't do component template colocation. It can't. It only covers the case where The ember-resolver stores modules without file extensions. It cannot distinguish |
While I think this is a good step, I also think this is getting mixed-in with interest for other router improvements. Last I heard there was work taking place for Polaris Edition, but perhaps the router stuff stalled.?. If there was a place to see what was planned for that, it would help to see how this RFC will lead into other router improvements. |
While we'd ideally have at least a Route Manager RFC for Polaris, for now, this RFC is the "router stuff" for Polaris. There is a lot of things we could do but for the most part our efforts are elsewhere and this is a small change that will enable a more coherent story. This came about while I was pairing with @ef4 on how to update the guides for Template tag. It is incredibly weird to explain .hbs for some things and .g(j|t)s for something else. Ed mentioned that he uses and recommends discourse/ember-route-template. When core team members are building apps and recommending different paths than our guides follow, it is a giant flashing sign that we need to do something to bring those changes to users following the documentation. |
With this change,
🎉 |
Gathering feedback from comments and RFC review meeting discussion:
|
After discussion with the spec meeting, our consensus was against destabilizing anything about existing hbs route files. All the existing learning materials, community knowledge, and tooling can remain exactly as it is. The gjs vs hbs distinction is a clean and clear break for where the new behavior goes, and no new behaviors go into hbs. |
@ef4 sorry, it's not clear to me what you're getting at. Are you saying this RFC will be "final to closed"? Or part of what is proposed will not go through? |
No, I'm saying this RFC is good as written. There were suggestions to expand it to also change the behavior of hbs route templates, and I'm saying I don't want to do that. I want to just introduce gjs route templates without changing anything about hbs. |
In short:
|
I'm clear on the desire to have a way off hbs asap, and sympathetic to how this pulls the sweater thread that leads to a complete Routing Overhaul RFC. It wasn't obvious to me when reading the template-only example that I was reading a glimmer component. And I was genuinely shocked when I saw the option to colocate js by 'enhancing' the route template to a glimmer component. I feel that this 'enhanceability' is exactly what starts pulling the sweater thread. This RFC is demonstrating something nearly like routable components, which is how you get questions like "what's the point of controllers?" and "who owns query params?". At this stage, if the goal is to really, surgically, just ditch hbs; I think these route templates should be template-only and not offer any 'enhanceability' to a glimmer component. That enhancement pathway opens the door too wide, and will make it difficult to reel in the possibility space when the Routing Overhaul RFC is finally describable. I think the introduction of I think these are the pieces of this RFC that smuggle in further dissatisfaction with Ember Routing, and get ahead of the skis when the goal is "make hbs disappear." In summary, what if we don't shake up the mental model at all right now, and focus solely on the syntax goal? To me that looks like this:
|
I think it would be incredibly confusing for there to ever be a There are questions to answer around future routing, but this change shouldn't impede that exploration nor eventual change. It will enable us to teach only template-tag components for new Ember development in a coherent way even though we still have to explain controllers for query params and certain hooks. Similar to migrating components to template tag I expect that most existing applications will take a while to do so and do it piecemeal. |
I'm not familiar with the team's overall goals for GJS/GTS, but up until now as a consumer I haven't viewed them as synonymous with Component. I've taken it to be similar to JSX where it signals a syntax extension on top of JS/TS syntax. Agnostic to what the file contents end up representing. I don't think Ember has to buy into the idea that GJS can only contain a Component, if it hasn't already. I think buying in there limits the possibilities for Routing RFCs like this one. Assuming agnostic file contents: The complexity of what If GJS must always mean Component: I think the sweater thread pull is unavoidable, and this RFC is effectively the first step towards Routing Overhaul. Speaking as an early adopter of GJS, I would avoid using GJS for route templates with this current proposal. I'm worried how un-idiomatic things can become once routes come with both controllers and components. With confusion especially around whether ViewModel should live in route.gjs or controller.js. Every wrong call my team makes, intentional or not, is (best case) a codemod to run or (worst case) a re-write. |
I think, with this, anything that can be on the component for the route should be -- meaning anything that isn't defining a queryParam or a needed hook on controllers. |
I can see two different ways of interpreting this suggestion, so I'll address both. The first interpretation of template-only is the The problem with trying to limit routing to only (Should you write new The second interpretation of "template only" is the way today's route templates works. They are a "bare template" that is not a component. We deliberately designed template tag so it's impossible to use it to obtain a bare template. So bare templates are not a solution to the problem of "how can we avoid teaching people two completely different paradigms for writing their templates?", because you cannot use them with template tag, on purpose.
I agree that avoiding those kind of outcomes is one of our most important goals when we work through an RFC like this. I believe this RFC reduces the confusion rather than worsening it. Today, you have to teach a complicated decision process:
After this RFC, that teaching simplifies to:
|
Riding along with the route+component approach, here are some more thoughts:
|
All of that is the stuff that's intentionally out of scope for this RFC, because it veers into "redo the router" territory.
Nothing replaces outlet, you keep using outlet. Outlet is already dynamically scoped, it already works in components, so there's no change.
I'm not sure I understand how this relates. We're effectively saying that the router will invoke components with the signature Notice that we're also not allowing you to customize the args. You can put whatever you want inside
Yes, it's intentionally weird. It reflects the weird reality. The vast majority of new route templates shouldn't use it, and would therefore be portable to elsewhere. If you do use it, you are actively highlighting why your component isn't portable, because it's tied to all this legacy state management.
This veers directly into "redesign the entire router" territory, which we're trying to avoid in this RFC. Without doing that first, treating query params special in this RFC would increase incoherence by introducing a new way of doing things that doesn't actually solve the problems we want to solve about query params, so instead of eventually teaching "old query params" and "new query params" we also have a third thing to teach like "old query params but accessed via that other component api". Query params live on controllers, that's just the truth about them and trying to reflect them elsewhere is fraught because they're mutable and because controllers have unbounded lifetimes. |
Sorry I couldn't make those meetings, but between the comment from 3 weeks ago ("elaborate on the alternative possibility...") and the following one ("After discussion with the spec meeting..."), it wasn't clear what was considered regarding my suggestions. My previous comments were perhaps getting too concrete, and some of the details caused more distractions than helped, so here is the high-level suggestion without getting into the implementation details, summarized in a format suitable for the Alternatives section:
Since I am not doing the implementation work, I can't really speak to the cost of implementing my suggestions, but I do think there are tangible benefits and gets us to a more coherent spot for the edition boundary, so if it was considered and rejected for implementation cost reasons, it would be good to have that documented as such. There was also a suggestion about making Regardless of the overall disposition of my suggestions, I also pointed out an obvious hole in my previous comments – this RFC should specify what is supposed to happen when someone inevitably places a To the extent that this RFC proposes special-casing based on file system locations (and I think as written, it kind of is proposing that, if only just inheriting the status quo of location-based component compilation), it probably should specific exactly what those rules are. For example, presumably, this covers I get that the RFC as-written is only specifying the runtime behavior, and that the rest is "left to the build tools". But I think it is important to actually specify what we intend for the build tools to do exactly in this RFC, because it's not just embroider that needs to know, but also codemods, linters, glint, etc, all potentially need to have implement the same set of rules correctly to get the right result. Which is the motivation behind my suggestion to take the opportunity to unify things and get rid of all those special casing once and for all. |
This RFC changes nothing about that experience. All the incoherence and downside risk that you're describing is the status quo, and this proposal actually makes it better by explaining what our path is to forever eliminate that incoherence (use GJS instead).
This is not how I see the plan for How We Teach Polaris. We are not going to teach people to write separate js and hbs. The user's coherent mental model is to use gjs. What docs will remain for hbs are going to be an explanation that it's the older component format and links to the older releases documentation.
Those rules are arcane, implementation-defined, and were implemented with compromises to cover even earlier incoherent things like pods. Asking us to write a spec for them before we can do a feature that makes them irrelevant does not strike me as reasonable.
I can be swayed on this point. Certainly the runtime implementation of What makes me lukewarm on this, is that I have no interest in spending our precious development resources on updating glint, ember-template-lint, guides, and API docs for this minor change that I would advise people against spending their time on. Changing |
Maybe a reasonable compromise on |
After extensive discussion with @chancancode and @wycats I incorporated edits to record their input and I have confirmation from both of them that we can move past the discussion, since the core feature proposed here has consensus and the other possible changes would stand as their own RFCs. |
Propose Use Template Tag in Routes
Rendered
Summary
This pull request is proposing a new RFC.
To succeed, it will need to pass into the Exploring Stage), followed by the Accepted Stage.
A Proposed or Exploring RFC may also move to the Closed Stage if it is withdrawn by the author or if it is rejected by the Ember team. This requires an "FCP to Close" period.
An FCP is required before merging this PR to advance to Accepted.
Upon merging this PR, automation will open a draft PR for this RFC to move to the Ready for Released Stage.
Exploring Stage Description
This stage is entered when the Ember team believes the concept described in the RFC should be pursued, but the RFC may still need some more work, discussion, answers to open questions, and/or a champion before it can move to the next stage.
An RFC is moved into Exploring with consensus of the relevant teams. The relevant team expects to spend time helping to refine the proposal. The RFC remains a PR and will have an
Exploring
label applied.An Exploring RFC that is successfully completed can move to Accepted with an FCP is required as in the existing process. It may also be moved to Closed with an FCP.
Accepted Stage Description
To move into the "accepted stage" the RFC must have complete prose and have successfully passed through an "FCP to Accept" period in which the community has weighed in and consensus has been achieved on the direction. The relevant teams believe that the proposal is well-specified and ready for implementation. The RFC has a champion within one of the relevant teams.
If there are unanswered questions, we have outlined them and expect that they will be answered before Ready for Release.
When the RFC is accepted, the PR will be merged, and automation will open a new PR to move the RFC to the Ready for Release stage. That PR should be used to track implementation progress and gain consensus to move to the next stage.
Checklist to move to Exploring
S-Proposed
is removed from the PR and the labelS-Exploring
is added.Checklist to move to Accepted
Final Comment Period
label has been added to start the FCP