UNPKG

@sigi/ssr

Version:

Server side rendering support for sigi framework

130 lines 5.02 kB
import { TERMINATE_ACTION_TYPE_SYMBOL, getSSREffectMeta, RETRY_ACTION_TYPE_SYMBOL } from '@sigi/core'; import { rootInjector } from '@sigi/di'; import { StateToPersist } from './state-to-persist'; export const SKIP_SYMBOL = Symbol('skip-symbol'); export const runSSREffects = (ctx, modules, config = {}) => { const stateToSerialize = {}; const actionsToRetry = {}; const { providers, timeout = 1 } = config; const injector = rootInjector.createChild([...modules, ...(providers !== null && providers !== void 0 ? providers : [])]); const cleanupFns = []; let timer; let terminatedCount = 0; let effectsCount = 0; const moduleInstanceCache = new Map(); injector.serverCache = moduleInstanceCache; const pendingState = new Promise((resolve, reject) => { if (!modules.length) { return resolve(); } timer = setTimeout(() => { reject(new Error('Terminate timeout')); }, timeout * 1000); for (const constructor of modules) { let isAllSkipped = true; const ssrActionsMeta = getSSREffectMeta(constructor.prototype, []); const effectModuleInstance = injector.getInstance(constructor); moduleInstanceCache.set(constructor, effectModuleInstance); const { store, moduleName } = effectModuleInstance; effectsCount += ssrActionsMeta.length; const subscription = store.action$.subscribe({ next: ({ type, payload }) => { isAllSkipped = false; if (type === RETRY_ACTION_TYPE_SYMBOL) { const { name } = payload; if (!actionsToRetry[moduleName]) { actionsToRetry[moduleName] = [name]; } else { actionsToRetry[moduleName].push(name); } } if (type === TERMINATE_ACTION_TYPE_SYMBOL) { terminatedCount++; } if (terminatedCount === effectsCount) { resolve(); } }, error: (e) => { reject(e); }, }); for (const ssrActionMeta of ssrActionsMeta) { if (ssrActionMeta.payloadGetter) { let maybeDeferredPayload; try { maybeDeferredPayload = ssrActionMeta.payloadGetter(ctx, SKIP_SYMBOL); } catch (e) { return reject(e); } Promise.resolve(maybeDeferredPayload) .then((payload) => { if (payload !== SKIP_SYMBOL) { isAllSkipped = false; store.dispatch({ type: ssrActionMeta.action, payload, store, }); } else { if (!actionsToRetry[moduleName]) { actionsToRetry[moduleName] = [ssrActionMeta.action]; } else { actionsToRetry[moduleName].push(ssrActionMeta.action); } effectsCount--; if (terminatedCount === effectsCount) { resolve(); } } }) .catch((e) => { reject(e); }); } else { isAllSkipped = false; store.dispatch({ type: ssrActionMeta.action, payload: undefined, store, }); } } cleanupFns.push(() => { subscription.unsubscribe(); store.dispose(); !isAllSkipped && (stateToSerialize[moduleName] = store.state); }); } if (!effectsCount) { resolve(); } }) .then(() => { if (timer) { clearTimeout(timer); timer = undefined; } for (const cleanup of cleanupFns) { cleanup(); } return new StateToPersist(stateToSerialize, actionsToRetry); }) .catch((e) => { if (timer) { clearTimeout(timer); timer = undefined; } for (const cleanup of cleanupFns) { cleanup(); } throw e; }); return { injector, pendingState }; }; //# sourceMappingURL=run.js.map