-
-
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
RFC: Engines #10
RFC: Engines #10
Conversation
with an engine could be accessed from the primary application like this: | ||
|
||
```handlebars | ||
{{authentication@login-form obscure-password=true}} |
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.
downside of this syntax is that it has no html compliant tag form (yet)
In theory something like:
<ember-namespace namespace="authentication">
<login-form>
</ember-namespace>
or a block form, may introduce nice things
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.
@stefanpenner How's that HTML-compliant tags align with (presumably) allowing tags with slashes after the Handlebars 2.0 update?
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.
for now we will support slashes only via {{foo/bar}}
syntax, as <foo/bar></foo/bar>
is kinda crazy and not supported by HTMLBars currently. I am unsure it should be, but likely further thought is needed.
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.
This actually seems like a somewhat serious issue. We're relying on HTMLBars syntax for something like: <my-component on-click={{action "foo"}}>
, and there is no equivalent old-component syntax.
We will need to figure out a solution for nested tag names pretty soon.
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.
FYI: document.createElement("foo:bar")
works (holdover from XML days, I suppose).
I think our solutions are going to end up being:
- Template-wide imports (
*
or named) - Scoped imports (like XML namespaces or what Stef suggested)
- Changes to the default namespace (would require
html:div
if HTML was desired).
I think that many solutions will work, and that as long as we have a clear, "one true story" for doing this, and it doesn't introduce excessive duplication or boilerplate, people will be able to live with it.
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.
its a bummer that @
wont work, as :
already has meaning...
Elephant in the room is async. I believe engines can be a great enabler of this, but some concerns exist.
Implicit vs Explicit namespaces within an engine. Another, topic of discussion is, does one need to constantly use the namespace within the namespace, for example. Within this.controllerFor('authentication@foo'); or can we without ambiguity consistently infer the namespace and only do. this.controllerFor('foo'); Engines all the way down. In a perfect world, top level applications would also be |
@stefanpenner Container keys used in the context of an engine should implicitly be in the same namespace; i.e. within |
so this would imply a custom container (or namespace aware shared container). What about the resolver, does each engine use the same resolver? I would love to work through some gnarly multi-container multi engine examples as I believe this will be more complicated then we will expect. Some early ideas @rwjblue and me through down https://github.com/rwjblue/container-resolver-namespaces |
I love where this is going, and I think it will be very helpful lots of teams. I think this RFC should include the mechanism(s) that would be available to for the application developer to modify classes and templates provided by the engine. e.g. in the authentication scenario you described, there is an out-of-the-box |
My gut feeling here is that you'd want some kind of container per engine, but the container for engines would just be a sort of proxy that ensured everything on the way out was namespaced. So basically, if a controller inside an engine did
|
That seems like it should be up to the engine author to me. In the specific case of authentication, I can imagine the author building the login page out of a series of components that talk to a service. If you don't like the built-in login page, you can create your own page and re-configure the provided components. Or, if you want totally custom UI, you can just inject the service and talk to it directly from custom components. |
@tomdale wrote
In this scenario, how would I tell the engine's login route to use the page that I crafted out of the engine's components? Does needing to change a small detail on the login screen mean I need to replace the template, route and router? It would be awesome (though potentially a footgun) if there were a way to make it easy for engine authors to either explicitly provide extension points, or to have every piece of an engine overridable by a) providing a file at a corresponding path in your own app, e.g. under |
@lukemelia it would seem like adding custom modules to engine/engine-name/templates/login.hbs would do the trick. As a 3rd party engine would actually exists in node_modules somewhere, so as long as |
ya, container + resolver pair per engine, with a global registry to enable escaping the current namespace. |
There may be good reasons to not pave an easy path for engines to escape their own namespace. What if we constrained their external interface to only be:
From the outside looking in, no new namespacing interface is needed because the user already namespaced these routes based on where they called The engine would not directly This is fairly analogous to the way components work. In this sense, engines are just super-components that happen to handle their own routing. |
As a heads up, we're considering moving away from a "bubbling events" model to one where consumers of components pass in callbacks that can be called (sort of like React but without the verbosity). |
I currently have an app that is broke down into multiple rails engine. Each rails engine has its own Ember namespace with routes, models, templates, etc. Here is for example the initializer for a CRM engine:
The first part of the initializer takes all the controllers/routes from the crm namespace and register them with the main application. The second part, well, is the router definition for the engine. The drawback is that the main application currently does not know about the other namespaces and does not decide which routes get mounted. Now the fun part is when you want to add routes to a 'dependent' engine. Let's say we have a project engine dependent on the crm engine. We would like to enhance a contact with a list of projects. The means:
Here is the code for the project namespace initializer:
The first part is the same as for the Crm engine can could be extracted for reuse. The second part loads the projects routes, but also add a new projects route in the parties route. For the template, I create a new template with the exact same path and name that will be loaded after the crm template. It is a copy of the original template so it is not optimal, but there is no easy way of doing it otherwise. For what it is worth, rails uses the same "copy to extend" pattern for the views in engines. As for the model, I just reopen the class within the project namespace and add the relationship. Same goes for new actions on the controllers, routes, etc. The technique above works really well for now and if you can build upon that, that would be sweet. I hope this helps! |
I'm confused between the difference of this RFC and ember-cli's already existing addons. Addons are effectively rails-like engines already. Beyond the engine-specific container I see a lot of overlap. |
@bcardarella I mostly agree. The only thing addons can't do is add routes to the router map. Even that could be done today by exporting a mount function from the add-on that the user can call from their router map. |
@ef4 yup, ember-admin is kind of doing this already but you have to opt-into it: https://github.com/dockyard/ember-admin#usage @rwjblue and I have discussed a few time renaming the addons to engines, and I think the scope of ability of addons have outgrown the term "addon" itself. I'm all for this RFC I just don't think there needs to be a separate effort. |
One thing that is not discussed in the proposal is handling links between an engine and an application. In the example of authentication, it's almost certain that you will need to link to login page of the engine from the host application, for example
Another thing to discuss is if an engine should be allowed to run without a host application. In Rails this idea was abandoned, because of various technical difficulties and design decisions that were made earlier, but it could be possible in Ember.js. The question is if this is something useful in Ember.js world and if it's hard to implement. @lukemelia mentioned customisation, which is also something important. In my opinion overriding templates should work out of the box, so a properly namespaced template in the application should be rendered in the engine. On top of that, there should be a way to override any of the routes or controllers, possibly with ability to subclass them. For example I should be able to subclass Customisation is a hard topic in general, although it still looks much better than in Rails. Rails doesn't have any notion of view components out of the box. Instead, there are multiple ways to extend templates in engines, which mostly use a notion of annotations (you can annotate template with blocks, like |
One more thing that came to my mind in the topic of router is mounting engines on a dynamic routes. In Rails, you can do something like that: resource :users do
mount Blog::Engine
end which allows to link to blog in the following way: |
this could be handled by subexpressions |
i think the idea is to formalize and improve this part of ember to further facilitate ember-admin and similar efforts. @tomdale we should add ember-admin to our use-cases to review. |
I like this overall concept. Sounds like there are still some details to be resolved, but definitely a 👍 overall. |
Then rephrase my comment to say "we should consider using the same kind of interface that components use." Whether that's bubbling events or callbacks, I think there's a potential win here in reusing the same concept. |
I have another use case I'd like to see covered by this feature, please consider adding it to your list: I have several small chunks of application that get reused in multiple places. They're good candidates to become For example, I have a rich editor for a "Doctor's Order". It needs to be able to pop up in multiple different contexts whenever someone clicks on related content. It benefits from being a real Today I'm stuck metaprogramming my router map and Routes so that I can define them all once and then apply them underneath each resource that may need them. (I don't want to link to a single canonical resource for this, because I render it inside the currently active top-level tab of my application, and it retains a lot of surrounding context. These different contexts really are different conceptual routes.) |
Loving where this idea is going. I could totally use this today for breaking up complex apps, or reusing duplicate code across non-related apps. Would be super nice with ember-admin 👍 |
Would this engine mechanism allow each composing app to attach itself to a different root element? |
Something like? Router.map(function () {
this.resource('admin', function () {
this.mount('authentication', { path: 'auth' });
// other resources/routes..
});
}); |
@atsjj I personally don't need that feature. My thinking is that you'd still share a single root element, but maybe you can expand on your use case a little? |
@tomdale I wouldn't say I have a use case for such a feature, but rather have a situation that kinda happened. I've been adding some new functionality with Ember to an existing Rails app and I've had to work around the problem of my Ember project not owning the entire DOM. I wouldn't want to suggest that this kind of feature be added into this RFC, but rather if this feature just might implicitly happen given my understanding that an Engine is just another (Ember) app inside an app. All that being said, I'd be happy to share the actual case with you offline if you're interested. |
Restore engines to tomdale/rfcs:master
Sorry everyone 😬 |
Stop messing about @tomdale 😜 |
@dgeb - Does this engines proposal take into consideration various versions of Ember running in one app? Some background… based on our upgrade experience with Ember from early pre-1.0 versions up through v1.12 (became impossible to upgrade to 1.13 for us.) my current refactor effort involves breaking down a big app to many smaller apps. (I’ve had to do that before as well, sometimes a screen at a time.) And, based on previous history with JS library dependencies in big JS apps (e.g. multiple version of jQuery with noConflict) - I came to the conclusion that I do NOT want another big Ember app that has all it’s dependencies requiring compatibility with a single Ember version, either due to template compiling requirements or other constraint. Basically many smaller apps should afford the abilty to run various apps on various versions of Ember. |
The idea of |
@tschoartschi Work has begun on engines. The I'm now working with @rwjblue on an ember-engines addon that extends these new base classes and others in order to get engines working in ember-cli. We're aiming to make this addon public by the end of January. After concepts have been proven in this addon, we'll gradually roll the functionality into ember and ember-cli. |
@dgeb where is this (addon) work happening? |
@knownasilya the addon work is happening in a private repo that will be made public in the next few weeks (certainly before the end of January). |
@dgeb any update on when the repo will be made public? |
The ember-engines addon has been published. Although it should still be considered experimental, ember-engines does implement many of the concepts laid out in this RFC. Feedback and contributions welcome. |
This is excellent news! On Thu, Jan 14, 2016 at 1:59 PM sandstrom [email protected] wrote:
|
awesome 👏 |
Amazing job! Any thought on when will this addon will work on Beta/Release? Or even better, when will it be merged with Ember itself? |
when its ready |
@stefanpenner well that's obvious. The question is do we have a timeline? Like ember 2.7 for example... I would like to assist, but to get the funding from my company I need a timeline (not a strict one, just a give or take). |
@danshapir Implementation work has largely been lead by @dgeb and @rwjblue. I suggest looking into issues at https://github.com/dgeb/ember-engines/issues and reaching out to them for context. If you have the time you can definitely make an impact. |
Has anyone put much thought into how or if one should define styles in an engine? The issue is styles from the parent app could easily smash those defined in the engine. It seems like something cool could be done with ember-css-modules. The simple solution is to utilize the default, scoped behavior of CSS Modules to avoid conflicts altogether (or at least keep them to a minimum). Another option (that could be used in conjunction with this approach) is to have a way of defining styles in a component or controller that need to be fulfilled by the engine consumer. This would be pretty trivial seeing as how Ember-CSS-Modules already exposes a Anyways I may be overthinking this but we recently ran into this problem in a project I was working on with engines. |
@timkendall styles are a bit challenging due to the potential of overlaps, certainly tools or libs like css-modules can help, in our case, we're relying on well-scoped rules. I don't think this problem is specific to engines, add-ons and any other vendor styles that you pull-in have the same issue. That said, engines, once we get lazy loading make the problem a bit harder. Today we could rely on load order and test it to make sure we get the expected behavior (e.g. app styles load after vendor styles or component styles are imported in a certain order). Then we could either fix the scoping or change the order to get the desired behavior. With lazy loading, the order depends on which routes are visited first, making the style order non-deterministic and extremely hard to test since the permutations can be really high even with a small number of engines (n!). |
Merging finally 🎉 We should continue to refine Ember's public API related to engines via subsequent RFCs. And we are tracking issues and progress in the ember-engines addon. |
RFC