UNPKG

vike

Version:

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

204 lines (203 loc) 8.94 kB
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; }