1

I'm trying to come up with a way to render a React stack trace error message in the browser, with all the formatting and layout that React does in the terminal. As an example, below is the stack trace error that shows in terminal, and I want to output this with the same formatting to a React component

SyntaxError: unknown: Expected corresponding JSX closing tag for <Tabss> (23:0)

  21 |   <TabItem value="orange">This is an orange �</TabItem>
  22 |   <TabItem value="banana">This is a banana �</TabItem>
> 23 | </Tabs>
     | ^
  24 | <Tabs
  25 |   groupId="test"
  26 |   defaultValue="orange"
    at Object._raise (C:\Users\Me\Documents\Projects\docs\node_modules\@babel\parser\lib\index.js:790:17)
    at Object.raiseWithData (C:\Users\Me\Documents\Projects\docs\node_modules\@babel\parser\lib\index.js:783:17)
    at Object.raise (C:\Users\Me\Documents\Projects\docs\node_modules\@babel\parser\lib\index.js:777:17)
    at Object.jsxParseElementAt (C:\Users\Me\Documents\Projects\docs\node_modules\@babel\parser\lib\index.js:4721:16)

The best way I've found so far is to save the stack trace as part of a json object, do a split on the line breaks, and then output that to React via the ansi-to-react component to handle the colours.

Whilst this gets me close to the above, it removes all white space, so the arrows pointing to the error etc do not line up.

Does anyone know of a way to achieve this or a library that will enable this?

K20GH
  • 6,032
  • 20
  • 78
  • 118

1 Answers1

2

So the way I solved this was as follows:

Pass the serialized error message to React, and then deserialize it. Pass it to StackTracey and clean it. Then use ansi-to-html and dangerously set the html with the output. Then map over the items and return the message:

import Convert from 'ansi-to-html';
import StackTracey from 'stacktracey';
const convert = new Convert({
  newline: true,
  escapeXML: true,
  fg: '#000',
});

function Error({error}) {
  const e = deserializeError(error);
  const stack = new StackTracey(e).withSources().clean();
  const msg = convert.toHtml(error.message);

 return (
  <>
    <div style={{ whiteSpace: 'break-spaces' }} dangerouslySetInnerHTML={{ __html: msg }} />
  {stack.items.map((e, i) => {
    return (
      <div>{e?.beforeParse}</div>
    )
  }
  </>
)}

enter image description here

K20GH
  • 6,032
  • 20
  • 78
  • 118