UNPKG

vite-plugin-symfony

Version:

A Vite plugin to integrate easily Vite in your Symfony application

167 lines (150 loc) 4.58 kB
/* eslint no-console: 0 */ import readline from "node:readline"; import colors from "picocolors"; import type { RollupError } from "rollup"; export interface ResolvedServerUrls { local: string[]; network: string[]; } export type LogType = "error" | "warn" | "info"; export type LogLevel = LogType | "silent"; export interface Logger { info(msg: string, options?: LogOptions): void; warn(msg: string, options?: LogOptions): void; warnOnce(msg: string, options?: LogOptions): void; error(msg: string, options?: LogErrorOptions): void; clearScreen(type: LogType): void; hasErrorLogged(error: Error | RollupError): boolean; hasWarned: boolean; } export interface LogOptions { clear?: boolean; timestamp?: boolean; } export interface LogErrorOptions extends LogOptions { error?: Error | RollupError | null; } export const LogLevels: Record<LogLevel, number> = { silent: 0, error: 1, warn: 2, info: 3, }; let lastType: LogType | undefined; let lastMsg: string | undefined; let sameCount = 0; function clearScreen() { const repeatCount = process.stdout.rows - 2; const blank = repeatCount > 0 ? "\n".repeat(repeatCount) : ""; console.log(blank); readline.cursorTo(process.stdout, 0, 0); readline.clearScreenDown(process.stdout); } export interface LoggerOptions { prefix?: string; allowClearScreen?: boolean; customLogger?: Logger; } export function createLogger(level: LogLevel = "info", options: LoggerOptions = {}): Logger { if (options.customLogger) { return options.customLogger; } const timeFormatter = new Intl.DateTimeFormat(undefined, { hour: "numeric", minute: "numeric", second: "numeric", }); const loggedErrors = new WeakSet<Error | RollupError>(); const { prefix = "[vite]", allowClearScreen = true } = options; const thresh = LogLevels[level]; const canClearScreen = allowClearScreen && process.stdout.isTTY && !process.env.CI; const clear = canClearScreen ? clearScreen : () => {}; function output(type: LogType, msg: string, options: LogErrorOptions = {}) { if (thresh >= LogLevels[type]) { const method = type === "info" ? "log" : type; const format = () => { const tag = type === "info" ? colors.cyan(colors.bold(prefix)) : type === "warn" ? colors.yellow(colors.bold(prefix)) : colors.red(colors.bold(prefix)); if (options.timestamp) { return `${colors.dim(timeFormatter.format(new Date()))} ${tag} ${msg}`; } else { return `${tag} ${msg}`; } }; if (options.error) { loggedErrors.add(options.error); } if (canClearScreen) { if (type === lastType && msg === lastMsg) { sameCount++; clear(); console[method](format(), colors.yellow(`(x${sameCount + 1})`)); } else { sameCount = 0; lastMsg = msg; lastType = type; if (options.clear) { clear(); } console[method](format()); } } else { console[method](format()); } } } const warnedMessages = new Set<string>(); const logger: Logger = { hasWarned: false, info(msg, opts) { output("info", msg, opts); }, warn(msg, opts) { logger.hasWarned = true; output("warn", msg, opts); }, warnOnce(msg, opts) { if (warnedMessages.has(msg)) return; logger.hasWarned = true; output("warn", msg, opts); warnedMessages.add(msg); }, error(msg, opts) { logger.hasWarned = true; output("error", msg, opts); }, clearScreen(type) { if (thresh >= LogLevels[type]) { clear(); } }, hasErrorLogged(error) { return loggedErrors.has(error); }, }; return logger; } export function printServerUrls( urls: ResolvedServerUrls, optionsHost: string | boolean | undefined, info: Logger["info"], ): void { const colorUrl = (url: string) => colors.cyan(url.replace(/:(\d+)\//, (_, port) => `:${colors.bold(port)}/`)); for (const url of urls.local) { info(` ${colors.green("➜")} ${colors.bold("Local")}: ${colorUrl(url)}`); } for (const url of urls.network) { info(` ${colors.green("➜")} ${colors.bold("Network")}: ${colorUrl(url)}`); } if (urls.network.length === 0 && optionsHost === undefined) { info( colors.dim(` ${colors.green("➜")} ${colors.bold("Network")}: use `) + colors.bold("--host") + colors.dim(" to expose"), ); } }