This commit is contained in:
Sean Yesmunt 2020-02-04 14:37:17 -05:00
parent 8773c95bf2
commit 4091aca554
10 changed files with 230 additions and 75 deletions

4
.sentryclirc Normal file
View file

@ -0,0 +1,4 @@
[defaults]
url = https://sentry.io/
org = lbry
project = react

View file

@ -4,11 +4,52 @@ const merge = require('webpack-merge');
const baseConfig = require('../webpack.base.config.js');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { DefinePlugin, ProvidePlugin } = require('webpack');
const SentryWebpackPlugin = require('@sentry/webpack-plugin');
const STATIC_ROOT = path.resolve(__dirname, '../static/');
const UI_ROOT = path.resolve(__dirname, '../ui/');
const DIST_ROOT = path.resolve(__dirname, 'dist/');
const WEB_PLATFORM_ROOT = __dirname;
const hasSentryToken = process.env.SENTRY_AUTH_TOKEN !== undefined;
let plugins = [
new CopyWebpackPlugin([
{
from: `${STATIC_ROOT}/index-web.html`,
to: `${DIST_ROOT}/index.html`,
},
{
from: `${STATIC_ROOT}/img/favicon.png`,
to: `${DIST_ROOT}/public/favicon.png`,
},
{
from: `${STATIC_ROOT}/img/v1-og.png`,
to: `${DIST_ROOT}/public/v1-og.png`,
},
{
from: `${STATIC_ROOT}/font/`,
to: `${DIST_ROOT}/public/font/`,
},
]),
new DefinePlugin({
IS_WEB: JSON.stringify(true),
'process.env.SDK_API_URL': JSON.stringify(process.env.SDK_API_URL || LBRY_TV_API),
}),
new ProvidePlugin({
__: ['i18n.js', '__'],
}),
];
if (hasSentryToken) {
plugins.push(
new SentryWebpackPlugin({
include: './dist',
ignoreFile: '.sentrycliignore',
ignore: ['node_modules', 'webpack.config.js'],
configFile: 'sentry.properties',
})
);
}
const webConfig = {
target: 'web',
@ -17,7 +58,7 @@ const webConfig = {
},
output: {
filename: '[name].js',
path: __dirname + '/dist/public/',
path: path.join(__dirname, 'dist/public/'),
publicPath: '/public/',
},
devServer: {
@ -55,33 +96,7 @@ const webConfig = {
fs: `${WEB_PLATFORM_ROOT}/stubs/fs.js`,
},
},
plugins: [
new CopyWebpackPlugin([
{
from: `${STATIC_ROOT}/index-web.html`,
to: `${DIST_ROOT}/index.html`,
},
{
from: `${STATIC_ROOT}/img/favicon.png`,
to: `${DIST_ROOT}/public/favicon.png`,
},
{
from: `${STATIC_ROOT}/img/v1-og.png`,
to: `${DIST_ROOT}/public/v1-og.png`,
},
{
from: `${STATIC_ROOT}/font/`,
to: `${DIST_ROOT}/public/font/`,
},
]),
new DefinePlugin({
IS_WEB: JSON.stringify(true),
'process.env.SDK_API_URL': JSON.stringify(process.env.SDK_API_URL || LBRY_TV_API),
}),
new ProvidePlugin({
__: ['i18n.js', '__'],
}),
],
plugins,
};
module.exports = merge(baseConfig, webConfig);

View file

@ -72,6 +72,8 @@
"@reach/menu-button": "^0.1.18",
"@reach/rect": "^0.2.1",
"@reach/tabs": "^0.1.5",
"@sentry/browser": "^5.12.1",
"@sentry/webpack-plugin": "^1.10.0",
"@types/three": "^0.93.1",
"adm-zip": "^0.4.13",
"async-exit-hook": "^2.0.1",

View file

