@oarepo/vuex-preloader
Version:
Preloader library (not only) for OARepo
340 lines (276 loc) • 10.3 kB
JavaScript
/*!
* @oarepo/vuex-preloader v1.3.5
* (c) Miroslav Simek <simeki@vscht.cz>
* Released under the MIT License.
*/
import Vue from 'vue';
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function extractActionParams(preloader, match, route, extraProps) {
var actionParams = {};
if (preloader.query) {
actionParams['query'] = route.query;
}
var params = preloader.params || null;
if (params) {
Object.keys(params).forEach(function (k) {
actionParams[params[k]] = route.params[k] || extraProps[k];
});
} else {
actionParams = Object.assign({}, route.params, {}, extraProps);
}
return actionParams;
}
var registerPreloader = function registerPreloader(router, store) {
var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
injection = _ref.injection,
errorHandler = _ref.errorHandler,
debug = _ref.debug;
// a container with path segment name => jsonified store action parameters.
// if these change in navigation, a reload on store is called
var storedActionParamsContainer = [{}];
var storedInjectedParamsContainer = {}; // a path segment name => dynamic store name mapping
var isolates = {};
var lastLoaded = {};
var reloaderTimers = {};
if (!errorHandler) {
errorHandler = function errorHandler(_ref2) {
var router = _ref2.router,
route = _ref2.route,
pathSegment = _ref2.pathSegment,
exception = _ref2.exception;
console.error('Exception detected');
return false;
};
}
async function runPreloader(match, storedActionParams, actionParams, preloader, from, to) {
var injects = {};
var name = match.name;
var reload = preloader.reload || false;
var storeModule = preloader.store || '';
var expiration = preloader.expiration;
var reloadInterval = preloader.reloadInterval;
var action = preloader.action || 'load';
var isolated = preloader.isolated || '';
var key = preloader.key || [name, storeModule, action].filter(function (x) {
return !!x;
}).map(function (x) {
return x.toString();
}).join(':');
if (debug) {
console.log("preloader will use key ".concat(key, " for route segment"), match);
}
var serializedParams = JSON.stringify(actionParams);
if (debug) {
console.log('checking if reload is needed: serialized params ', serializedParams, 'stored params', storedActionParams[key], 'reload', reload);
}
var skipReloading = !reload;
if (storedActionParams[key] === undefined) {
skipReloading = false;
} else if (storedActionParams[key] !== serializedParams) {
skipReloading = false;
}
var storeState = store.state;
if (storeModule.length) {
storeState = storeState[storeModule];
}
if (storeState['reloadNeeded']) {
skipReloading = false;
}
if (expiration && lastLoaded[key] && new Date(lastLoaded[key].getTime() + expiration * 1000) < new Date()) {
skipReloading = false;
}
if (skipReloading) {
if (injection) {
if (debug) {
console.log('Injecting cache to component', injects);
}
Object.keys(storedInjectedParamsContainer[key] || {}).forEach(function (k) {
to.params[k] = storedInjectedParamsContainer[key][k];
});
}
return _defineProperty({}, key, storedActionParams[key]);
}
if (isolated) {
var storeModuleDef = await isolated({
store: store,
match: match,
route: to,
router: router
});
await Vue.nextTick();
storeModule = storeModuleDef.store;
delete storeModuleDef[store];
injects = Object.assign({}, injects, {}, storeModuleDef);
isolates[key] = storeModule;
}
async function runReload() {
injects['storeModule'] = storeModule;
var namespacedAction = storeModule ? "".concat(storeModule, "/").concat(action) : action;
if (debug) {
console.log('dispatch', namespacedAction, actionParams, 'from', from, 'to', to);
}
await store.dispatch(namespacedAction, actionParams);
lastLoaded[key] = new Date();
}
await runReload();
if (reloadInterval) {
if (reloaderTimers[key] !== undefined) {
clearInterval(reloaderTimers[key]);
}
reloaderTimers[key] = setInterval(runReload, reloadInterval * 1000);
}
if (injection) {
if (debug) {
console.log('Injecting to component', injects);
}
storedInjectedParamsContainer[key] = {};
Object.keys(injects).forEach(function (k) {
to.params[k] = injects[k];
storedInjectedParamsContainer[key][k] = injects[k];
});
}
if (debug) {
console.log("Called store ".concat(name, ", returning"), _defineProperty({}, key, serializedParams));
}
return _defineProperty({}, key, serializedParams);
}
async function beforeEachHandler(to, from, next) {
var storedActionParams = storedActionParamsContainer[0];
var newActionParams = {}; // for each route segment, check if there is a preloader and run it
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = to.matched[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var match = _step.value;
var preloaders = match.meta && match.meta.preloader;
if (preloaders === undefined) {
continue;
}
var extraProps = {};
if (match.props) {
if (match.props["default"] instanceof Function) {
extraProps = Object.assign({}, match.props["default"](to));
} else if (Object(match.props["default"]) === match.props["default"]) {
extraProps = Object.assign({}, match.props["default"]);
}
} // the ``preloaders`` are either a single object or an array. If a single object, cast it to an array
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = (Array.isArray(preloaders) ? preloaders : [preloaders])[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var preloader = _step2.value;
var actionParams = extractActionParams(preloader, match, to, Object.assign({}, preloader.props || {}, {}, extraProps));
try {
// run the preloader. It returns an object {key: actionParams} as a retval.
// Extend the new action params with the retval - this way we know which actions
// has been found on the path
Object.assign(newActionParams, (await runPreloader(match, storedActionParams, actionParams, preloader, from, to)));
} catch (e) {
// in case of error run the error handler and call its next
console.error(e);
var res = errorHandler(router, to, match, e) || false;
if (res !== true) {
next(res);
return;
}
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) {
_iterator2["return"]();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator["return"] != null) {
_iterator["return"]();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
if (debug) {
console.log('about tpo remove isolates and timers, current action params', newActionParams);
} // clean up isolates that are no more used in path segments
Object.keys(isolates).forEach(function (key) {
if (newActionParams[key] === undefined) {
if (debug) {
console.log('Removing isolated store', key);
}
store.unregisterModule(isolates[key]);
delete isolates[key]; // remove stored params as the isolated store has been destroyed
if (storedActionParamsContainer[0][key] !== undefined) {
delete storedActionParamsContainer[0][key];
}
if (storedInjectedParamsContainer[key] !== undefined) {
delete storedInjectedParamsContainer[key];
}
}
}); // clean up all timers that are no more used in path segments
Object.keys(reloaderTimers).forEach(function (key) {
if (newActionParams[key] === undefined) {
if (debug) {
console.log('Removing timer', key);
}
clearInterval(reloaderTimers[key]);
delete reloaderTimers[key];
}
}); // store parameters for the next route change
storedActionParamsContainer[0] = Object.assign({}, storedActionParams, {}, newActionParams);
if (debug) {
console.log('calling next, stored action params', storedActionParamsContainer[0]);
}
next();
}
router.beforeEach(beforeEachHandler);
return {
beforeEachHandler: beforeEachHandler
};
};
var library = {
install: function install(Vue) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var store = options.store;
var router = options.router;
if (store === undefined) {
throw new Error('Pass store to @oarepo/vuex-preloader');
}
if (router === undefined) {
throw new Error('Pass router to @oarepo/vuex-preloader');
}
delete options.store;
delete options.router;
registerPreloader(router, store, options);
}
};
export default library;
export { registerPreloader };