rfcs
rfcs copied to clipboard
Default Modifier Manager
Polyfill: https://github.com/NullVoxPopuli/ember-functions-as-modifiers-polyfill
Places to update (if they aren't mentioned in the RFC (I forget))
- https://guides.emberjs.com/release/components/template-lifecycle-dom-and-modifiers/#toc_abstracting-the-logic-into-a-custom-modifier
gonna try to update this RFC this weekend with all the things I learned from the default-helper-manager RFC and phrase things from first-principles' perspectives, and then we can get this RFC movin!!!!
Updated!
Made an addon to try it out: https://github.com/NullVoxPopuli/ember-functions-as-modifiers-polyfill
Hey @NullVoxPopuli, we chatted about this briefly at today’s Framework Core team meeting, and we all agree that the basic idea is good, but folks had some thoughts about what the shape of the API should be, as well as how it fits in timing-wise with #779, which substantially ups the importance and perceived urgency of this design. We’ll be in touch to work through some of those details with you in a “spec” working group context to hammer down those details.
Thanks again for getting the ball rolling here!
We’ll be in touch...
Narrator: They were not in touch.
In all seriousness though, what needs to be done here? @chriskrycho
I believe we actually have been: @wycats has chatted with @NullVoxPopuli about a bunch of related pieces here (and for Resources), based in part on the Starbeam research, and I believe they’ve made some progress there. We should revisit current status though!
I believe the main consideration around function-based modifiers and a default manager is the exact shape of the teardown handling. The current design just returns a teardown function. I think the idea from Starbeam is to return a slightly richer object which includes that.
@chriskrycho I should have made it clear that I thought it was likely that there was some conversation, it’s just not visible here.
@chriskrycho said:
I believe the main consideration around function-based modifiers and a default manager is the exact shape of the teardown handling. The current design just returns a teardown function. I think the idea from Starbeam is to return a slightly richer object which includes that.
This is about right. The longer version is that Starbeam's design supports multiple setup blocks (each of which can run either in "layout" / pre-paint timing or in normal / idle timing), and each of which can have its own teardown.
Most but not all of this can theoretically be built on top of modifier manager. We don't need to add those features now, but it's nice for the "just a function" API design to leave space for future extensions along these lines.
Another consideration from Starbeam: Starbeam modifiers can be invoked with a "ref" that gets filled in dynamically with an element, and once the ref is filled in, the modifier's lifecycle begins.
Ember doesn't strictly need that design, because our lifecycle is largely managed through the implementation of the template runtime. However, if we want to support invoking modifiers directly, we might want to consider having them take a reference rather than an element. It's not strictly necessary, because you can always call the modifier in the same place as you fill in the element reference.
That said, for Starbeam, the extra indirection allows the reference to be filled in by the internals of third-party code (like another framework), and this may be useful for Ember as well.
I don't think any of this is a blocker to making some tactical progress on this issue, but I suppose @NullVoxPopuli and I should work together to update this proposal to match the Starbeam design and see what people think 😄
@wycats @NullVoxPopuli nudge to work on this RFC and update it. <3
Gonna copy some disco from Discord so it doesn't get lost:
last we schemed, we were thinking about ditching ember-modifier in favor of resources -- something similar to: https://reactive.nullvoxpopuli.com/functions/resource_modifier.modifier.html
tho, in general, we need native support for resource builders so the modifier import wouldn't be needed
there are some questions about timing as well, related to
- https://github.com/emberjs/rfcs/pull/883
- and https://github.com/emberjs/rfcs/pull/957
cc @runspired @wycats @ef4
one main thing we need for any of this to be ergonomic is to have a chained invocation (at some timing) in the rendering layer. like:
// modifier
function myModifier(element, ...args) {
// abstraction that handles cleanup here
}
// resource
function ConnectionStatus() {
// abstraction that handles cleanup here
}
// these are the same, authoring wise, except for their signature and usage in syntax:
<template>
<div {{myModifier}}>{{Clock}}</div>
</template>
where:
// abstraction that handles cleanup here
could be:
function myModifier(element, ...args) {
return resource(({ on }) => {
on.cleanup(() => {});
});
}
function ConnectionStatus() {
return resource(({ on }) => {
on.cleanup(() => {});
return () => someValue;
});
}
or
function myModifier(element, ...args) {
// setup here
return {
/* custom properties for reactivity or something */,
/* handle for the framework to destroy, like on.cleanup */
[Symbol.dispose]() {
// cleanup here
}
}
}
function ConnectionStatus() {
// setup here
return {
// special getter? or do we require properties?
// (eliminating the possibility that resources today
// have where they can represent plain values
// (I would not like losing that 😅 )
get value() {
return someValue;
},
/* custom properties for reactivity or something */,
/* handle for the framework to destroy, like on.cleanup */
[Symbol.dispose]() {
// cleanup here
}
}
}
using Symbol.dispose could one day be the implementation of resources -- but we still have to explore timing semantics, as on gives us more API/timing surfaces to explore (as well as a synchronization phase, which can't currently be implemented in ember)
an idea if/when dispose lands
to get plain values back, maybe we could do some... prototype hacks.function ConnectionStatus() {
// setup here
const result = someValue;
result[Symbol.dispose] = () => { /* cleanup */ };
return result;
}
idk, probably terrible.
the chained invocation is needed because we need to call the factory function, and then "do something" with the thing it returns.
this would either be using the HelperManager or ModifierManager syntems based on usage in the template (edited) in any case, it'd be very hard to get away from any imports for modifiers unless you didn't need cleanup at all
tho, an importless modifier could be one that uses native disposables, like above -- but we don't even have Symbol.dispose yet in browsers, so we can't really do that yet.