diff --git a/sources/@roots/bud-compiler/src/service/index.tsx b/sources/@roots/bud-compiler/src/service/index.tsx index dea9114764..6db984b83b 100644 --- a/sources/@roots/bud-compiler/src/service/index.tsx +++ b/sources/@roots/bud-compiler/src/service/index.tsx @@ -21,7 +21,6 @@ import {Error as DisplayError} from '@roots/bud-dashboard/components/error' import {Service} from '@roots/bud-framework/service' import {bind} from '@roots/bud-support/decorators/bind' import {BudError} from '@roots/bud-support/errors' -import {render} from '@roots/bud-support/ink' import isNull from '@roots/bud-support/lodash/isNull' import isNumber from '@roots/bud-support/lodash/isNumber' import isString from '@roots/bud-support/lodash/isString' @@ -31,11 +30,6 @@ import stripAnsi from '@roots/bud-support/strip-ansi' * {@link BudCompiler} implementation */ class Compiler extends Service implements BudCompiler { - /** - * {@link BudCompiler.compilationStats} - */ - public declare compilationStats: BudCompiler[`compilationStats`] - /** * {@link BudCompiler.config} */ @@ -73,9 +67,11 @@ class Compiler extends Service implements BudCompiler { }) if (`isBudError` in error) { - render() + this.app.context.render() } else { - render() + this.app.context.render( + , + ) } } /** @@ -88,26 +84,21 @@ class Compiler extends Service implements BudCompiler { ? `${this.app.label} (${child.name})` : child.name - this.stats = stats - - this.compilationStats = stats.toJson(statsOptions) - - this.app.dashboard.updateStats(this.compilationStats) + this.stats = stats.toJson(statsOptions) + this.app.context.render(this.app.dashboard.render(stats)) if (stats.hasErrors()) { process.exitCode = 1 - this.compilationStats.children = this.compilationStats.children?.map( - child => ({ - ...child, - errors: - child.errors && this.sourceErrors - ? this.sourceErrors(child.errors) - : child.errors ?? [], - }), - ) + this.stats.children = this.stats.children?.map(child => ({ + ...child, + errors: + child.errors && this.sourceErrors + ? this.sourceErrors(child.errors) + : child.errors ?? [], + })) - this.compilationStats.children + this.stats.children ?.filter( child => isNumber(child.errorsCount) && child.errorsCount > 0, ) @@ -131,7 +122,7 @@ class Compiler extends Service implements BudCompiler { }) } - this.compilationStats.children + this.stats.children ?.filter(child => child.errorsCount === 0) .forEach(child => { try { @@ -146,6 +137,7 @@ class Compiler extends Service implements BudCompiler { }) this.app.server?.publicUrl.href && + this.app.context.browser && this.app.notifier.openBrowser(this.app.server?.publicUrl.href) } catch (error) { this.logger.error(error) @@ -224,8 +216,8 @@ class Compiler extends Service implements BudCompiler { * In a perfect world webpack plugins would use the * `nameForCondition` property to identify the module. */ - if (ident && this.compilationStats?.children) { - module = this.compilationStats.children + if (ident && this.stats?.children) { + module = this.stats.children .flatMap(child => child?.modules) .find(module => [module?.id, module?.name].includes(ident)) } diff --git a/sources/@roots/bud-dashboard/src/application.tsx b/sources/@roots/bud-dashboard/src/application.tsx index d5da66f752..5f6b316f7a 100644 --- a/sources/@roots/bud-dashboard/src/application.tsx +++ b/sources/@roots/bud-dashboard/src/application.tsx @@ -4,6 +4,7 @@ import type {StatsCompilation} from '@roots/bud-framework/config' import {exit} from 'node:process' import {Error} from '@roots/bud-dashboard/components/error' +import Footer from '@roots/bud-dashboard/components/footer' import Compilation from '@roots/bud-dashboard/views/compilation' import Debug from '@roots/bud-dashboard/views/debug' import Server from '@roots/bud-dashboard/views/server' @@ -16,11 +17,11 @@ import { useState, useStdout, } from '@roots/bud-support/ink' +import escapes from '@roots/bud-support/ansi-escapes' export interface Props { basedir?: string - close?: (callback: (error?: Error | null) => any) => void - closed?: boolean + close?: (callback: (error?: Error | null) => any) => any compact?: boolean compilations?: Array> debug?: boolean @@ -32,11 +33,12 @@ export interface Props { errors?: StatsCompilation[`errors`] isolated?: number mode: Bud['mode'] + notifier?: Bud[`notifier`] proxy?: boolean proxyUrl?: URL publicDevUrl?: URL publicProxyUrl?: URL - status?: false | string + displayHelp?: boolean warnings?: StatsCompilation[`warnings`] } @@ -56,7 +58,7 @@ export const Application = ({ proxyUrl, publicDevUrl, publicProxyUrl, - status, + displayHelp, }: Props) => { const {stdout} = useStdout() @@ -96,6 +98,7 @@ export const Application = ({ return ( <> {error && } + {compilations.map((compilation, id) => ( ) => { - const app = useApp() + const onExit = useOnExit() + const stdout = useStdout() + const [compact, setCompact] = useState(props.compact) + const [debug, setDisplayDebug] = useState(props.debug) + const [displayAssets, setDisplayAssets] = useState(props.displayAssets) + const [displayEntrypoints, setDisplayEntrypoints] = useState(true) const [displayServerInfo, setDisplayServerInfo] = useState( props.displayServerInfo, ) - const [debug, setDisplayDebug] = useState(props.debug) - const [displayEntrypoints, setDisplayEntrypoints] = useState(true) - const [displayAssets, setDisplayAssets] = useState(props.displayAssets) - const [closed, setClosed] = useState(false) - const [compact, setCompact] = useState(props.compact) + const [help, setHelp] = useState(false) const [isolated, setIsolated] = useState(0) useInput((key, input) => { @@ -184,54 +189,80 @@ export const TeletypeApplication = ({ case `a`: setDisplayAssets(!displayAssets) break - case `e`: - setDisplayEntrypoints(!displayEntrypoints) + + case `b`: + if (notifier?.openBrowser && props.devUrl) { + notifier.openBrowser(props.devUrl?.toString()) + notifier.browserOpened = false + } break + + case `c`: + setCompact(!compact) + break + case `d`: setDisplayDebug(!debug) break + + case `e`: + setDisplayEntrypoints(!displayEntrypoints) + break + + case `h`: + setHelp(!help) + break + + case `q`: + onExit() + break + + case `r`: + stdout.write(escapes.clearTerminal) + break + case `s`: setDisplayServerInfo(!displayServerInfo) break - case `c`: - setCompact(!compact) - break + case `0`: setIsolated(0) break - default: - break } new Array(9).fill(0).forEach((_, i) => { if (!props.compilations) return + key === `${i + 1}` && isolated !== i + 1 && setIsolated(Math.min(i + 1, props.compilations.length)) }) - if (input.escape) { - setClosed(true) - if (close) - close((error?) => { - if (error) app.exit(error) - else app.exit() - - exit(error ? 1 : 0) - }) - } + if (input.escape) onExit() }) return ( - + <> + +