@ -1,6 +1,7 @@
// @flow
import { Lbryio } from 'lbryinc';
import ReactGA from 'react-ga';
import * as Sentry from '@sentry/browser';
import { history } from './store';
// @if TARGET='app'
import Native from 'native';
@ -21,7 +22,7 @@ ElectronCookies.enable({
// @endif
type Analytics = {
error: string => void,
error: ({}, {}) => Promise<any>,
pageView: string => void,
setUser: Object => void,
toggle: (boolean, ?boolean) => void,
@ -48,10 +49,18 @@ type LogPublishParams = {
let analyticsEnabled: boolean = isProduction;
const analytics: Analytics = {
error: message => {
if (analyticsEnabled && isProduction) {
Lbryio.call('event', 'desktop_error', { error_message: message });
}
error: (error, errorInfo) => {
return new Promise(resolve => {
if (analyticsEnabled && isProduction) {
Sentry.withScope(scope => {
scope.setExtras(errorInfo);
const eventId = Sentry.captureException(error);
resolve(eventId);
});
} else {
resolve(null);
}
});
},
pageView: path => {
if (analyticsEnabled) {

View file

@ -4,8 +4,6 @@ import React from 'react';
import Yrbl from 'component/yrbl';
import Button from 'component/button';
import { withRouter } from 'react-router';
import Native from 'native';
import { Lbry } from 'lbry-redux';
import analytics from 'analytics';
import I18nMessage from 'component/i18nMessage';
@ -18,12 +16,13 @@ type Props = {
type State = {
hasError: boolean,
eventId: ?string,
};
class ErrorBoundary extends React.Component<Props, State> {
constructor() {
super();
this.state = { hasError: false };
this.state = { hasError: false, eventId: undefined };
(this: any).refresh = this.refresh.bind(this);
}
@ -32,38 +31,24 @@ class ErrorBoundary extends React.Component<Props, State> {
return { hasError: true };
}
componentDidCatch(error: { stack: string }) {
let errorMessage = 'Uncaught error\n';
// @if TARGET='web'
errorMessage += 'lbry.tv\n';
errorMessage += `page: ${window.location.pathname + window.location.search}\n`;
errorMessage += error.stack;
analytics.error(errorMessage);
// @endif
// @if TARGET='app'
Native.getAppVersionInfo().then(({ localVersion }) => {
Lbry.version().then(({ lbrynet_version: sdkVersion }) => {
errorMessage += `app version: ${localVersion}\n`;
errorMessage += `sdk version: ${sdkVersion}\n`;
errorMessage += `page: ${window.location.href.split('.html')[1]}\n`;
errorMessage += `${error.stack}`;
analytics.error(errorMessage);
});
componentDidCatch(error, errorInfo) {
analytics.error(error, errorInfo).then(eventId => {
this.setState({ eventId });
});
// @endif
}
refresh() {
const { history } = this.props;
// use history.replace instead of history.push so the user can't click back to the errored page
history.replace('');
this.setState({ hasError: false });
}
render() {
if (this.state.hasError) {
const { hasError, eventId } = this.state;
if (hasError) {
return (
<div className="main main--empty">
<Yrbl
@ -82,11 +67,23 @@ class ErrorBoundary extends React.Component<Props, State> {
),
}}
>
There was an error. It's been reported and will be fixed. Try %refreshing_the_app_link% to fix it. If
that doesn't work, try pressing Ctrl+R/Cmd+R.
There was an error. Try %refreshing_the_app_link% to fix it. If that doesn't work, try pressing
Ctrl+R/Cmd+R.
</I18nMessage>
}
/>
{eventId === null && (
<div className="error-wrapper">
<span className="error-text">
{__('You are not currently sharing diagnostic data so this error was not reported.')}
</span>
</div>
)}
{eventId && (
<div className="error-wrapper">
<span className="error-text">{__('Error ID: %eventId%', { eventId })}</span>
</div>
)}
</div>
);
}

View file

@ -1,5 +1,5 @@
import 'babel-polyfill';
import * as Sentry from '@sentry/browser';
import ErrorBoundary from 'component/errorBoundary';
import App from 'component/app';
import SnackBar from 'component/snackBar';
@ -43,6 +43,14 @@ import 'scss/all.scss';
// These overrides can't live in lbrytv/ because they need to use the same instance of `Lbry`
import apiPublishCallViaWeb from 'lbrytv/setup/publish';
// Sentry error logging setup
// Will only work if you have a SENTRY_AUTH_TOKEN env
// We still add code in analytics.js to send the error to sentry manually
// If it's caught by componentDidCatch in component/errorBoundary, it will not bubble up to this error reporter
if (process.env.NODE_ENV === 'production') {
Sentry.init({ dsn: 'https://f93af3fa9c94470d9a0a22602cce3154@sentry.io/1877677' });
}
const PROXY_PATH = 'api/v1/proxy';
export const SDK_API_URL = `${process.env.SDK_API_URL}/${PROXY_PATH}` || `https://api.lbry.tv/${PROXY_PATH}`;

View file

@ -231,6 +231,12 @@ a {
}
}
.error-wrapper {
background-color: var(--color-error);
padding: var(--spacing-small);
border-radius: var(--border-radius);
}
.error-text {
color: var(--color-text-error);
}

View file

@ -12,14 +12,12 @@ const STATIC_ROOT = path.resolve(__dirname, 'static/');
let baseConfig = {
mode: ifProduction('production', 'development'),
devtool: ifProduction(false, 'eval-source-map'),
devtool: ifProduction('source-map', 'eval-cheap-source-map'),
optimization: {
minimizer: [
new TerserPlugin({
parallel: true,
terserOptions: {
mangle: true,
},
sourceMap: true,
}),
],
},
@ -87,6 +85,7 @@ let baseConfig = {
__static: `"${path.join(__dirname, 'static').replace(/\\/g, '\\\\')}"`,
'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
'process.env.LBRY_API_URL': JSON.stringify(process.env.LBRY_API_URL),
'process.env.SENTRY_AUTH_TOKEN': JSON.stringify(process.env.SENTRY_AUTH_TOKEN),
}),
],
};

View file

@ -7,10 +7,12 @@ const CopyWebpackPlugin = require('copy-webpack-plugin');
const { DefinePlugin, ProvidePlugin } = require('webpack');
const { getIfUtils, removeEmpty } = require('webpack-config-utils');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const SentryWebpackPlugin = require('@sentry/webpack-plugin');
const STATIC_ROOT = path.resolve(__dirname, 'static/');
const DIST_ROOT = path.resolve(__dirname, 'dist/');
const NODE_ENV = process.env.NODE_ENV || 'development';
const hasSentryToken = process.env.SENTRY_AUTH_TOKEN !== undefined;
const { ifProduction } = getIfUtils(NODE_ENV);
@ -83,6 +85,26 @@ if (process.env.NODE_ENV === 'production') {
});
}
let plugins = [
new DefinePlugin({
IS_WEB: JSON.stringify(false),
}),
new ProvidePlugin({
__: ['i18n.js', '__'],
}),
];
if (hasSentryToken) {
plugins.push(
new SentryWebpackPlugin({
include: './dist',
ignoreFile: '.sentrycliignore',
ignore: ['node_modules', 'webpack.config.js', 'webworkers'],
configFile: 'sentry.properties',
})
);
}
const renderConfig = {
target: 'electron-renderer',
entry: {
@ -110,15 +132,7 @@ const renderConfig = {
},
],
},
plugins: [
// new BundleAnalyzerPlugin(),
new DefinePlugin({
IS_WEB: JSON.stringify(false),
}),
new ProvidePlugin({
__: ['i18n.js', '__'],
}),
],
plugins,
};
module.exports = [merge(baseConfig, mainConfig), merge(baseConfig, renderConfig)];

105
yarn.lock
View file

@ -1140,6 +1140,77 @@
dependencies:
any-observable "^0.3.0"
"@sentry/browser@^5.12.1":
version "5.12.1"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.12.1.tgz#dc1f268595269fb7277f55eb625c7e92d76dc01b"
integrity sha512-Zl7VdppUxctyaoqMSEhnDJp2rrupx8n8N2n3PSooH74yhB2Z91nt84mouczprBsw3JU1iggGyUw9seRFzDI1hw==
dependencies:
"@sentry/core" "5.12.0"
"@sentry/types" "5.12.0"
"@sentry/utils" "5.12.0"
tslib "^1.9.3"
"@sentry/cli@^1.49.0":
version "1.49.0"
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.49.0.tgz#174152978acbe6023986a8fb0b247cf58b4653d8"
integrity sha512-Augz7c42Cxz/xWQ/NOVjUGePKVA370quvskWbCICMUwxcTvKnCLI+7KDdzEoCexj4MSuxFfBzLnrrn4w2+c9TQ==
dependencies:
fs-copy-file-sync "^1.1.1"
https-proxy-agent "^3.0.0"
mkdirp "^0.5.1"
node-fetch "^2.1.2"
progress "2.0.0"
proxy-from-env "^1.0.0"
"@sentry/core@5.12.0":
version "5.12.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.12.0.tgz#d6380c4ef7beee5f418ac1d0e5be86a2de2af449"
integrity sha512-wY4rsoX71QsGpcs9tF+OxKgDPKzIFMRvFiSRcJoPMfhFsTilQ/CBMn/c3bDtWQd9Bnr/ReQIL6NbnIjUsPHA4Q==
dependencies:
"@sentry/hub" "5.12.0"
"@sentry/minimal" "5.12.0"
"@sentry/types" "5.12.0"
"@sentry/utils" "5.12.0"
tslib "^1.9.3"
"@sentry/hub@5.12.0":
version "5.12.0"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.12.0.tgz#5e8c8f249f5bdbeb8cc4ec02c2ccc53a67f2cc02"
integrity sha512-3k7yE8BEVJsKx8mR4LcI4IN0O8pngmq44OcJ/fRUUBAPqsT38jsJdP2CaWhdlM1jiNUzUDB1ktBv6/lY+VgcoQ==
dependencies:
"@sentry/types" "5.12.0"
"@sentry/utils" "5.12.0"
tslib "^1.9.3"
"@sentry/minimal@5.12.0":
version "5.12.0"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.12.0.tgz#2611e2aa520c1edb7999e6de51bd65ec66341757"
integrity sha512-fk73meyz4k4jCg9yzbma+WkggsfEIQWI2e2TWfYsRGcrV3RnlSrXyM4D91/A8Bjx10SNezHPUFHjasjlHXOkyA==
dependencies:
"@sentry/hub" "5.12.0"
"@sentry/types" "5.12.0"
tslib "^1.9.3"
"@sentry/types@5.12.0":
version "5.12.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.12.0.tgz#5367e53c74261beea01502e3f7b6f3d822682a31"
integrity sha512-aZbBouBLrKB8wXlztriIagZNmsB+wegk1Jkl6eprqRW/w24Sl/47tiwH8c5S4jYTxdAiJk+SAR10AAuYmIN3zg==
"@sentry/utils@5.12.0":
version "5.12.0"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.12.0.tgz#62967f934a3ee6d21472eac0219084e37225933e"
integrity sha512-fYUadGLbfTCbs4OG5hKCOtv2jrNE4/8LHNABy9DwNJ/t5DVtGqWAZBnxsC+FG6a3nVqCpxjFI9AHlYsJ2wsf7Q==
dependencies:
"@sentry/types" "5.12.0"
tslib "^1.9.3"
"@sentry/webpack-plugin@^1.10.0":
version "1.10.0"
resolved "https://registry.yarnpkg.com/@sentry/webpack-plugin/-/webpack-plugin-1.10.0.tgz#7f7727b18dbdd3eaeb0998102be89d8733ddbca5"
integrity sha512-keT6cH8732bFjdH/v+C/UwbJu6byZ5L8t7QRLjgj+fqDyc/RlVEw9VzIQSJGUtd2XgImpdduWzgxythLkwKJjg==
dependencies:
"@sentry/cli" "^1.49.0"
"@sindresorhus/is@^0.14.0":
version "0.14.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
@ -1462,6 +1533,13 @@ agent-base@4, agent-base@^4.1.0:
dependencies:
es6-promisify "^5.0.0"
agent-base@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
dependencies:
es6-promisify "^5.0.0"
ajv-errors@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d"
@ -5293,6 +5371,11 @@ fs-constants@^1.0.0:
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
fs-copy-file-sync@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fs-copy-file-sync/-/fs-copy-file-sync-1.1.1.tgz#11bf32c096c10d126e5f6b36d06eece776062918"
integrity sha512-2QY5eeqVv4m2PfyMiEuy9adxNP+ajf+8AR05cEi+OAzPcOj90hvFImeZhTmKLBgSd9EvG33jsD7ZRxsx9dThkQ==
fs-extra@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
@ -6055,6 +6138,14 @@ https-proxy-agent@^2.2.0:
agent-base "^4.1.0"
debug "^3.1.0"
https-proxy-agent@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz#b8c286433e87602311b01c8ea34413d856a4af81"
integrity sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==
dependencies:
agent-base "^4.3.0"
debug "^3.1.0"
humanize-plus@^1.8.1:
version "1.8.2"
resolved "https://registry.yarnpkg.com/humanize-plus/-/humanize-plus-1.8.2.tgz#a65b34459ad6367adbb3707a82a3c9f916167030"
@ -8060,7 +8151,7 @@ node-emoji@^1.8.1:
dependencies:
lodash.toarray "^4.4.0"
node-fetch@^2.1.1, node-fetch@^2.3.0:
node-fetch@^2.1.1, node-fetch@^2.1.2, node-fetch@^2.3.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
@ -9739,6 +9830,11 @@ progress-stream@^1.1.0:
speedometer "~0.1.2"
through2 "~0.2.3"
progress@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f"
integrity sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=
progress@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
@ -9771,6 +9867,11 @@ proxy-addr@~2.0.5:
forwarded "~0.1.2"
ipaddr.js "1.9.0"
proxy-from-env@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee"
integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=
proxy-polyfill@0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/proxy-polyfill/-/proxy-polyfill-0.1.6.tgz#ef41ec6c66f534db15db36c54493a62d184b364e"
@ -12145,7 +12246,7 @@ tryer@^1.0.0:
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
tslib@^1.9.0:
tslib@^1.9.0, tslib@^1.9.3:
version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==