UNPKG

vike

Version:

The Framework *You* Control - Next.js & Nuxt alternative for unprecedented flexibility and dependability.

148 lines (147 loc) 6.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.execHook = execHook; exports.execHookGlobal = execHookGlobal; exports.execHookDirect = execHookDirect; exports.execHookDirectSingle = execHookDirectSingle; exports.execHookDirectSingleWithReturn = execHookDirectSingleWithReturn; exports.execHookDirectWithoutPageContext = execHookDirectWithoutPageContext; exports.execHookDirectSync = execHookDirectSync; exports.getPageContext = getPageContext; exports.providePageContext = providePageContext; exports.isUserHookError = isUserHookError; const assert_js_1 = require("../../utils/assert.js"); const getGlobalObject_js_1 = require("../../utils/getGlobalObject.js"); const humanizeTime_js_1 = require("../../utils/humanizeTime.js"); const isObject_js_1 = require("../../utils/isObject.js"); const getHook_js_1 = require("./getHook.js"); const preparePageContextForPublicUsage_js_1 = require("../preparePageContextForPublicUsage.js"); const globalObject = (0, getGlobalObject_js_1.getGlobalObject)('utils/execHook.ts', { userHookErrors: new WeakMap(), pageContext: null, }); async function execHook(hookName, pageContext, preparePageContextForPublicUsage) { const hooks = (0, getHook_js_1.getHookFromPageContextNew)(hookName, pageContext); return await execHookDirect(hooks, pageContext, preparePageContextForPublicUsage); } async function execHookGlobal(hookName, pageConfigGlobal, pageContext, hookArg, prepareForPublicUsage) { const hooks = (0, getHook_js_1.getHookFromPageConfigGlobalCumulative)(pageConfigGlobal, hookName); const hookArgForPublicUsage = prepareForPublicUsage(hookArg); await Promise.all(hooks.map(async (hook) => { await execHookDirectAsync(() => hook.hookFn(hookArgForPublicUsage), hook, pageContext); })); } async function execHookDirect(hooks, pageContext, preparePageContextForPublicUsage) { if (!hooks.length) return []; const pageContextForPublicUsage = preparePageContextForPublicUsage(pageContext); const hooksWithResult = await Promise.all(hooks.map(async (hook) => { const hookReturn = await execHookDirectAsync(() => hook.hookFn(pageContextForPublicUsage), hook, pageContextForPublicUsage); return { ...hook, hookReturn }; })); return hooksWithResult; } async function execHookDirectSingle(hook, pageContext, preparePageContextForPublicUsage) { const hooksWithResult = await execHookDirect([hook], pageContext, preparePageContextForPublicUsage); const { hookReturn } = hooksWithResult[0]; (0, assert_js_1.assertUsage)(hookReturn === undefined, `The ${hook.hookName}() hook defined by ${hook.hookFilePath} isn't allowed to return a value`); } async function execHookDirectSingleWithReturn(hook, pageContext, preparePageContextForPublicUsage) { const hooksWithResult = await execHookDirect([hook], pageContext, preparePageContextForPublicUsage); const { hookReturn } = hooksWithResult[0]; return { hookReturn }; } function isUserHookError(err) { if (!(0, isObject_js_1.isObject)(err)) return false; return globalObject.userHookErrors.get(err) ?? false; } async function execHookDirectWithoutPageContext(hookFnCaller, hook) { const { hookName, hookFilePath, hookTimeout } = hook; const hookReturn = await execHookDirectAsync(hookFnCaller, { hookName, hookFilePath, hookTimeout }, null); return hookReturn; } function execHookDirectAsync(hookFnCaller, hook, pageContextForPublicUsage) { const { hookName, hookFilePath, hookTimeout: { error: timeoutErr, warning: timeoutWarn }, } = hook; let resolve; let reject; const promise = new Promise((resolve_, reject_) => { resolve = (ret) => { clearTimeouts(); resolve_(ret); }; reject = (err) => { clearTimeouts(); reject_(err); }; }); const clearTimeouts = () => { if (currentTimeoutWarn) clearTimeout(currentTimeoutWarn); if (currentTimeoutErr) clearTimeout(currentTimeoutErr); }; const currentTimeoutWarn = isNotDisabled(timeoutWarn) && setTimeout(() => { (0, assert_js_1.assertWarning)(false, `The ${hookName}() hook defined by ${hookFilePath} is slow: it's taking more than ${(0, humanizeTime_js_1.humanizeTime)(timeoutWarn)} (https://vike.dev/hooksTimeout)`, { onlyOnce: false }); }, timeoutWarn); const currentTimeoutErr = isNotDisabled(timeoutErr) && setTimeout(() => { const err = (0, assert_js_1.getProjectError)(`The ${hookName}() hook defined by ${hookFilePath} timed out: it didn't finish after ${(0, humanizeTime_js_1.humanizeTime)(timeoutErr)} (https://vike.dev/hooksTimeout)`); reject(err); }, timeoutErr); (async () => { try { providePageContextInternal(pageContextForPublicUsage); const ret = await hookFnCaller(); resolve(ret); } catch (err) { if ((0, isObject_js_1.isObject)(err)) { globalObject.userHookErrors.set(err, { hookName, hookFilePath }); } reject(err); } })(); return promise; } function execHookDirectSync(hook, pageContext, preparePageContextForPublicUsage) { const pageContextForPublicUsage = preparePageContextForPublicUsage(pageContext); providePageContextInternal(pageContextForPublicUsage); const hookReturn = hook.hookFn(pageContextForPublicUsage); return { hookReturn }; } function isNotDisabled(timeout) { return !!timeout && timeout !== Infinity; } /** * Access `pageContext` object inside Vike hooks, in order to create universal hooks. * * https://vike.dev/getPageContext */ function getPageContext() { const { pageContext } = globalObject; if (!pageContext) return null; const pageContextForPublicUsage = pageContext._isProxyObject ? // providePageContext() is called on the user-land (e.g. it's called by `vike-{react,vue,solid}`) thus it's already a proxy pageContext : (0, preparePageContextForPublicUsage_js_1.preparePageContextForPublicUsage)(pageContext); return pageContextForPublicUsage; } /** * Provide `pageContext` for universal hooks. * * https://vike.dev/getPageContext */ function providePageContext(pageContext) { providePageContextInternal(pageContext); } function providePageContextInternal(pageContext) { globalObject.pageContext = pageContext; // Promise.resolve() is quicker than process.nextTick() and setImmediate() // https://stackoverflow.com/questions/67949576/process-nexttick-before-promise-resolve-then Promise.resolve().then(() => { globalObject.pageContext = null; }); }