alfonsogarciacaro / fable-vue

Fable bindings for Vue.js
35 stars 2 forks source link

Embrace Vuex? #6

Open alfonsogarciacaro opened 5 years ago

alfonsogarciacaro commented 5 years ago

Seems the standard tool for state management in Vue ecosystem is Vuex, should we use it or try to implement Elmish for Vue instead? (Maybe we could event adapt Elmish to Vue.)

Some of the benefits of Vuex are the integration with the Vue devtools and apparently some performance improvements too.

Zaid-Ajaj commented 5 years ago

YES Please! Maybe we can add a mini-elmish on top of the store (mutations = msgs, actions = commands), although I am not sure how performance goes if we don't mutate but create a new instance of the state type instead like we do with react. data communication is another concern

alfonsogarciacaro commented 5 years ago

Maybe we can do something as it's done here but in a nested fashion to only mutate the fields that have actually changed. What do you mean by data communication?

Zaid-Ajaj commented 5 years ago

Maybe we can do something as it's done here but in a nested fashion to only mutate the fields that have actually changed

Sounds like a plan

What do you mean by data communication?

I assume the state of the store will be a big record type with field having the type of the states of the children, so I was wondering to extract the child states from the store in a type-safe manner. I have to play around with the code to get a feel for it ;)

alfonsogarciacaro commented 5 years ago

Seems Vuex has the concept of modules, but I assume we don't need really them when using typed records for the store model. Maybe we can add a makeComponentWithStore helper or similar and then we pass a projection function to select the local store from the global store (probably the projection should be passed when instantiating the component, to avoid making the component dependent of the App store type).

We can try things on the go, I'm sure that as we add pieces to the puzzle (router, etc.) we'll realize we've missing things anyways :)

Lanayx commented 5 years ago

Writing here as active user of both F# and Vue.js =) Will be glad to help as well, and here are some thoughts. 1) Please try using Vuex as it is, don't implement your own solution. Reason for that are Vuex plugins, extensions and user experience. Vuex is the cornerstone of the Vue success, leave it as is =) 2) Try contacting Evan You regarding Vue 3.0 features. He planned to get rid of Actions and Mutations separation, so it's better not to become legacy from the start. He also promised to provide better support for external vue compilers integration in 3.0 3) Many people use mapping for Vuex store in components (mapState, mapGetters, mapActions and mapMutations.), they would be happy to continue using it 4) As for modules, their purpose is to create namespaces, so actions from one module won't accidently call mutations or getters from another, it's a native thing for Vue users 4) Nuxt is the most successful project on the top of the Vue.js, it gives SSR build on the top of several hooks, static file structure and of course Vuex, ideally I would like to see the same ability in our F# world as well.

Zaid-Ajaj commented 5 years ago

Hello there @Lanayx, thanks for chiming in on the subject matter and your help is really appreciated if we could make something nice out of this because my own knowledge of vue.js is quite limited

Let me go through your points

Please try using Vuex as it is, don't implement your own solution. Reason for that are Vuex plugins, extensions and user experience. Vuex is the cornerstone of the Vue success, leave it as is =)

This is the plan, we are currently trying to see how to make a binding on top of vuex that can be used in a type safe manner, preferably using union messages and update functions. I am playing around with it now but it still not entirely clear how the mapping should be done. Or are you suggesting to literally keep using vuex as is by defining mutations and actions?

Try contacting Evan You regarding Vue 3.0 features. He planned to get rid of Actions and Mutations separation, so it's better not to become legacy from the start. He also promised to provide better support for external vue compilers integration in 3.0

I guess waiting for the features to stabilize first would fine for now, there still quite a lot to figure out on how to make this work nicely in a type-safe way

Many people use mapping for Vuex store in components (mapState, mapGetters, mapActions and mapMutations.), they would be happy to continue using it

Using these would mean that child components would know about the outer (parent) state types, just like @alfonsogarciacaro said, it would be ideal if a child component takes a getState function from outside that decides what data the child component will have (sorry if this is vague, I don't have sample code yet)

As for modules, their purpose is to create namespaces, so actions from one module won't accidently call mutations or getters from another, it's a native thing for Vue users

If we make getState right, then it would not be possible for child components to mutate other parts of the app.

Nuxt is the most successful project on the top of the Vue.js, it gives SSR build on the top of several hooks, static file structure and of course Vuex, ideally I would like to see the same ability in our F# world as well.

Lanayx commented 5 years ago

What I want to achieve with Fable+Vue is not another architecture, but the same architecture, ideally only thing that should be changed is js => fsharp similarly to how it is done using js => ts As for Vuex actions and mutations, what usually is done is defining constants and using dispatch on those constants, I don't have any problems with those, only thing I'm missing is typed parameters in actions and mutations. As for features, here is a roadmap https://github.com/vuejs/roadmap, they moved joining actions and mutations to 4.0. I personally don't use Vuex mutations and mutate state in Actions, since it is more convenient and sooner or later mutations will be deprecated.. Regarding stores, it's not that is should be impossible to call one child module from another, vice versa, sometimes it is very useful to do this. However, I think if the modules will be typed, calling a function from a specific typed module should be very convenient, since now in js prepending actions with module name is a bit painful. Regarding should store be mutable or immutable, I'm totally for the first option. The big idea of Vuex is that it is a single mutable object, but mutations are only allowed from the store itself. From performance perspective I think Fable should follow this, because Vue.js is fast, it will be even faster in 3.0 and while adding all F# goodness, this speed shouldn't be lost.

ghost commented 5 years ago

but keep fable.vue (core) and fable.vuex as separate packages :crossed_fingers:

alfonsogarciacaro commented 5 years ago

Thanks a lot for your comments @Lanayx! I'm also just starting Vue so your experience is really helpful 🙌

Do you happen to know an example of a medium-size Vue app using Vuex in a standard way? I'm going through the documentation but I haven't found yet a comprehensive example combining most of the concepts.

Trying to translate such an app to F# would be useful to see what kind of challenges will be facing and how also how most adequately can we bind to Vue concepts using F# as idiomatic as possible.

Lanayx commented 5 years ago

@alfonsogarciacaro Ok, I'll provide two examples for both real-world app as well as standard approach in 1-2 days

Lanayx commented 5 years ago

@alfonsogarciacaro Was able to make it earlier =) Here is an example of repo with a quite standard approach (vuex with actions and mutations, router with authguard, computed properties connected to vuex getters, access to low-level apis like $el, $refs, watch, store with modules) https://github.com/berksaribas/vuetify-chat

And a real world example, that uses Nuxt on top of Vue.js which is a default choice for any sites with SSR requirement. What else was used: external components, store extension, more external libs, folder structure instead of router, middleware, some nuxt-specific hooks (fetch, nuxtServerInit), constants as names for actions, mutating state in actions, cross-module communication. Unfortunately I can't provide server for this. https://github.com/Lanayx/FVRealExample

One of the ideas for Vuex with Vue is that you are free to choose between local component data and Vuex in case several components are involved.

alfonsogarciacaro commented 5 years ago

This is great @Lanayx, thanks a lot! This is going to be tremendously helpful 🏅