davestewart / vuex-pathify

Vue / Vuex plugin providing a unified path syntax to Vuex stores
https://davestewart.github.io/vuex-pathify
MIT License
1.37k stars 57 forks source link

Are there any plans to port vuex-pathify to vue3 or is this project becoming abandonware? Thanks. #130

Open iKnowMagic opened 3 years ago

iKnowMagic commented 3 years ago

Inquiring about vuex-pathify being ported to vue3

davestewart commented 3 years ago

Ouch! That hurts 😆

Well, the codebase has been stable on Vue 2 so I simply haven't needed to make any updates for a long while.

As for Vue 3, I would need to a) know what best practices are and b) look into the state of Vuex in Vue 3.

Are these things pretty much settled now?

Maybe you can help with some answers and I can look to see what I can do.

iKnowMagic commented 3 years ago

Thanks.

vuex-pathify was sort of working with Vuex 4; the "get" component helper did not work but the "sync" helper did work. Now Vuex is throwing all sorts of errors when used with vuex-pathify. See the attached screenshot for an example.

image

As it is, it looks like vuex-pathify is not usable with Vuex 4 (Vue 3).

NGPixel commented 3 years ago

I also started to use Vue 3 for a new project and found out that vuex-pathify doesn't work.

The main issues seem to be:

Hopefully this library can be updated to work with Vue 3 as it makes working with vuex so much easier!

davestewart commented 3 years ago

OK, good info; thanks both.

I'm currently deep into another project and finding it very hard to find the time and brainpower to switch to anything else, but I get that the more time goes by, the more chance you guys will have of jumping ship, so I'll make this a priority.

Sorry it's been so long since I checked in on GitHub as well; that should give you an idea of where my focus is right now!

bkarlson commented 3 years ago

It seems like Vue 3 is not supported by vue-class-component yet, their README is confusing. Gotta wait a bit more I guess.. https://yarnpkg.com/package/vue-class-component

MajesticPotatoe commented 3 years ago

Oddly enough, I've been experimenting with vuex-pathify on vue3 + vite and managed to get it working. Had to force vuex-pathify to use vue-class-component v8.0.0-beta.2, and had to borrow some stuff from #95 to get it working in setup(). Haven't run into any of the errors mentioned about with get or sync, and the one VCC error was solved with the beta.2, so looks promising.

iKnowMagic commented 3 years ago

How about using adjusting vuex-pathify to work with vue 3.1+, since vue 3.1+ is supposed to be fully backward-compatible with vue 2 ?

davestewart commented 3 years ago

Sorry everyone; I've not been good to my word and haven't worked on this yet.

Can someone set up a sample project and post the repo link?

As soon as that is done, I will work on this.

Thanks.

NGPixel commented 3 years ago

I made a fork of the project without the vue-class-component dependency. This fixes all the warnings when using Vue 3. Also replaced rollup with esbuild for the actual build as I was getting all sort of errors.

It has both the CommonJS and ESM versions.

# Using npm:
npm install @requarks/vuex-pathify

# Using yarn:
yarn add @requarks/vuex-pathify

Hopefully we'll see an updated version from the maintainers in the future, but in the meantime this should address the issues raised for Vue 3.

davestewart commented 3 years ago

Hey @NGPixel - I'm happy to merge this if it does the job.

Do you want to make a PR for further discussion?

iKnowMagic commented 3 years ago

@NGPixel Many thanks for the work :) I installed your version and unfortunately, the types are missing; without types, it is breaking Vue 3 / Typescript.

NGPixel commented 3 years ago

@iKnowMagic I added back the typings in 2.0.2 while removing the vue-class-components reference from them. However I'm not using Typescript so I have no idea if more changes are needed. Let me know...

@davestewart I can make a PR but my version basically just undo the vue-class-component PR. So anyone that relies on these decorators would see their project break. I don't have any experience with decorators so I wouldn't be the best person to propose a proper update to the library while keeping this functionality. I simply wanted a quick patch that removes the warnings caused by vue-class-components. So this is probably not what you want, unless you want to create a major version that removes that functionality altogether.

