Skip to content

Commit

Permalink
feat(gatsby): Set up Fast Refresh (#29588)
Browse files Browse the repository at this point in the history
Co-authored-by: Ward Peeters <[email protected]>
Co-authored-by: Michal Piechowiak <[email protected]>
Co-authored-by: gatsbybot <[email protected]>
  • Loading branch information
4 people authored Feb 26, 2021
1 parent e79fc6b commit e0bd955
Show file tree
Hide file tree
Showing 26 changed files with 4,935 additions and 562 deletions.
48 changes: 14 additions & 34 deletions packages/gatsby/cache-dir/error-overlay-handler.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,25 @@
const overlayPackage = require(`@pmmmwh/react-refresh-webpack-plugin/overlay`)

const ErrorOverlay = {
showCompileError: overlayPackage.showCompileError,
clearCompileError: overlayPackage.clearCompileError,
}

const errorMap = {}

function flat(arr) {
return Array.prototype.flat ? arr.flat() : [].concat(...arr)
}

const handleErrorOverlay = () => {
const errors = Object.values(errorMap)
let errorStringsToDisplay = []
let errorsToDisplay = []
if (errors.length > 0) {
errorStringsToDisplay = flat(errors)
.map(error => {
if (typeof error === `string`) {
return error
} else if (typeof error === `object`) {
const errorStrBuilder = [error.text]

if (error.filePath) {
errorStrBuilder.push(`File: ${error.filePath}`)
}

return errorStrBuilder.join(`\n\n`)
}

return null
})
.filter(Boolean)
errorsToDisplay = errors.flatMap(e => e).filter(Boolean)
}

if (errorStringsToDisplay.length > 0) {
ErrorOverlay.showCompileError(errorStringsToDisplay.join(`\n\n`))
if (errorsToDisplay.length > 0) {
window._gatsbyEvents.push([
`FAST_REFRESH`,
{
action: `SHOW_GRAPHQL_ERRORS`,
payload: errorsToDisplay,
},
])
} else {
ErrorOverlay.clearCompileError()
window._gatsbyEvents.push([
`FAST_REFRESH`,
{ action: `CLEAR_GRAPHQL_ERRORS` },
])
}
}

Expand All @@ -52,5 +34,3 @@ export const reportError = (errorID, error) => {
}
handleErrorOverlay()
}

export { errorMap }
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import * as React from "react"
import { useId } from "./use-id"
import * as keys from "../helpers/keys"
import { match } from "../helpers/match"

function ChevronIcon() {
return (
<svg
focusable="false"
preserveAspectRatio="xMidYMid meet"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
width="16"
height="16"
viewBox="0 0 16 16"
aria-hidden="true"
data-gatsby-overlay="chevron-icon"
>
<path d="M11 8L6 13 5.3 12.3 9.6 8 5.3 3.7 6 3z" />
</svg>
)
}

export function Accordion({ children, ...rest }) {
return (
<ul data-gatsby-overlay="accordion" {...rest}>
{children}
</ul>
)
}

export function AccordionItem({
children,
disabled = false,
open = false,
title = `title`,
...rest
}) {
const [isOpen, setIsOpen] = React.useState(open)
const [prevIsOpen, setPrevIsOpen] = React.useState(open)
const id = useId(`accordion-item`)

if (open !== prevIsOpen) {
setIsOpen(open)
setPrevIsOpen(open)
}

const toggleOpen = () => {
const nextValue = !isOpen
setIsOpen(nextValue)
}

// If the AccordionItem is open, and the user hits the ESC key, then close it
const onKeyDown = event => {
if (isOpen && match(event, keys.Escape)) {
setIsOpen(false)
}
}

return (
<li
data-gatsby-overlay="accordion__item"
data-accordion-active={isOpen ? `true` : `false`}
{...rest}
>
<button
data-gatsby-overlay="accordion__item__heading"
type="button"
disabled={disabled}
aria-controls={id}
aria-expanded={isOpen}
onClick={toggleOpen}
onKeyDown={onKeyDown}
>
<ChevronIcon />
<div data-gatsby-overlay="accordion__item__title">{title}</div>
</button>
<div id={id} data-gatsby-overlay="accordion__item__content">
{children}
</div>
</li>
)
}
Original file line number Diff line number Diff line change
@@ -1,44 +1,35 @@
import React from "react"
import Overlay from "./overlay"
import Anser from "anser"
import CodeFrame from "./code-frame"
import { prettifyStack } from "../utils"
import * as React from "react"
import { Overlay, Header, Body, Footer, HeaderOpenClose } from "./overlay"
import { CodeFrame } from "./code-frame"
import { prettifyStack, openInEditor } from "../utils"

const BuildError = ({ error, open, dismiss }) => {
const [file, cause, _emptyLine, ...rest] = error.split(`\n`)
const [_fullPath, _detailedError] = rest
const detailedError = Anser.ansiToJson(_detailedError, {
remove_empty: true,
json: true,
})
const lineNumberRegex = /^[0-9]*:[0-9]*$/g
const lineNumberFiltered = detailedError.filter(
d => d.content !== ` ` && d.content.match(lineNumberRegex)
)[0]?.content
const lineNumber = lineNumberFiltered.substr(
0,
lineNumberFiltered.indexOf(`:`)
)
// Error that is thrown on e.g. webpack errors and thus can't be dismissed and must be fixed
export function BuildError({ error }) {
// Incoming build error shape is like this:
// ./relative-path-to-file
// Additional information (sometimes empty line => handled in "prettifyStack" function)
// /absolute-path-to-file
// Errors/Warnings
const [file, ...rest] = error.split(`\n`)
const decoded = prettifyStack(rest)

const header = (
<>
<div data-gatsby-overlay="header__cause-file">
<p>{cause}</p>
<span>{file}</span>
</div>
<button
onClick={() => open(file, lineNumber)}
data-gatsby-overlay="header__open-in-editor"
>
Open in editor
</button>
</>
return (
<Overlay>
<Header data-gatsby-error-type="build-error">
<div data-gatsby-overlay="header__cause-file">
<h1 id="gatsby-overlay-labelledby">Failed to compile</h1>
<span>{file}</span>
</div>
<HeaderOpenClose open={() => openInEditor(file, 1)} dismiss={false} />
</Header>
<Body>
<h2>Source</h2>
<CodeFrame decoded={decoded} />
</Body>
<Footer id="gatsby-overlay-describedby">
This error occurred during the build process and can only be dismissed
by fixing the error.
</Footer>
</Overlay>
)

const body = <CodeFrame decoded={decoded} />

return <Overlay header={header} body={body} dismiss={dismiss} />
}

export default BuildError
Original file line number Diff line number Diff line change
@@ -1,28 +1,54 @@
import React from "react"
import * as React from "react"

const CodeFrame = ({ decoded }) => (
<pre data-gatsby-overlay="pre">
<code data-gatsby-overlay="pre__code">
{decoded
? decoded.map((entry, index) => (
export function CodeFrame({ decoded }) {
if (!decoded) {
return (
<pre data-gatsby-overlay="pre">
<code data-gatsby-overlay="pre__code" />
</pre>
)
}

return (
<pre data-gatsby-overlay="pre">
<code data-gatsby-overlay="pre__code">
{decoded.map((entry, index) => {
// Check if content is "Enter" and render other element that collapses
// Otherwise an empty line would be printed
if (
index === 0 &&
entry.content ===
`
`
) {
return (
<span
key={`frame-${index}`}
data-gatsby-overlay="pre__code__span__empty"
/>
)
}

const style = {
color: entry.fg ? `var(--color-${entry.fg})` : undefined,
...(entry.decoration === `bold`
? { fontWeight: 800 }
: entry.decoration === `italic`
? { fontStyle: `italic` }
: undefined),
}

return (
<span
key={`frame-${index}`}
data-gatsby-overlay="pre__code__span"
style={{
color: entry.fg ? `var(--color-${entry.fg})` : undefined,
...(entry.decoration === `bold`
? { fontWeight: 800 }
: entry.decoration === `italic`
? { fontStyle: `italic` }
: undefined),
}}
style={style}
>
{entry.content}
</span>
))
: null}
</code>
</pre>
)

export default CodeFrame
)
})}
</code>
</pre>
)
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
import React from "react"
import * as React from "react"

class ErrorBoundary extends React.Component {
state = { hasError: false }
export class ErrorBoundary extends React.Component {
state = { error: null }

componentDidCatch(error) {
this.props.onError(error)
}

componentDidMount() {
this.props.clearErrors()
}

static getDerivedStateFromError() {
return { hasError: true }
this.setState({ error })
}

render() {
return this.state.hasError ? null : this.props.children
// Without this check => possible infinite loop
return this.state.error && this.props.hasErrors ? null : this.props.children
}
}

export default ErrorBoundary
Loading

0 comments on commit e0bd955

Please sign in to comment.