You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After a lot of debate and enduring weeks of inner turmoil, I've decided to move forward with a series of drastic changes that will be eventually released as Hyperapp 2.0.
Predictable as it may be, my plan was to leave things the way they are here and create a new JavaScript framework. A direct competitor to Hyperapp, but pretty much the same under the hood. I am calling that off and going to focus on making a better Hyperapp instead!
Breaking changes again? I am afraid so. I'm unsatisfied with how some things work in Hyperapp and want to fix them to the bone, not start a brand new project. I don't think I will be able to fairly concentrate on two projects that have exactly the same goal when what differentiates them are just some subtle (but important) API differences.
What will change?
With 2.0 I intend to fix several pain points I've experienced with Hyperapp due to its extreme DIY-ness. In the words of @okwolf:
Hyperapp holds firm on the functional programming front when managing your state, but takes a pragmatic approach to allowing for side effects, asynchronous actions, and DOM manipulations.
Hyperapp is minimal and pragmatic and I don't want to change it but in order to improve, we need to do more for the user. So, this is what I am going to focus on:
Easy to test — By making actions and effects pure, testing will be a piece of cake.
The biggest surprise here is that you no longer need to pass the actions to the app() call, wait for them to be wired to state changes and receive them inside the view or any of that wacky stuff. It just works.
How to pass data into the action? Just use JavaScript.
You can create a closure that receives the data and returns a function that HA expects num => state => ({ count: state.count + num }) or use the tuple syntax (preferable) as shown below.
Yes, you just put the value { count: 0 } there and you're done.
Side Effects
Ok, time to cut to the chase. How are going to do async stuff now?
import{h,app}from"hyperapp"import{delay}from"@hyperapp/fx"constup=state=>({count: state.count+1})// This is how we define an effect (Elm calls it commands).constdelayedUp=delay(1000,up)app({init: {count: 0},view: state=>(<div><h1>{state.count}</h1><buttononclick={up}>+1</button><buttononclick={delayedUp}>+1 with delay</button></div>),container: document.body})
What if I want to set the state to something and cause a side effect to happen at the same time? I have you covered (almost). In Elm, they have tuples, but in JavaScript we only have arrays. So, let's use them.
There's one more important new feature: Subscriptions. Aptly ripped off Elm's subscriptions, this is how we are going to listen for external input now.
import{h,app}from"hyperapp"import{Mouse}from"@hyperapp/subscriptions"// I am open to a shorter name.constpositionChanged=(state,mouse)=>({x: mouse.x,y: mouse.y})constmain=app({init: {x: 0,y: 0},view: state=>`${state.x}, ${state.y}`,subscriptions: state=>[Mouse.move(positionChanged)],container: document.body})
What's breaking?
Slices will be gone. There will be other mechanism to easily update props deeply nested, but other than that bye bye slices.
Obviously, actions that cause side effects will need to be upgraded to use managed FX, which should be a joy — you'll love FX. I don't believe this will be a particular difficult feat, but we'll see. For 1.0 migration help and support I've created a #1to2 channel in Slack, please join! 🎉
Other
Middleware
Some things are still undecided. Should Hyperapp export all side effects? Perhaps we can reuse @hyperapp/fx for that?
I am going to remove slices! But now that actions are decoupled from the state update mechanism, we should be able to come up with similar patterns doing something similar to Redux's combineReducers.
Actions return a new state (not a partial state), so you need to merge the current state with whatever you return, similar to redux.
Lifecycle events? I am still not sure how to handle these. For now, I'll keep them the way they are.
Bundle size? All the core stuff is, in fact, less than current Hyperapp, but adding effects to that will makes us closer to 2 kB.
My interests have shifted to care more code readability and less about code golfing. A tiny code base is still a big priority for me, but not at the expense of making the code unreadable.
Server side rendering? I'm torn on this one. Should it be available out of the box or should we continue using @hyperapp/render? I am going to need @frenzzy to chime on this one.
JSX, @hyperapp/html, hyperx, h. Nothing is changing about here.
The router will continue to be an external module.
Background
After a lot of debate and enduring weeks of inner turmoil, I've decided to move forward with a series of drastic changes that will be eventually released as Hyperapp 2.0.
Predictable as it may be, my plan was to leave things the way they are here and create a new JavaScript framework. A direct competitor to Hyperapp, but pretty much the same under the hood. I am calling that off and going to focus on making a better Hyperapp instead!
Breaking changes again? I am afraid so. I'm unsatisfied with how some things work in Hyperapp and want to fix them to the bone, not start a brand new project. I don't think I will be able to fairly concentrate on two projects that have exactly the same goal when what differentiates them are just some subtle (but important) API differences.
What will change?
With 2.0 I intend to fix several pain points I've experienced with Hyperapp due to its extreme DIY-ness. In the words of @okwolf:
Hyperapp is minimal and pragmatic and I don't want to change it but in order to improve, we need to do more for the user. So, this is what I am going to focus on:
dynamic(import("./future-component")). Fix Dynamic actions: How to add new actions at runtime? #533.Show me the money!
The Simple Counter
Let's begin with a simple counter and kick it up a notch afterward.
The biggest surprise here is that you no longer need to pass the actions to the app() call, wait for them to be wired to state changes and receive them inside the view or any of that wacky stuff. It just works.
How to pass data into the action?
Just use JavaScript.This looks very similar to 1.0, the difference is that the curried function is completely justified now — not built-in or forced upon you.
Here's an interesting way you will be able to reset the count.
Yes, you just put the value { count: 0 } there and you're done.
Side Effects
Ok, time to cut to the chase. How are going to do async stuff now?
What if I want to set the state to something and cause a side effect to happen at the same time? I have you covered (almost). In Elm, they have tuples, but in JavaScript we only have arrays. So, let's use them.
Notice that creating a function for actions and effects is A Good Practice, but nothing prevents you from doing this:
What about a full example that fetches some information on initialization? The following example is ported from Hyperapp + Hyperapp FX here.
Handling data from DOM events?
DOM events, like effects, produce a result or have data associated with them (http fetch response, DOM
event, etc).Interoperability
Absolutely. The app function will now return a
dispatchfunction (instead of "wired actions") so you can execute actions or effects at will.Dynamic Imports
What about dynamic imported components out of the box?
Subscriptions
There's one more important new feature: Subscriptions. Aptly ripped off Elm's subscriptions, this is how we are going to listen for external input now.
What's breaking?
#1to2channel in Slack, please join! 🎉Other
Middleware
Some things are still undecided. Should Hyperapp export all side effects? Perhaps we can reuse
@hyperapp/fxfor that?I am going to remove slices! But now that actions are decoupled from the state update mechanism, we should be able to come up with similar patterns doing something similar to Redux's
combineReducers.Actions return a new state (not a partial state), so you need to merge the current state with whatever you return, similar to redux.
Lifecycle events? I am still not sure how to handle these. For now, I'll keep them the way they are.
Bundle size? All the core stuff is, in fact, less than current Hyperapp, but adding effects to that will makes us closer to 2 kB.
My interests have shifted to care more code readability and less about code golfing. A tiny code base is still a big priority for me, but not at the expense of making the code unreadable.
Server side rendering? I'm torn on this one. Should it be available out of the box or should we continue using
@hyperapp/render? I am going to need @frenzzy to chime on this one.JSX, @hyperapp/html, hyperx, h. Nothing is changing about here.
The router will continue to be an external module.
I'm still working hard to improve the performance and 2.0 will not affect Rewrite patch algo / improve diffing performance #499 or Keyed children diff optimization #663. I suspect 2.0 will have slightly better performance out of the box because of how DOM events are going to be handled now.
When is this going to be available?
Very soon. I'll be pushing all the stuff to the
fringebranch and publish as[email protected]as soon as I can so we all can start playing with this.Related