Как сделать так, чтобы React Create App Production Граница границы отображалась в исходном коде

Я использую компонент границы ошибок, чтобы ловить реагировать на ошибки, и он работает нормально.

Моя проблема в том, что в производственном приложении ведение журнала является бесполезным, поскольку стек компонентов выглядит следующим образом:

\n    in t\n    in t\n   in t\n    in t\n    in t\n    in div\n    in t\n    in u\n    in n\n    in t\n    in t

В то время как в среде разработки стек компонентов более удобен:

in ErrorPage (created by Route)\n    in Route (at Routes.js:60)\n    in Switch (at Routes.js:46)\n    in Router (created by BrowserRouter)\n    in BrowserRouter (at Routes.js:45)\n    in div (at Routes.js:43)\n    in ThemeProvider (at theme.js:1262)\n    in Theme (at Routes.js:42)\n    in Provider (at Routes.js:41)\n    in ErrorBoundary (at Routes.js:40)\n    in Routes (at index.js:12)

То же самое происходит с сообщением. В производство мы получаем:

t.value (http://localhost:3333/static/js/main.5a3e606e.js:1:680858

Пока в dev:

Uncaught TypeError: Person is not a constructor
at ErrorPage._this.click2 (ErrorPage.js:12)

Есть ли способ заставить реагировать на ошибки отображаться в исходном коде и сделать журналирование действительно полезным в производстве?

ОБНОВЛЕНИЕ: я использую библиотеку под названием http://js.jsnlog.com/ которая обрабатывает журналы и фактически перехватывает все (даже обработчики событий). Вот так выглядит компонент Boundary https://pastebin.com/aBFtD7DB. Проблема не в том, чтобы поймать ошибки, а в том, что на производстве они бесполезны.

2 ответа

Решение

Я нашел решение этой проблемы с помощью библиотеки https://www.stacktracejs.com/.

Метод StackTrace.report() будет извлекать карту и получать необходимую вам унифицированную информацию!

Так что теперь моя React Boundary выглядит следующим образом. Я все еще использую window.onerror, чтобы убедиться, что я все поймаю.

Во-первых, не забудьте добавить stacktrace-gps а также stacktrace-js в ваш package.json

import React, { Component } from "react";
import StackTrace from "stacktrace-js";

window.onerror = function(msg, file, line, col, error) {
  StackTrace.fromError(error).then(err => {
    StackTrace.report(
      err,
      `//${window.location.hostname}:${process.env.REACT_APP_LOGGER_PORT || 3334}/jsnlog.logger`,
      {
        type: "window.onerror",
        url: window.location.href,
        userId: window.userId,
        agent: window.navigator.userAgent,
        date: new Date(),
        msg: msg
      }
    );
  });
};

class ErrorBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
  }

  componentDidCatch(error, errorInfo) {
    this.setState({ error });
    StackTrace.fromError(error).then(err => {
      StackTrace.report(
        err,
        `//${window.location.hostname}:${process.env.REACT_APP_LOGGER_PORT || 3334}/jsnlog.logger`,
        {
          type: "React boundary",
          url: window.location.href,
          userId: window.userId,
          agent: window.navigator.userAgent,
          date: new Date(),
          msg: error.toString()
        }
      );
    });
  }

  render() {
    if (this.state.error) {
      //render fallback UI
      return (
        <div className="snap text-center">
          <p>We're sorry — something's gone wrong.</p>
          <p>Our team has been notified</p>
        </div>
      );
    } else {
      //when there's not an error, render children untouched
      return this.props.children;
    }
  }
}

export default ErrorBoundary;

Во-первых, важно создать исходную карту. Я сделал это, добавив devtools в конфигурацию webpack для создания исходной карты. Краткий фрагмент этого выглядит следующим образом:

devtools: "source-map",
new UglifyJsPlugin({
  sourceMap: true
})

После создания исходных карт я использовал библиотеку https://www.stacktracejs.com/.

Однако, чтобы уменьшить размер пакета на производстве, я не импортировал весь пакет stacktrace. Я реализовал разделение кода на стороне клиента и на стороне сервера.

Клиентская сторона: я импортировал парсер ошибок. Это создает объект, который содержит имя файла, номер строки, номер столбца и имя функции. Я отправляю объект, созданный с помощью этого на сервер.

import ErrorStackParser from "error-stack-parser";

componentDidCatch(error) {
   let params = {stackframes: ErrorStackParser.parse(error)};
   let url = 'https://example.com';
   axios.post(url, params)
}

На стороне сервера я импортировал "stacktrace-gps" и "stackframe" и использовал их, чтобы найти их, чтобы получить номер строки и столбец фактического кода из исходной карты.

const StackTraceGPS = require("stacktrace-gps");
const request = require("request");

var logger = function(req, res) {
  let stackframes = req.body.stackframes;
  let stackframe = new StackFrame(
    stackframes[0]
  ); /* Getting stack of the topmost element as it contains the most important information */

  /* We send extra ajax function to fetch source maps from url */
  const gps = new StackTraceGPS({
    ajax: url => {
      return new Promise((resolve, reject) => {
        request(
          {
            url,
            method: "get"
          },
          (error, response) => {
            if (error) {
              reject(error);
            } else {
              resolve(response.body);
            }
          }
        );
      });
    }
  });

  gps.pinpoint(stackframe).then(
    info => {
      console.log(info); /* Actual file Info*/
    },
    err => {
      console.log(err);
    }
  );
};

Это уменьшает размер пакета и дает возможность регистрировать ошибки на стороне сервера.

Другие вопросы по тегам