Skip to content

Instantly share code, notes, and snippets.

@bajzarpa
Created April 25, 2022 12:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bajzarpa/f6b4eb57390fc7507a58881f709500c4 to your computer and use it in GitHub Desktop.
Save bajzarpa/f6b4eb57390fc7507a58881f709500c4 to your computer and use it in GitHub Desktop.
Vue.js plugin to use VueX 3 with old VueX
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