vike
Version:
The Framework *You* Control - Next.js & Nuxt alternative for unprecedented flexibility and dependability.
148 lines (147 loc) • 6.75 kB
JavaScript
;
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;
});
}