I also stripped much of the project (docs, demo, tests, etc.) to remove any rollup dependencies which were causing npm install errors (specifically node-sass which is deprecated anyway). Some work would need to be done on that front as well.

davestewart commented 3 years ago

@NGPixel - gotcha.

Well, thanks for sharing the info. The Vue 3 version will be a major version patch for sure.

Based on what @iKnowMagic has mentioned, I may just rewrite it in TypeScript and kill two birds with one stone.

iKnowMagic commented 3 years ago

Thank you so much @davestewart @NGPixel the types from the current vuex-pathify version would not work out-of-the-box, unfortunately

davestewart commented 3 years ago

@iKnowMagic what's the situation in Vue 3 regarding state these days?

I haven't really looked at Vue 3 and certainly not looked at Vuex development for a long time now.

What do people favour?

NGPixel commented 3 years ago

@davestewart Vue 3 works great with the new Vuex 4 and is still the way the go for state management.

julie777 commented 3 years ago

it appears that pathify partly works with vue 3 and vuex 4 (I am using quasar 2).

The normal vue 3 way of accessing the store const store = useStore() works for get and set as those methods are added to the store by pathify. However the sync method is not added to the store.

Using import { get, sync } from 'vuex-pathify'; to provide the functionality doesn't work because get and sync try to access the store using this.$store.

It seems as though all that is necessary is to bind the sync and call methods to the store the same way get and set are.

Okay, I'm adding more info. Using the Vue 3 composition api, I can't get the spread operator to work. I'm new to js and vue, so it might be my problem.

pathify works fine if, using the vue composition api, I use the const store = useStore and them write my computed functions for get and set using store.get and store.set. So for simple uses I can use pathify and I am happy for now.

It looks like sync could be added to helpers/accessors.js and that would allow sync to work with vue 3

iKnowMagic commented 3 years ago

@davestewart Vite is taking over the web development landscape.

VueUse is becoming a highly recommended companion to Vue development.

Vue 3 benefits greatly with TypeScript.

Pinia may be a good replacement for Vuex and may offer insight into Vuex 5. Still, Vuex 4 is the most used store management solution. Some may say that Vuex is not necessary anymore (even VueUse provides simplified store management), but I think Vuex still has a good place in the Vue ecosystem.

Vuex is unfortunately too verbose and that's where vuex-pathify has a huge potential as a companion library to Vuex.

vue-demi may help create projects that are compatible with both Vue 2 and Vue 3. There is also the @vue/compat library, that provides backward compatibility from Vue 3 to Vue 2.

If anything I would say that future-proof projects need to be compatible with Vite, TypeScript, and Vue 3.

:)

davestewart commented 3 years ago

Using import { get, sync } from 'vuex-pathify'; to provide the functionality doesn't work because get and sync try to access the store using this.$store.

That should bind the scope to the component instance; I presume you can still access the store through this.$store ?

In any case, I think I realised that my current injection of the global store into Pathify is needlessly complex (the original implementation was based on a possibly misunderstanding of some issues around how webpack handles importing) so I might be able to simplify all this.

Anyway, thanks for all the information folks!

FWIW, what has been keeping me away from Pathify all this time is something I've been working myself into the ground on this last 18 months; a new browser tab manager called Control Space; here's a little sneak peek:

image

I'm in the last week before the 1.0 launch (after 14 betas!) so should absolutely be able to find some time for this.

A couple of links if you are interested to know more:

Cheers, Dave

julie777 commented 3 years ago

"I presume you can still access the store through this.$store ?"

With the vue 3 composition api there is no access to this. I believe that is why the new way to access the store is to use const store = useStore().

I agree that simplification is good, and it seems like the pathify codebase could shrink if you don't do all the work relating to the global vue instance. BTW, that is one of the big changes in VUE 3 is that you are not supposed to access the global vue instance because there can be more than one root vue instance. (I think I understood that correctly from the vue doc and from the way that quasar 2 is doing initilization of the vue app.)

