diff --git a/packages/gatsby-cli/src/reporter/reporters/ink/components/develop.js b/packages/gatsby-cli/src/reporter/reporters/ink/components/develop.js index b8366eb384699..7f37b6b50c684 100644 --- a/packages/gatsby-cli/src/reporter/reporters/ink/components/develop.js +++ b/packages/gatsby-cli/src/reporter/reporters/ink/components/develop.js @@ -1,46 +1,7 @@ -import React, { useContext, useState, useEffect, useRef } from "react" +import React, { Component } from "react" import { Box, Color, StdoutContext } from "ink" import fetch from "node-fetch" -// Handy hook from https://overreacted.io/making-setinterval-declarative-with-react-hooks/ -function useInterval(callback, delay) { - const savedCallback = useRef() - - // Remember the latest callback. - useEffect(() => { - savedCallback.current = callback - }, [callback]) - - // Set up the interval. - useEffect(() => { - function tick() { - savedCallback.current() - } - if (delay !== null) { - let id = setInterval(tick, delay) - return () => clearInterval(id) - } - - return null - }, [delay]) -} - -// Track the width and height of the terminal. Responsive app design baby! -const useTerminalResize = () => { - const { stdout } = useContext(StdoutContext) - const [sizes, setSizes] = useState([stdout.columns, stdout.rows]) - useEffect(() => { - stdout.on(`resize`, () => { - setSizes([stdout.columns, stdout.rows]) - }) - return () => { - stdout.off(`resize`) - } - }, [stdout]) - - return sizes -} - // Query the site's graphql instance for the latest count. const fetchPageQueryCount = url => fetch(`${url}___graphql`, { @@ -57,33 +18,69 @@ const fetchPageQueryCount = url => .then(res => res.json()) .then(json => json.data.allSitePage.totalCount) -const Develop = props => { - const [pagesCount, setPagesCount] = useState(0) +class Develop extends Component { + state = { + pagesCount: 0, + sizes: [this.props.stdout.columns, this.props.stdout.rows], + } + timer = null - fetchPageQueryCount(props.stage.context.url).then(count => - setPagesCount(count) - ) - // Query for latest page count every second. - // Built-in subscriptions would be nice. - useInterval(() => { - // POST to get pages count. - fetchPageQueryCount(props.stage.context.url).then(count => - setPagesCount(count) + fetchPageCount() { + fetchPageQueryCount(this.props.stage.context.url).then(pagesCount => + this.setState({ pagesCount }) ) - }, 1000) - const [width] = useTerminalResize() + this.timer = setTimeout(this.fetchPageCount.bind(this), 1000) + } + + componentDidMount() { + this.fetchPageCount() + + const { stdout } = this.props + stdout.on(`resize`, () => { + this.setState({ + sizes: [stdout.columns, stdout.rows], + }) + }) + } + + componentWillUpdate(nextProps) { + if (this.props.stdout !== nextProps.stdout) { + this.props.stdout.off(`resize`) - return ( - - {`—`.repeat(width)} - - {pagesCount} pages - - {props.stage.context.appName} + const { stdout } = nextProps + stdout.on(`resize`, () => { + this.setState({ + sizes: [stdout.columns, stdout.rows], + }) + }) + } + } + + componentWillUnmount() { + this.props.stdout.off(`resize`) + + if (this.timer) { + clearTimeout(this.timer) + } + } + + render() { + return ( + + {`—`.repeat(this.state.sizes[0])} + + {this.state.pagesCount} pages + + {this.props.stage.context.appName} + - - ) + ) + } } -export default Develop +export default props => ( + + {({ stdout }) => } + +) diff --git a/packages/gatsby-cli/src/reporter/reporters/ink/reporter.js b/packages/gatsby-cli/src/reporter/reporters/ink/reporter.js index 37feea92f9ec1..a1e3356c31db3 100644 --- a/packages/gatsby-cli/src/reporter/reporters/ink/reporter.js +++ b/packages/gatsby-cli/src/reporter/reporters/ink/reporter.js @@ -1,6 +1,7 @@ import React from "react" import { Static, Box } from "ink" import chalk from "chalk" +import { trackBuildError } from "gatsby-telemetry" import Spinner from "./components/spinner" import ProgressBar from "./components/progress-bar" import Develop from "./components/develop" @@ -126,8 +127,39 @@ export default class GatsbyReporter extends React.Component { this._addMessage(`verbose`, str) } + static getDerivedStateFromError(error) { + return { hasError: true, error: error.name } + } + + componentDidCatch(error, info) { + trackBuildError(`INK`, { + error: { + message: error.name, + stack: info.componentStack, + }, + }) + } + render() { - const { activities, messages, disableColors, stage } = this.state + const { + activities, + messages, + disableColors, + stage, + hasError, + error, + } = this.state + + if (hasError) { + // You can render any custom fallback UI + return ( + + + We've encountered an error: {error} + + + ) + } const spinners = [] const progressBars = []