I'm going to develop a plugin to add some features on Vuex. In this plugins a ideal usage is define some extra options in Vuex.Store constructor options. In present version, I have to use my plugin likes:
import Vuex from 'vuex'
import enhance from 'vuex-enhance'
const enhancedVuex = enhance(Vuex)
// In actual usage, store options and extra options combined togther
const store = enhanceVuex.Store({ ...storeOptions, ...extraOptions })
The enhace plugin will replace the old Store constructor with a wrapped new Store constructor and pre handle the extra options which I defined in store options.
If the store instance provides a method to access the original store option or a specific option on passed options such as 'extra', I can use my plugin by following the Vuex plugin development guide (read extra options and post register state, mutations, getters, actions).
Add Vuex.Store Instance methods:
or
extra or extraOptions, this methods read storeOptions.extra or storeOptions.extraOptionsOr instance paramter access:
store.originalOptions
or
store.extraOptions
You should check this PR: https://github.com/vuejs/vuex/pull/571
To extend Vuex functionalities you can use actions enhancers (This is what Vuexfire does: https://github.com/posva/vuexfire/blob/master/src/index.js#L186)
@posva It may not satisfy such a demand that adding some additional store stuff after created Store instance. According to the plugin development part of vuex doc, registered plugins can only receive the store instance as its only param, and no other ways to access the original store options which are passed to Vuex.Store. I wish the plugin can read some extra options defined in store options and then register some new store stuff accord these options.
Btw, thx for intro a nice service firebase and I'm gonna try it on some other projects.
Why don't you just pass options directly in plugin? I wonder why you need to access to the entire store options.
function somePlugin(options) {
return store => {
// ...
}
}
new Vuex.Store({
plugins: [somePlugin({ ... })]
})
@ktsn Thx for your suggestion, it sounds like a nice way, but I still wonder if it's possible to provide access to extra options when plugin take effects. This enhance plugin, will inject more interfaces on actions context and require a new shape of getters definition:
const store = new Vuex.store({
state: {
// navtive vuex state
products: [],
cart: null
},
getters: {
// native vuex getters
},
xGetters: {
products: {
getter: state => state.products
getterConfig1: 'cfg1',
getterConfig2: 'cfg2'
},
cart: {
// define getter through object shape
}
},
actions: {
// native vuex actions
},
xActions: {
// pend, success, fail are wrapped commits.
// Them will commit some inner mutations which tell users the action status
loadProducts: ({ state, rootState, commit, dispatch, getters, pend, success, fail}, payload) {
// before fetch data
pend()
// if fetch data successful
success()
// if fetch data fail
fail()
}
}
})
My plugin will read xGetter and xActions and produce some extra native state, mutations, getters, actions. In the declaration phrase, I wanna define xGetters, xActions in store options for users can easy define them and meanwhile acquire the relationship with native store stuff(in the above case, user know that xGetters.books.getter should output data mounted on native vuex state and can only output date computed through products and cart not others).
If extract xGetters and xActions into the plugin options, it seems like not much elegant and user have to know what they defined in the original store options. In another aspect, I think plugin options should be all about the plugin itself. The xGetters and xActions are things for vuex store.
@zheeeng Sorry, I may not understand you yet but your use case looks can be covered with the enhancer approach that @posva suggested? I think you don't need to define extra options if you want to enhance getters/actions/mutations. And as the enhancers are used along the native staff, their relationships would be clear enough.
const store = new Vuex.store({
getters: {
// native vuex getters
// getter enhancer
...xGetters({
products: {
getter: state => state.products
getterConfig1: 'cfg1',
getterConfig2: 'cfg2'
},
cart: {
// define getter through object shape
}
})
},
actions: {
// native vuex actions
// actions enhancer
...xActions({
// pend, success, fail are wrapped commits.
// Them will commit some inner mutations which tell users the action status
loadProducts: ({ state, rootState, commit, dispatch, getters, pend, success, fail}, payload) {
// before fetch data
pend()
// if fetch data successful
success()
// if fetch data fail
fail()
}
})
}
})
@ktsn Not simply xGetters only produce getters, xActions only produce actions. xGetters and xActions will produce corresponding native state, mutations, getters, and actions. Thus I have to recognize xGetters, xActions definitions from native getters and actions and then handle them to generate store stuff.
The enhancer input: xGetters, xActions
output: state, mutations, actions, getters, some of them will be collected in a specific plugin module.
At present, a sound way satisfying my usage is factoring Vuex to enhancedVuex. If possible, I want some new apis help to make the plugin can be registered through plugins option.
@zheeeng I see your point. In that case, I think we also need the functionality to add additional store stuff for plugins that #571 includes. Because plugins are initialized after finishing the store setup, currently.
For now, we need to wrap the Vuex store that you're doing or define options/module enhancer to do that.
I noticed one of my Vuex plugin has such demand. https://github.com/ktsn/vuex-assert
The plugin needs an additional option for each module and it has a relation with state.
Maybe, accessing store options in plugin is useful, not sure about registering additional stuffs though.
I made a similar "plugin" for my application.
I have a fairly large store, with deep nesting. The plugin supports adding watchers inside individual store modules, with a signature that resembles components watch sections, while also receiving a context object similar to actions.
This gives me freedom to create observe changes in other parts of the store, while keeping everything separated in its own modules.
I do this by creating a new section within Vuex modules:
import * as mutations from './mutations'
import * as modules from './modules'
import * as actions from './actions'
import * as watch from './watch' // my own section
import * as getters from './getters'
import state from './state'
export default {
namespaced: true,
modules,
mutations,
actions,
watch, // my own section
getters,
state
}
To achieve this, I have to encapsulate the Vuex instance to be able to parse the store definition to load the watchers. I also overload registerModule to be able to handle dynamic loading.
I have also created another one that adds a persistence flag to each submodule, allowing fine-grained persistence control.
It would be really nice to have a solid way to extend Vuex functionality; plugins work fine, but just to some extent.
@zheeeng I also wanted something like your xActions example. I ended up with:
const NamespacedActionsPlugin = function (Vue, namespace, store) {
const rootModule = store._modules.root._rawModule;
const actions = rootModule[namespace];
if (actions === undefined) {
throw new Error(`Section ${namespace} must be defined`);
}
const newModule = {
namespaced: true,
actions: actions,
};
store.registerModule(namespace, newModule);
}
That I'm using with:
const store = new Vuex.Store({
socket: {
// actions in the 'socket' submodule
someAction(context, value) {},
otherAction(context, value) {},
},
state: {},
actions: {}, // actions in the root module
});
Vue.use(Vuex);
Vue.use(NamespacedActionsPlugin, 'socket', store);
Then the socket actions can be dispatched with:
this.$store.dispatch('socket/someAction', {obj:1});
this.$store.dispatch('socket/otherAction', {obj:2});
The NamespacedActionsPlugin is very clean and simple and can be adapted for mutations or state for example. In my opinion, it avoid the unecesssary nesting required to use "submodule plugins" like the "socket" one.
@nolde would be really nice to be able to extend Vuex functionallity.
Closing due to inactivity. Please open another issue if we still need to discuss about this one.
Most helpful comment
I made a similar "plugin" for my application.
I have a fairly large store, with deep nesting. The plugin supports adding watchers inside individual store modules, with a signature that resembles components
watchsections, while also receiving acontextobject similar to actions.This gives me freedom to create observe changes in other parts of the store, while keeping everything separated in its own modules.
I do this by creating a new section within Vuex modules:
To achieve this, I have to encapsulate the Vuex instance to be able to parse the store definition to load the watchers. I also overload
registerModuleto be able to handle dynamic loading.I have also created another one that adds a
persistenceflag to each submodule, allowing fine-grained persistence control.It would be really nice to have a solid way to extend Vuex functionality; plugins work fine, but just to some extent.