ccorcos/elmish

Library status

eliperelman opened this issue ยท 14 comments

I've been reading over the tutorials and I really like the concept and its surface. I'm curious to know about the ability of using elmish as a library, as the repo seems to be in a state of instability. I looked through the branches and it seems that the mego branch has been going through some recent change.

Do you know what it would take in order to make this project user-ready?

Thanks :)

So the master branch is "stable" but has some flaws that I've been trying to address, primarily having to do with large-scale performance. If you want to build a project with it that is going to be huge and supported for all of time, I'd say go for it. Its a simple pattern and you can change it however you want to fit your needs.a

In the mego branch, I'm looking into a few additional concepts addressing some things that aren't ideal with the existing pattern on master:

  • performance isnt scalable from a complexity standpoint since every action requires an entire re-render and re-parsing or all declarative side-effects. In the lazy branch, I explored how to solve this issue with this concept of "partially applied function equality", and I think thats a decent solution that I've adopted into the Z library in the mego branch.
  • with all this laziness stuff, there starts to be an annoying amount of boilerplate for the developer, especially for dynamic higher order components like listOf, so I'm exploring ways of dealing with that. For static components, a simple schema is easy to define and generate everything which I've implemented in mego. But for more complicated components like listOf or undoable, the schemas are arbitrary. So I think a good solution there would be to make the schema a function of state, and return lenses for setting and getting the state of each subcomponent in the schema. This is not implemented yet and where I'm currently exploring in this README.
  • another problem with the existing master pattern is that when data needs to be shared between sibling components, it needs to live in a common ancestor and get piped around to all the components through props. This is annoying and somethign I hate dealing with in React. So I have this concept of publications, where a component can publish information from its state, and other components and subscribe to that publication by means of a lens. Parent components merge lenses and thus only the information needed by a single component and its subcomponents get passed down so we can maintain good performance characteristics. This is also a WIP but shouldnt be too hard after we get the schemas down.
  • lastly, I need to think harder about a set of helper functions for building services. I want every service to parse lazy trees, just like React, so we can get the same performance characteristics. This way we dont have to diff the entire tree if we know a component's state is the same.

So there's a bunch of stuff I want to explore still. I welcome any input or help on this if youre interested. I've committed myself not to build any more side-project apps until I've come up with a frontend architecture that doesnt suck, so I'm going to keep working on this once my job calms down a little bit.

The last thing I'll want to do is analyse the performance characteristics of the entire app. Thats something that is rarely done in a rigorous fashion and since this app is entirely composed of pure functions it should be possible. And in that regard, the only concern I have left with this entire approach is the complexity associated with comparing partially applied functions because the comparison will depend on the depth of the component hierarchy.... This is just speculation at this point though. We'll see :)

My biggest concern is making sure that the API is simple to consume, and project structure is easy to follow and implement. It seems like mego has a good start, just need to simplify some things in that regard. Maybe a sample project using mego would be useful as well that can evolve as the branch does.

For services, it would also be nice to be able to plug in external services easily.

Anyway, I'll take a look at mego and see if there's anything I can contribute to moving this along.

Maybe a sample project using mego would be useful as well that can evolve as the branch does.

Thats going to be a while -- I havent figured out all the schema crawling stuff yet..

For services, it would also be nice to be able to plug in external services easily.

Thats the plan! Just like the way master works.

Anyway, I'll take a look at mego and see if there's anything I can contribute to moving this along.

Sounds good ๐Ÿ‘

@eliperelman after some recent insights I've created a new branch that I think is going to work:

https://github.com/ccorcos/elmish/blob/inverted/v11/main.js

Rather than map over dispatch and passing the subcomponent state on (like we did before), we pass the global dispatch and state and let the component narrow down on the state that it wants. This makes it much easier on the developer. We do this by "lifting" components. Then the component keeps track of a lens for reading and mutating the global state, and maps over the actions to nest them appropriately.

This also make the publish/subscribe implementation pretty easy :)

I'm working on building services now but I want to do it the lazily so its performant (just like React). I've been working on this tree / lazyReduce concept here:

https://github.com/ccorcos/elmish/blob/inverted/v12/tree.js

I think its going to work quite well. And so long as we lift any subcomponents, the services can crawl the entire component tree.

There are only two things that are still up in the air conceptually.

  1. when you lift a component, how can you specify if you want the actions to seamlessly route to the subcomponents or if you want to override/block them? I think this will likely involve some kind of overriding behavior like a _update method.

  2. how do you specify lifted subcomponents for dynamic higher-order functions like undoable and listOf so that services can crawl the entire component hierarchy? I think the solution will be to have a special function like _lifted which accepts state and produces the lifted components dynamically. The difference here is that the initial state needs to be explicitly constructed rather than generated under the hood.

I also think we could support all Redux middleware is we fake out the store api which would be really cool. Although I find that most redux middleware breaks purity :/

Anyways, let me know what you think, if you're still interested in this.

@eliperelman this is going to be the workhorse of pretty much ever service: https://github.com/ccorcos/lazy-tree

@ccorcos sorry I haven't responded, been a little busy lately. I'm taking a look now.

I haven't dove into v11 elmish code yet, but just a quick question, in update:

return { count: state.count + 1 }

Are you re-creating the state, returning an object to be merged with state, or something else?

In other words, can you evolve the state from update outside your component bounds?

h('button.dec', {onClick: dispatch('dec')}, '-')

So, this dispatch is different than the standard Redux dispatch, does it return a function that dispatches the action? e.g.?:

// reduced for brevity
const dispatch = (action) => () => redux.dispatch(action);

I've always liked doing it that way, but naming it dispatch I think might cause confusion about what it does vs. redux dispatch. Maybe dispatcher/dispatches?

With JSX:

<button className="dec" onClick={dispatches('dec')}>-</button>

I like where this is going. I'm a JS developer, so it's nice to be able to write with the elm-like patterns but in JS.

The pain point I noticed at first glance in the tutorials when listOf is introduced, it seems like some awkward boilerplate code when configuring listOf dispatch to handle the child dispatches. Is there a better way?

If listOf is a default tool in the library, then I don't really have to worry about it. x]

I have a much better way :) I'll show you when I'm back at my computer
On Thu, Sep 29, 2016 at 12:42 Joseph Orbegoso Pea notifications@github.com
wrote:

I like where this is going. I'm a JS developer, so it's nice to be able to
write with the elm-like patterns but in JS.

The pain point I noticed at first glance in the tutorials when listOf is
introduced, it seems like some awkward boilerplate code when configuring
listOf dispatch to handle the child dispatches. Is there a better way?

If listOf is a default tool in the library, then I don't really have to
worry about it. x]

โ€”
You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
#1 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/ABth3y2ixtzJ9qZjLi1xUKmQEL82S7Znks5qvBSdgaJpZM4JCMs6
.

Cool, show me in person! When's the next meetup you're going to?

No immediate plans. But I'm down for something.

this is what it looks like: https://github.com/ccorcos/elmish/blob/inverted/v16/main.js#L122-L135

Need some tutorial comments. x}