vike
Version:
The Framework *You* Control - Next.js & Nuxt alternative for unprecedented flexibility and dependability.
204 lines (203 loc) • 8.94 kB
JavaScript
import '../assertEnvVite.js';
// TO-DO/eventually:
// - New hook onLog(): https://github.com/vikejs/vike/issues/1438
// - Exact same logs between prod and dev, only difference is that some log objects have:
// - `isDevLog: true`
// - `willBeLogged: false` in production
// - `showTimestamp: true`
// - Never clear screen (it's complex with little benefit)
// - Only show a one-liner init log (instead of Vite's multi-line log)
export { logVite };
export { logConfigInfo };
export { logErrorServerDev };
import { isAbortError } from '../../../shared-server-client/route/abort.js';
import { getViteConfig } from '../../../server/runtime/globalContext.js';
import { assertPageContext_logRuntime, setLogRuntimeDev, } from '../../../server/runtime/loggerRuntime.js';
import { assertIsNotProductionRuntime } from '../../../utils/assertSetup.js';
import { colorVike, colorError, colorWarning } from '../../../utils/colorsClient.js';
import { colorVite, hasGreen, hasRed, hasYellow, stripAnsi } from '../../../utils/colorsServer.js';
import { isDebugError } from '../../../utils/debug.js';
import { formatHintLog } from '../../../utils/formatHintLog.js';
import { setAssertOnBeforeErr, assert, setAssertAddAssertTagsDev } from '../../../utils/assert.js';
import { hasProp } from '../../../utils/hasProp.js';
import { isErrorWithCodeSnippet, getPrettyErrorWithCodeSnippet } from './loggerDev/errorWithCodeSnippet.js';
import { getConfigExecutionErrorIntroMsg, getConfigBuildErrorFormatted, } from './resolveVikeConfigInternal/transpileAndExecuteFile.js';
import pc from '@brillout/picocolors';
import { isUserHookError } from '../../../shared-server-client/hooks/execHook.js';
import { getViteDevServer } from '../../../server/runtime/globalContext.js';
import { logErrorServer } from '../../../server/runtime/logErrorServer.js';
import { getBetterError } from '../../../utils/getBetterError.js';
import { getRequestId_withAsyncHook } from '../../../server/runtime/asyncHook.js';
import { getRequestTag } from '../../../server/runtime/renderPageServer.js';
assertIsNotProductionRuntime();
setLogRuntimeDev(logErrorServerDev, logRuntimeInfoDev);
setAssertOnBeforeErr((err) => {
// We must directly apply vite.ssrFixStacktrace() to `assertWarning(..., { showStackTrace: true })` because warnings aren't caught by the try-catch of renderPageServer()
applyViteSourceMap(err);
});
setAssertAddAssertTagsDev(addAssertTagsDev);
// Note shown to user when Vike completely modifies the error message (which is somewhat risky)
const errorDebugNote = pc.dim(formatHintLog("Error isn't helpful? See https://vike.dev/debug#verbose-errors"));
function logRuntimeInfoDev(msg, pageContext, logType) {
assertPageContext_logRuntime(pageContext);
const tagSource = getTagSource(pageContext?._requestId);
logDev(msg, logType, tagSource, '[vike]');
}
function logConfigInfo(msg, logType) {
const tagSource = getTagSource() ?? 'config';
logDev(msg, logType, tagSource, '[vike]');
}
function logVite(msg, logType, requestId, prependViteTag) {
const tagSource = getTagSource(requestId);
logDev(msg, logType, tagSource, '[vite]', !prependViteTag);
}
function logErrorServerDev(err, pageContext, errorComesFromVite = false) {
assertPageContext_logRuntime(pageContext);
applyViteSourceMap(err);
// Skip `throw render()` / `throw redirect()`
if (isAbortError(err) && !isDebugError()) {
return;
}
const tagSource = getTagSource(pageContext?._requestId);
const logErr = (err) => {
logErrorServer(err, pageContext);
};
if (isErrorWithCodeSnippet(err)) {
// We handle transpile errors globally because wrapping viteDevServer.ssrLoadModule() wouldn't be enough: transpile errors can be thrown not only when calling viteDevServer.ssrLoadModule() but also later when loading user code with import() (since Vite lazy-transpiles import() calls)
const viteConfig = getViteConfig();
assert(viteConfig);
const errMsgFormatted = getPrettyErrorWithCodeSnippet(err, viteConfig.root);
assert(stripAnsi(errMsgFormatted).startsWith('Failed to transpile'));
const message = `${getTags(errMsgFormatted, '[vite]', tagSource, 'error')}${errMsgFormatted}\n${errorDebugNote}`;
const errBetter = getBetterError(err, { message, hideStack: true });
logErr(errBetter);
return;
}
{
const errMsgFormatted = getConfigBuildErrorFormatted(err);
if (errMsgFormatted) {
assert(stripAnsi(errMsgFormatted).startsWith('Failed to transpile'));
const message = `${getTagsError(errMsgFormatted, tagSource)}${errMsgFormatted}\n${errorDebugNote}`;
const errBetter = getBetterError(err, { message, hideStack: true });
logErr(errBetter);
return;
}
}
{
const errIntro = getConfigExecutionErrorIntroMsg(err);
if (errIntro) {
assert(stripAnsi(errIntro).startsWith('Failed to execute'));
const prepend = `${getTagsError(errIntro, tagSource)}${errIntro}\n`;
const errBetter = getBetterError(err, { message: { prepend } });
logErr(errBetter);
return;
}
}
{
const hook = isUserHookError(err);
if (hook) {
const { hookName, hookFilePath } = hook;
const errIntro = pc.red(`Following error was thrown by the ${hookName}() hook defined at ${hookFilePath}`);
const prepend = `${getTagsError(errIntro, tagSource)}${errIntro}\n`;
const errBetter = getBetterError(err, { message: { prepend } });
logErr(errBetter);
return;
}
}
if (tagSource) {
const errIntro = colorError(`[Error] ${errorComesFromVite ? 'Transpilation error' : 'An error was thrown'}:`);
const prepend = `${getTagsError(errIntro, tagSource)}${errIntro}\n`;
const errBetter = getBetterError(err, { message: { prepend } });
logErr(errBetter);
return;
}
logErr(err);
}
function logDev(msg, logType, tagSource, tagTool, doNotAddTags) {
if (!doNotAddTags) {
msg = getTags(msg, tagTool, tagSource, logType) + msg;
}
if (logType === 'info') {
console.log(msg);
return;
}
if (logType === 'warn') {
console.warn(msg);
return;
}
if (logType === 'error') {
console.error(msg);
return;
}
if (logType === 'error-resolve') {
// stderr because user will most likely want to know about error recovering
console.error(msg);
return;
}
assert(false);
}
function getTagSource(requestId = null) {
const requestIdFromStore = getRequestId_withAsyncHook();
if (requestIdFromStore !== null) {
if (requestId === null) {
requestId = requestIdFromStore;
}
else {
assert(requestId === requestIdFromStore);
}
}
if (requestId === null)
return null;
// const tagSource = requestId % 2 === 1 ? (`request-${requestId}` as const) : (`request(${requestId})` as const)
const tagSource = getRequestTag(requestId);
return tagSource;
}
function applyViteSourceMap(thing) {
if (isDebugError())
return;
if (!hasProp(thing, 'stack'))
return;
const viteDevServer = getViteDevServer();
if (!viteDevServer)
return;
// Apply Vite's source maps
viteDevServer.ssrFixStacktrace(thing);
}
function getTagsError(msg, tagSource) {
return getTags(msg, '[vike]', tagSource, 'error');
}
function getTags(msg, tagTool, tagSource, logType) {
const tagToolColored = (() => {
if (logType === 'error' && !hasRed(msg))
return colorError(tagTool);
if (logType === 'error-resolve' && !hasGreen(msg))
return pc.bold(pc.green(tagTool));
if (logType === 'warn' && !hasYellow(msg))
return colorWarning(tagTool);
if (tagTool === '[vite]')
return colorVite(tagTool);
if (tagTool === '[vike]')
return colorVike(tagTool);
assert(false);
})();
const timestamp = getTagTimestamp();
const whitespace = (/\s|\[/.test(stripAnsi(msg)[0]) ? '' : ' ');
const tagSourceOuter = getTagSourceOuter(tagSource);
const tags = `${timestamp} ${tagToolColored}${tagSourceOuter}${whitespace}`;
return tags;
}
function getTagTimestamp() {
const timestamp = pc.dim(new Date().toLocaleTimeString());
return timestamp;
}
function getTagSourceOuter(tagSource) {
const tagSourceOuter = (!tagSource ? '' : pc.dim(`[${tagSource}]`));
return tagSourceOuter;
}
function addAssertTagsDev(tagVike, tagType) {
const timestamp = getTagTimestamp();
const tagSource = getTagSource();
const tagSourceOuter = getTagSourceOuter(tagSource);
const tagsDev = `${timestamp} ${tagVike}${tagSourceOuter}${tagType}`;
return tagsDev;
}