davestewart commented 3 years ago

Thanks @julie777 - maybe the best bet would be to inject it via the options

julie777 commented 3 years ago

I went and reviewed a bit. For vue 3 with the composition api the suggestion is to provide access either with provide/inject or for things like the store that are essentially global modules const x = useX() which is suggested instead of having the store module export store as an object.

The are two benefits to be gained from using pathify, for simple stores with multiple modules. One is the simplification of the vue component code, and even better is the huge simplification and reduction in the store code that I have to write. My store code is now trivial with only state. Getting ride of all the extra files and needing to write mutators, etc. was very nice. I now have a concise definition of what my store is storing. My vue code is not much simpler yet, but adding sync to accessors.js would help that. Being able to "spread" the sync would make it very concise.

const store = useStore()    // used for both cases

// without pathify
const leftDrawerOpen = computed({
{
  get() { return store.state.view.leftDrawerOpen },
  set(val) { store.commit('view/updateLeftDrawerOpen', val) }
})

// with pathify
const leftDrawerOpen = computed({
  get() { return store.get('view/leftDrawerOpen') },
  set(newValue) { store.set('view/leftDrawerOpen', newValue) }
})

// with sync
const leftDrawerOpen = computed(()=> store.sync('view/leftDrawerOpen')

Tame the Vuex Beast with vuex-pathify is a nice article that shows the advantage of pathify, but it is for the view options api.

I can imagine how nice it would be to only need the following in my code

const {value1, value1, value3} = computed(() => store.sync(['x/value1', 'x/y/value2', 'something/somethingelse/value3']))
davestewart commented 3 years ago

I can imagine how nice it would be to only need the following in my code

That indeed would be cool.

We have something like that at the moment with *, but I get your intention to reference multiple stores' properties here

davestewart commented 3 years ago

I mentioned this further up, but if someone had time to create a simple Vue 3 / Vuex 4 repo that I could use as a starting point, or reference an existing one, that would be a great head start when I do start this.

disarticulate commented 3 years ago

@davestewart https://github.com/disarticulate/quasar-base

I installed vuex-pathify the way that was recommended in the docs at one point, and has been smooth sailing through several iterations.

It still appears to be working for whatever I've done needed it for.

The only issue I see but haven't had any 'problems' with except a console warning:

 App •  WARNING  •  UI  in ./node_modules/vue-class-component/dist/vue-class-component.esm.js

export 'default' (imported as 'Vue') was not found in 'vue' (possible exports: $computed, $fromRefs, $raw, $ref, $shallowRef, BaseTransition, Comment, EffectScope, Fragment, KeepAlive, ReactiveEffect, Static, Suspense, Teleport, Text, Transition, TransitionGroup, VueElement, callWithAsyncErrorHandling, callWithErrorHandling, camelize, capitalize, cloneVNode, compatUtils, compile, computed, createApp, createBlock, createCommentVNode, createElementBlock, createElementVNode, createHydrationRenderer, createRenderer, createSSRApp, createSlots, createStaticVNode, createTextVNode, createVNode, customRef, defineAsyncComponent, defineComponent, defineCustomElement, defineEmits, defineExpose, defineProps, defineSSRCustomElement, devtools, effect, effectScope, getCurrentInstance, getCurrentScope, getTransitionRawChildren, guardReactiveProps, h, handleError, hydrate, initCustomFormatter, inject, isMemoSame, isProxy, isReactive, isReadonly, isRef, isRuntimeOnly, isVNode, markRaw, mergeDefaults, mergeProps, nextTick, normalizeClass, normalizeProps, normalizeStyle, onActivated, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onScopeDispose, onServerPrefetch, onUnmounted, onUpdated, openBlock, popScopeId, provide, proxyRefs, pushScopeId, queuePostFlushCb, reactive, readonly, ref, registerRuntimeCompiler, render, renderList, renderSlot, resolveComponent, resolveDirective, resolveDynamicComponent, resolveFilter, resolveTransitionHooks, setBlockTracking, setDevtoolsHook, setTransitionHooks, shallowReactive, shallowReadonly, shallowRef, ssrContextKey, ssrUtils, stop, toDisplayString, toHandlerKey, toHandlers, toRaw, toRef, toRefs, transformVNodeArgs, triggerRef, unref, useAttrs, useCssModule, useCssVars, useSSRContext, useSlots, useTransitionState, vModelCheckbox, vModelDynamic, vModelRadio, vModelSelect, vModelText, vShow, version, warn, watch, watchEffect, watchPostEffect, watchSyncEffect, withAsyncContext, withCtx, withDefaults, withDirectives, withKeys, withMemo, withModifiers, withScopeId)

keep up the good work!

davestewart commented 3 years ago

Interestingly, I just watched this and Evan You seems to think that Pinia will be the go to with Vue 3, which makes you wonder how much future Vuex 5 will have...

https://www.youtube.com/watch?v=gpTbH469Qog

julie777 commented 3 years ago

I mentioned this further up, but if someone had time to create a simple Vue 3 / Vuex 4 repo that I could use as a starting point, or reference an existing one, that would be a great head start when I do start this.

As a quasar user, I would recommend just creating a quasar project and choosing vuex during create. It will have Vue 3 and Vuex 4. That is how I do all my setup for working on components as it gives me a fully functioning app that can be run. I then add a small amount of code for dev purposes.

iKnowMagic commented 3 years ago

Could you please try https://github.com/sapphi-red/vite-boilerplate-plus - I would recommend Vite + Typescript + Vue 3 to make any library/app future-proof. The above-mentioned link contains a starter template with Vuex and ESLint, in addition to Vite + Typescript + Vue 3 (the default Vite template does not come with Vuex nor ESLint). In addition to Vite + Typescript + Vuex + Vue 3 + ESLint, it would be nice if the template supported Jest out-of-the-box. Alas, the above-mentioned template does not come with Jest. Other templates could be found at https://github.com/vitejs/awesome-vite - regrettably, I could not find a template in the latter link with the aforementioned requirements.

iKnowMagic commented 3 years ago

Interestingly, I just watched this and Evan You seems to think that Pinia will be the go to with Vue 3, which makes you wonder how much future Vuex 5 will have...

https://www.youtube.com/watch?v=gpTbH469Qog

Pinia comes with read-only and writable state mappers that would seemingly render vuex-pathify obsolete. However, vuex-pathify / Vue 3 could begin with support for Vuex 4 and offer the same syntax for Vuex 5 or Pinia, making it an attractive addition to both the current Vuex 4 and some future Vuex 5 or Pinia - just a thought :)

davestewart commented 3 years ago

@iKnowMagic yeah, I think providing support for Vue 3 / vuex 4 is a must.

I guess I don't know enough about Pinia to comment yet, but I think you're suggesting Pathify would supply a common wrapper / adapter syntax for both Vuex and Pinia?

I'm not sure how this would work with types, which of course is the way everything is going... do you know yourself?

julie777 commented 3 years ago

I did some reading about pinia. It seems as if I had two vuex pathify stores and access variables using pathify at "store1/variable1" and "store2/variable2" then with pinia I would use

const store1 = useStore1()
val = store2.variable1

and that would eliminate the need for pathify. It would if everything was only a single layer deep. with pathify I can use "store/x/y/z/q" as my path. Is that also possible with pinia? (forgive my lack of knowledge about pinia. Does pinia support store2.x.y.z = 54?

Also, I don't put logic in my store. My logic is separated in other ways, so I only use get and set which pathify makes trivial.

iKnowMagic commented 3 years ago

I did some reading about pinia. It seems as if I had two vuex pathify stores and access variables using pathify at "store1/variable1" and "store2/variable2" then with pinia I would use

const store1 = useStore1()
val = store2.variable1

and that would eliminate the need for pathify. It would if everything was only a single layer deep. with pathify I can use "store/x/y/z/q" as my path. Is that also possible with pinia? (forgive my lack of knowledge about pinia. Does pinia support store2.x.y.z = 54?

Also, I don't put logic in my store. My logic is separated in other ways, so I only use get and set which pathify makes trivial.

Vuex-pathify is still very useful because:

  1. Vuex 4 is the most used store in Vue.
  2. Pinia is supported by one person while Vuex has a team behind it. Moreover, Vuex goes through a more rigorous testing and development phase where many heads decide what is best for Vuex/Vue.
  3. Pinia is reflecting some of the features that Vuex 5 may have and vuex-pathify could make it easier to transition from Vuex 4 to Vuex 5 by providing the same syntax underneath.

@davestewart it would be amazing if Vuex 5 adopted the power of vuex-pathify syntax, merging vuex-pathify and Vuex 5 into a single product.

@julie777 as to what Pinia's syntax looks like it may be best to check out it's documentation; just my five cent :)

davestewart commented 2 years ago

Update:

davestewart commented 2 years ago

Good news everyone! It looks like I've got it all working – at least with a basic store:

image

Next steps:

Later steps:

If you want to help spread the good news, I made a small announcement on Twitter.

vesper8 commented 2 years ago

@davestewart this looks great!

Question, will the Vue3 version of vuex-pathify support both Vuex 4.0 and Pinia?

I know they've alluded to basically making Vuex 5 = Pinia, but this might still be a long ways away.

davestewart commented 2 years ago

Hey @vesper8 ...

I hadn't thought about it TBH.

As I understand it, Pinia is a completely separate codebase from Vuex, isn't Flux, and doesn't use strings, so not sure how you see Pathify being of any use here?

davestewart commented 2 years ago

Question, everyone.

Vue 3 now supports Options and Composition API. For computed properties, the Composition API uses computed(fn) whereas the Options API uses fn. Therefore, when requesting get or sync Pathify needs to know what to return.

I want to keep the API as simple as possible, so right now, the get and sync take an additional argument useComputed that defaults to true:

get (path, props, useComputed = true) { ... }
sync (path, props, useComputed = true) { ... }

So Pathify in Vue 3 using the Options API looks like this:

export default {
  computed: {
    message: get('message', null, false),

    ...sync([
      'greeting',
      'name'
    ], null, false),
  },
}

This feels a bit yukky to me, so I want to consider some other options:

  1. allow false to be passed in place of props (which can only be array or object): get('message', false)
  2. add additional methods: $get and $sync (and maybe $call for completeness).
  3. do nothing and let the user add any sugar themselves if they really can't stand the API
  4. something else

I'm leaning towards 3.

EDIT: also not 2, as I'm changing the store.get/set/copy methods to store.$get/$set/$copy in line with how plugin methods are normally defined.

Thoughts?

sanscheese commented 2 years ago

Awesome work!

I would think 3 too, to see how it plays out.

My hunch is as Pina becomes the go-to for what most Vue 3 apps need as their store, Vuex is then for those needing the added complexity of flux, so it's likely they'll use composition API.

How about a config option to set useComputed to false, for devs that want options API to get the first-class experience? I can see a common case of devs feeling stuck on Vue 2 from vuex/pathify (and likely on Options API) who want to be able to upgrade to Vue 3 and then shift over to PIna. This may help with a smoother upgrade?

davestewart commented 2 years ago

Hey Ben!

Thanks for your input.

Regards the config option, I think with users switching between options and composition on a case-by-case basis that could get confusing.

So I think, yeah, let it play out. Well-put!

davestewart commented 2 years ago

Vuex Pathify is now in Beta for Vue 3:

dimavolo commented 2 years ago

Vuex Pathify is now in Beta for Vue 3:

Dave that's awesome! Excited to try this out. Thanks for creating and supporting the best Vuex plugin.

davestewart commented 2 years ago

@dimavolo - aw... that's so kind of you to say! Thanks so much 😊