Created
April 25, 2022 12:43
-
-
Save bajzarpa/f6b4eb57390fc7507a58881f709500c4 to your computer and use it in GitHub Desktop.
Vue.js plugin to use VueX 3 with old VueX
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const LegacyVuexOptionAdapter = { | |
install(Vue) { | |
Vue.mixin({ | |
beforeCreate() { | |
vuexAdapterInit.call(this, Vue); | |
}, | |
}); | |
// option merging | |
const merge = Vue.config.optionMergeStrategies.computed; | |
Vue.config.optionMergeStrategies.vuex = (toValue, fromValue) => { | |
if (!toValue) return fromValue; | |
if (!fromValue) return toValue; | |
return { | |
getters: merge(toValue.getters, fromValue.getters), | |
actions: merge(toValue.actions, fromValue.actions), | |
}; | |
}; | |
}, | |
}; | |
function vuexAdapterInit(Vue) { | |
// note: store injection is done by the official Vuex plugin | |
const options = this.$options; | |
const { vuex } = options; | |
// if no vuex option found nothing to do | |
if (!vuex) return; | |
// vuex option handling | |
if (!this.$store) { | |
// eslint-disable-next-line no-console | |
console.warn( | |
'[vuex] store not injected. make sure to ' + | |
'provide the store option in your root component.' | |
); | |
} | |
const { getters, actions } = vuex; | |
if (getters) { | |
Object.entries(getters).forEach(([key, getter]) => { | |
defineVuexGetter(this, key, getter); | |
}); | |
} | |
if (actions) { | |
const store = this.$store; | |
options.methods ??= {}; | |
Object.entries(actions).forEach(([key, action]) => { | |
options.methods[key] = makeBoundAction(store, action, key); | |
}); | |
} | |
} | |
/** | |
* Define a Vuex getter on an instance. | |
* | |
* @param {Vue} vm | |
* @param {String} key | |
* @param {Function} getter | |
*/ | |
function defineVuexGetter(vm, key, getter) { | |
if (isNotFunction(getter)) { | |
// eslint-disable-next-line no-console | |
console.warn(`[vuex] Getter bound to key 'vuex.getters.${key}' is not a function.`); | |
return; | |
} | |
Object.defineProperty(vm, key, { | |
enumerable: true, | |
configurable: true, | |
get: makeComputedGetter(vm.$store, getter), | |
set: setter, | |
}); | |
} | |
function makeComputedGetter(store, getter) { | |
const vm = store._vm; | |
const cacheId = vm._uid; | |
// cached | |
if (getter[cacheId]) return getter[cacheId]; | |
const Watcher = getWatcher(vm); | |
const Dep = getDep(vm); | |
const watcher = new Watcher(vm, (vm) => getter(vm.$data.$$state), null, { lazy: true }); | |
const computedGetter = () => { | |
if (watcher.dirty) { | |
watcher.evaluate(); | |
} | |
if (Dep.target) { | |
watcher.depend(); | |
} | |
return watcher.value; | |
}; | |
getter[cacheId] = computedGetter; | |
return computedGetter; | |
} | |
/** | |
* Setter for all getter properties. | |
*/ | |
function setter() { | |
throw new Error('vuex getter properties are read-only.'); | |
} | |
/** | |
* Make a bound-to-store version of a raw action function. | |
* | |
* @param {Store} store | |
* @param {Function} action | |
* @param {String} key | |
*/ | |
function makeBoundAction(store, action, key) { | |
if (typeof action !== 'function') { | |
// eslint-disable-next-line no-console | |
console.warn(`[vuex] Action bound to key 'vuex.actions.${key}' is not a function.`); | |
} | |
return function vuexBoundAction(...args) { | |
return action.call(this, store, ...args); | |
}; | |
} | |
/** | |
* Hacks to get access to Vue internals. | |
* Maybe we should expose these... | |
*/ | |
let Watcher; | |
function getWatcher(vm) { | |
if (!Watcher) { | |
const noop = function () {}; | |
const unwatch = vm.$watch(noop, noop); | |
Watcher = vm._watchers[0].constructor; | |
unwatch(); | |
} | |
return Watcher; | |
} | |
let Dep; | |
function getDep(vm) { | |
if (!Dep) { | |
Dep = vm._data.__ob__.dep.constructor; | |
} | |
return Dep; | |
} | |
export default LegacyVuexOptionAdapter; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment