@sentry/react 7.0.0-alpha.0 → 7.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -3
- package/cjs/constants.js +12 -5
- package/cjs/constants.js.map +1 -1
- package/cjs/errorboundary.js +139 -112
- package/cjs/errorboundary.js.map +1 -1
- package/cjs/flags.js +7 -3
- package/cjs/flags.js.map +1 -1
- package/cjs/index.js +30 -21
- package/cjs/index.js.map +1 -1
- package/cjs/profiler.js +178 -147
- package/cjs/profiler.js.map +1 -1
- package/cjs/reactrouter.js +149 -99
- package/cjs/reactrouter.js.map +1 -1
- package/cjs/reactrouterv3.js +107 -83
- package/cjs/reactrouterv3.js.map +1 -1
- package/cjs/reactrouterv6.js +163 -0
- package/cjs/reactrouterv6.js.map +1 -0
- package/cjs/redux.js +51 -42
- package/cjs/redux.js.map +1 -1
- package/cjs/sdk.js +18 -15
- package/cjs/sdk.js.map +1 -1
- package/esm/constants.js +8 -4
- package/esm/constants.js.map +1 -1
- package/esm/errorboundary.js +124 -107
- package/esm/errorboundary.js.map +1 -1
- package/esm/flags.js +5 -2
- package/esm/flags.js.map +1 -1
- package/esm/index.js +8 -7
- package/esm/index.js.map +1 -1
- package/esm/profiler.js +161 -140
- package/esm/profiler.js.map +1 -1
- package/esm/reactrouter.js +134 -92
- package/esm/reactrouter.js.map +1 -1
- package/esm/reactrouterv3.js +103 -79
- package/esm/reactrouterv3.js.map +1 -1
- package/esm/reactrouterv6.js +153 -0
- package/esm/reactrouterv6.js.map +1 -0
- package/esm/redux.js +49 -41
- package/esm/redux.js.map +1 -1
- package/esm/sdk.js +17 -14
- package/esm/sdk.js.map +1 -1
- package/package.json +5 -6
- package/types/errorboundary.d.ts +1 -0
- package/types/errorboundary.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/reactrouterv6.d.ts +27 -0
- package/types/reactrouterv6.d.ts.map +1 -0
- package/cjs/constants.d.ts +0 -4
- package/cjs/constants.d.ts.map +0 -1
- package/cjs/errorboundary.d.ts +0 -62
- package/cjs/errorboundary.d.ts.map +0 -1
- package/cjs/flags.d.ts +0 -3
- package/cjs/flags.d.ts.map +0 -1
- package/cjs/index.d.ts +0 -8
- package/cjs/index.d.ts.map +0 -1
- package/cjs/profiler.d.ts +0 -54
- package/cjs/profiler.d.ts.map +0 -1
- package/cjs/reactrouter.d.ts +0 -25
- package/cjs/reactrouter.d.ts.map +0 -1
- package/cjs/reactrouterv3.d.ts +0 -26
- package/cjs/reactrouterv3.d.ts.map +0 -1
- package/cjs/redux.d.ts +0 -33
- package/cjs/redux.d.ts.map +0 -1
- package/cjs/sdk.d.ts +0 -6
- package/cjs/sdk.d.ts.map +0 -1
- package/cjs/types.d.ts +0 -8
- package/cjs/types.d.ts.map +0 -1
- package/cjs/types.js +0 -2
- package/cjs/types.js.map +0 -1
- package/esm/constants.d.ts +0 -4
- package/esm/constants.d.ts.map +0 -1
- package/esm/errorboundary.d.ts +0 -62
- package/esm/errorboundary.d.ts.map +0 -1
- package/esm/flags.d.ts +0 -3
- package/esm/flags.d.ts.map +0 -1
- package/esm/index.d.ts +0 -8
- package/esm/index.d.ts.map +0 -1
- package/esm/profiler.d.ts +0 -54
- package/esm/profiler.d.ts.map +0 -1
- package/esm/reactrouter.d.ts +0 -25
- package/esm/reactrouter.d.ts.map +0 -1
- package/esm/reactrouterv3.d.ts +0 -26
- package/esm/reactrouterv3.d.ts.map +0 -1
- package/esm/redux.d.ts +0 -33
- package/esm/redux.d.ts.map +0 -1
- package/esm/sdk.d.ts +0 -6
- package/esm/sdk.d.ts.map +0 -1
- package/esm/types.d.ts +0 -8
- package/esm/types.d.ts.map +0 -1
- package/esm/types.js +0 -1
- package/esm/types.js.map +0 -1
package/cjs/profiler.js
CHANGED
|
@@ -1,98 +1,110 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
|
|
1
|
+
var {
|
|
2
|
+
_interopDefault,
|
|
3
|
+
_interopNamespace
|
|
4
|
+
} = require('@sentry/utils/cjs/buildPolyfills');
|
|
5
|
+
|
|
6
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
7
|
+
|
|
8
|
+
var browser = require('@sentry/browser');
|
|
9
|
+
var utils = require('@sentry/utils');
|
|
10
|
+
var hoistNonReactStatics = require('hoist-non-react-statics');
|
|
11
|
+
var React = require('react');
|
|
12
|
+
var constants = require('./constants.js');
|
|
13
|
+
|
|
14
|
+
var hoistNonReactStatics__default = /*#__PURE__*/_interopDefault(hoistNonReactStatics);
|
|
15
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
16
|
+
|
|
17
|
+
var _jsxFileName = "/home/runner/work/sentry-javascript/sentry-javascript/packages/react/src/profiler.tsx";
|
|
18
|
+
var UNKNOWN_COMPONENT = 'unknown';
|
|
19
|
+
|
|
11
20
|
/**
|
|
12
21
|
* The Profiler component leverages Sentry's Tracing integration to generate
|
|
13
22
|
* spans based on component lifecycles.
|
|
14
23
|
*/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
return _this;
|
|
24
|
+
class Profiler extends React__namespace.Component {
|
|
25
|
+
/**
|
|
26
|
+
* The span of the mount activity
|
|
27
|
+
* Made protected for the React Native SDK to access
|
|
28
|
+
*/
|
|
29
|
+
__init() {this._mountSpan = undefined;}
|
|
30
|
+
|
|
31
|
+
static __initStatic() {this.defaultProps = {
|
|
32
|
+
disabled: false,
|
|
33
|
+
includeRender: true,
|
|
34
|
+
includeUpdates: true,
|
|
35
|
+
};}
|
|
36
|
+
|
|
37
|
+
constructor(props) {
|
|
38
|
+
super(props);Profiler.prototype.__init.call(this);;
|
|
39
|
+
const { name, disabled = false } = this.props;
|
|
40
|
+
|
|
41
|
+
if (disabled) {
|
|
42
|
+
return;
|
|
36
43
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
44
|
+
|
|
45
|
+
var activeTransaction = getActiveTransaction();
|
|
46
|
+
if (activeTransaction) {
|
|
47
|
+
this._mountSpan = activeTransaction.startChild({
|
|
48
|
+
description: `<${name}>`,
|
|
49
|
+
op: constants.REACT_MOUNT_OP,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// If a component mounted, we can finish the mount activity.
|
|
55
|
+
componentDidMount() {
|
|
56
|
+
if (this._mountSpan) {
|
|
57
|
+
this._mountSpan.finish();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
componentDidUpdate({ updateProps, includeUpdates = true }) {
|
|
62
|
+
// Only generate an update span if hasUpdateSpan is true, if there is a valid mountSpan,
|
|
63
|
+
// and if the updateProps have changed. It is ok to not do a deep equality check here as it is expensive.
|
|
64
|
+
// We are just trying to give baseline clues for further investigation.
|
|
65
|
+
if (includeUpdates && this._mountSpan && updateProps !== this.props.updateProps) {
|
|
66
|
+
// See what props haved changed between the previous props, and the current props. This is
|
|
67
|
+
// set as data on the span. We just store the prop keys as the values could be potenially very large.
|
|
68
|
+
var changedProps = Object.keys(updateProps).filter(k => updateProps[k] !== this.props.updateProps[k]);
|
|
69
|
+
if (changedProps.length > 0) {
|
|
70
|
+
// The update span is a point in time span with 0 duration, just signifying that the component
|
|
71
|
+
// has been updated.
|
|
72
|
+
var now = utils.timestampWithMs();
|
|
73
|
+
this._mountSpan.startChild({
|
|
74
|
+
data: {
|
|
75
|
+
changedProps,
|
|
76
|
+
},
|
|
77
|
+
description: `<${this.props.name}>`,
|
|
78
|
+
endTimestamp: now,
|
|
79
|
+
op: constants.REACT_UPDATE_OP,
|
|
80
|
+
startTimestamp: now,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// If a component is unmounted, we can say it is no longer on the screen.
|
|
87
|
+
// This means we can finish the span representing the component render.
|
|
88
|
+
componentWillUnmount() {
|
|
89
|
+
const { name, includeRender = true } = this.props;
|
|
90
|
+
|
|
91
|
+
if (this._mountSpan && includeRender) {
|
|
92
|
+
// If we were able to obtain the spanId of the mount activity, we should set the
|
|
93
|
+
// next activity as a child to the component mount activity.
|
|
94
|
+
this._mountSpan.startChild({
|
|
95
|
+
description: `<${name}>`,
|
|
96
|
+
endTimestamp: utils.timestampWithMs(),
|
|
97
|
+
op: constants.REACT_RENDER_OP,
|
|
98
|
+
startTimestamp: this._mountSpan.endTimestamp,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
render() {
|
|
104
|
+
return this.props.children;
|
|
105
|
+
}
|
|
106
|
+
}Profiler.__initStatic();
|
|
107
|
+
|
|
96
108
|
/**
|
|
97
109
|
* withProfiler is a higher order component that wraps a
|
|
98
110
|
* component in a {@link Profiler} component. It is recommended that
|
|
@@ -101,19 +113,28 @@ exports.Profiler = Profiler;
|
|
|
101
113
|
* @param WrappedComponent component that is wrapped by Profiler
|
|
102
114
|
* @param options the {@link ProfilerProps} you can pass into the Profiler
|
|
103
115
|
*/
|
|
104
|
-
function withProfiler(
|
|
105
|
-
|
|
106
|
-
options
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
function withProfiler(
|
|
117
|
+
WrappedComponent,
|
|
118
|
+
// We do not want to have `updateProps` given in options, it is instead filled through the HOC.
|
|
119
|
+
options,
|
|
120
|
+
) {
|
|
121
|
+
var componentDisplayName =
|
|
122
|
+
(options && options.name) || WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;
|
|
123
|
+
|
|
124
|
+
var Wrapped = (props) => (
|
|
125
|
+
React__namespace.createElement(Profiler, { ...options, name: componentDisplayName, updateProps: props, __self: this, __source: {fileName: _jsxFileName, lineNumber: 133}}
|
|
126
|
+
, React__namespace.createElement(WrappedComponent, { ...props, __self: this, __source: {fileName: _jsxFileName, lineNumber: 134}} )
|
|
127
|
+
)
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
Wrapped.displayName = `profiler(${componentDisplayName})`;
|
|
131
|
+
|
|
132
|
+
// Copy over static methods from Wrapped component to Profiler HOC
|
|
133
|
+
// See: https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over
|
|
134
|
+
hoistNonReactStatics__default(Wrapped, WrappedComponent);
|
|
135
|
+
return Wrapped;
|
|
115
136
|
}
|
|
116
|
-
|
|
137
|
+
|
|
117
138
|
/**
|
|
118
139
|
*
|
|
119
140
|
* `useProfiler` is a React hook that profiles a React component.
|
|
@@ -121,53 +142,63 @@ exports.withProfiler = withProfiler;
|
|
|
121
142
|
* Requires React 16.8 or above.
|
|
122
143
|
* @param name displayName of component being profiled
|
|
123
144
|
*/
|
|
124
|
-
function useProfiler(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
145
|
+
function useProfiler(
|
|
146
|
+
name,
|
|
147
|
+
options = {
|
|
148
|
+
disabled: false,
|
|
149
|
+
hasRenderSpan: true,
|
|
150
|
+
},
|
|
151
|
+
) {
|
|
152
|
+
const [mountSpan] = React__namespace.useState(() => {
|
|
153
|
+
if (options && options.disabled) {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
var activeTransaction = getActiveTransaction();
|
|
158
|
+
if (activeTransaction) {
|
|
159
|
+
return activeTransaction.startChild({
|
|
160
|
+
description: `<${name}>`,
|
|
161
|
+
op: constants.REACT_MOUNT_OP,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return undefined;
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
React__namespace.useEffect(() => {
|
|
169
|
+
if (mountSpan) {
|
|
170
|
+
mountSpan.finish();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return () => {
|
|
174
|
+
if (mountSpan && options.hasRenderSpan) {
|
|
175
|
+
mountSpan.startChild({
|
|
176
|
+
description: `<${name}>`,
|
|
177
|
+
endTimestamp: utils.timestampWithMs(),
|
|
178
|
+
op: constants.REACT_RENDER_OP,
|
|
179
|
+
startTimestamp: mountSpan.endTimestamp,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
// We only want this to run once.
|
|
184
|
+
}, []);
|
|
159
185
|
}
|
|
160
|
-
|
|
186
|
+
|
|
161
187
|
/** Grabs active transaction off scope */
|
|
162
|
-
function getActiveTransaction(hub) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return scope.getTransaction();
|
|
168
|
-
}
|
|
188
|
+
function getActiveTransaction(hub = browser.getCurrentHub()) {
|
|
189
|
+
if (hub) {
|
|
190
|
+
var scope = hub.getScope();
|
|
191
|
+
if (scope) {
|
|
192
|
+
return scope.getTransaction() ;
|
|
169
193
|
}
|
|
170
|
-
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return undefined;
|
|
171
197
|
}
|
|
198
|
+
|
|
199
|
+
exports.Profiler = Profiler;
|
|
200
|
+
exports.UNKNOWN_COMPONENT = UNKNOWN_COMPONENT;
|
|
172
201
|
exports.getActiveTransaction = getActiveTransaction;
|
|
173
|
-
|
|
202
|
+
exports.useProfiler = useProfiler;
|
|
203
|
+
exports.withProfiler = withProfiler;
|
|
204
|
+
//# sourceMappingURL=profiler.js.map
|
package/cjs/profiler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profiler.js","sourceRoot":"","sources":["../../src/profiler.tsx"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { getCurrentHub, Hub } from '@sentry/browser';\nimport { Span, Transaction } from '@sentry/types';\nimport { timestampWithMs } from '@sentry/utils';\nimport hoistNonReactStatics from 'hoist-non-react-statics';\nimport * as React from 'react';\n\nimport { REACT_MOUNT_OP, REACT_RENDER_OP, REACT_UPDATE_OP } from './constants';\n\nexport const UNKNOWN_COMPONENT = 'unknown';\n\nexport type ProfilerProps = {\n // The name of the component being profiled.\n name: string;\n // If the Profiler is disabled. False by default. This is useful if you want to disable profilers\n // in certain environments.\n disabled?: boolean;\n // If time component is on page should be displayed as spans. True by default.\n includeRender?: boolean;\n // If component updates should be displayed as spans. True by default.\n includeUpdates?: boolean;\n // props given to component being profiled.\n updateProps: { [key: string]: unknown };\n};\n\n/**\n * The Profiler component leverages Sentry's Tracing integration to generate\n * spans based on component lifecycles.\n */\nclass Profiler extends React.Component<ProfilerProps> {\n /**\n * The span of the mount activity\n * Made protected for the React Native SDK to access\n */\n protected _mountSpan: Span | undefined = undefined;\n\n // eslint-disable-next-line @typescript-eslint/member-ordering\n public static defaultProps: Partial<ProfilerProps> = {\n disabled: false,\n includeRender: true,\n includeUpdates: true,\n };\n\n public constructor(props: ProfilerProps) {\n super(props);\n const { name, disabled = false } = this.props;\n\n if (disabled) {\n return;\n }\n\n const activeTransaction = getActiveTransaction();\n if (activeTransaction) {\n this._mountSpan = activeTransaction.startChild({\n description: `<${name}>`,\n op: REACT_MOUNT_OP,\n });\n }\n }\n\n // If a component mounted, we can finish the mount activity.\n public componentDidMount(): void {\n if (this._mountSpan) {\n this._mountSpan.finish();\n }\n }\n\n public componentDidUpdate({ updateProps, includeUpdates = true }: ProfilerProps): void {\n // Only generate an update span if hasUpdateSpan is true, if there is a valid mountSpan,\n // and if the updateProps have changed. It is ok to not do a deep equality check here as it is expensive.\n // We are just trying to give baseline clues for further investigation.\n if (includeUpdates && this._mountSpan && updateProps !== this.props.updateProps) {\n // See what props haved changed between the previous props, and the current props. This is\n // set as data on the span. We just store the prop keys as the values could be potenially very large.\n const changedProps = Object.keys(updateProps).filter(k => updateProps[k] !== this.props.updateProps[k]);\n if (changedProps.length > 0) {\n // The update span is a point in time span with 0 duration, just signifying that the component\n // has been updated.\n const now = timestampWithMs();\n this._mountSpan.startChild({\n data: {\n changedProps,\n },\n description: `<${this.props.name}>`,\n endTimestamp: now,\n op: REACT_UPDATE_OP,\n startTimestamp: now,\n });\n }\n }\n }\n\n // If a component is unmounted, we can say it is no longer on the screen.\n // This means we can finish the span representing the component render.\n public componentWillUnmount(): void {\n const { name, includeRender = true } = this.props;\n\n if (this._mountSpan && includeRender) {\n // If we were able to obtain the spanId of the mount activity, we should set the\n // next activity as a child to the component mount activity.\n this._mountSpan.startChild({\n description: `<${name}>`,\n endTimestamp: timestampWithMs(),\n op: REACT_RENDER_OP,\n startTimestamp: this._mountSpan.endTimestamp,\n });\n }\n }\n\n public render(): React.ReactNode {\n return this.props.children;\n }\n}\n\n/**\n * withProfiler is a higher order component that wraps a\n * component in a {@link Profiler} component. It is recommended that\n * the higher order component be used over the regular {@link Profiler} component.\n *\n * @param WrappedComponent component that is wrapped by Profiler\n * @param options the {@link ProfilerProps} you can pass into the Profiler\n */\nfunction withProfiler<P extends Record<string, any>>(\n WrappedComponent: React.ComponentType<P>,\n // We do not want to have `updateProps` given in options, it is instead filled through the HOC.\n options?: Pick<Partial<ProfilerProps>, Exclude<keyof ProfilerProps, 'updateProps'>>,\n): React.FC<P> {\n const componentDisplayName =\n (options && options.name) || WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;\n\n const Wrapped: React.FC<P> = (props: P) => (\n <Profiler {...options} name={componentDisplayName} updateProps={props}>\n <WrappedComponent {...props} />\n </Profiler>\n );\n\n Wrapped.displayName = `profiler(${componentDisplayName})`;\n\n // Copy over static methods from Wrapped component to Profiler HOC\n // See: https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over\n hoistNonReactStatics(Wrapped, WrappedComponent);\n return Wrapped;\n}\n\n/**\n *\n * `useProfiler` is a React hook that profiles a React component.\n *\n * Requires React 16.8 or above.\n * @param name displayName of component being profiled\n */\nfunction useProfiler(\n name: string,\n options: { disabled?: boolean; hasRenderSpan?: boolean } = {\n disabled: false,\n hasRenderSpan: true,\n },\n): void {\n const [mountSpan] = React.useState(() => {\n if (options && options.disabled) {\n return undefined;\n }\n\n const activeTransaction = getActiveTransaction();\n if (activeTransaction) {\n return activeTransaction.startChild({\n description: `<${name}>`,\n op: REACT_MOUNT_OP,\n });\n }\n\n return undefined;\n });\n\n React.useEffect(() => {\n if (mountSpan) {\n mountSpan.finish();\n }\n\n return (): void => {\n if (mountSpan && options.hasRenderSpan) {\n mountSpan.startChild({\n description: `<${name}>`,\n endTimestamp: timestampWithMs(),\n op: REACT_RENDER_OP,\n startTimestamp: mountSpan.endTimestamp,\n });\n }\n };\n // We only want this to run once.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n}\n\nexport { withProfiler, Profiler, useProfiler };\n\n/** Grabs active transaction off scope */\nexport function getActiveTransaction<T extends Transaction>(hub: Hub = getCurrentHub()): T | undefined {\n if (hub) {\n const scope = hub.getScope();\n if (scope) {\n return scope.getTransaction() as T | undefined;\n }\n }\n\n return undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"profiler.js","sources":["../../src/profiler.tsx"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { getCurrentHub, Hub } from '@sentry/browser';\nimport { Span, Transaction } from '@sentry/types';\nimport { timestampWithMs } from '@sentry/utils';\nimport hoistNonReactStatics from 'hoist-non-react-statics';\nimport * as React from 'react';\n\nimport { REACT_MOUNT_OP, REACT_RENDER_OP, REACT_UPDATE_OP } from './constants';\n\nexport const UNKNOWN_COMPONENT = 'unknown';\n\nexport type ProfilerProps = {\n // The name of the component being profiled.\n name: string;\n // If the Profiler is disabled. False by default. This is useful if you want to disable profilers\n // in certain environments.\n disabled?: boolean;\n // If time component is on page should be displayed as spans. True by default.\n includeRender?: boolean;\n // If component updates should be displayed as spans. True by default.\n includeUpdates?: boolean;\n // props given to component being profiled.\n updateProps: { [key: string]: unknown };\n};\n\n/**\n * The Profiler component leverages Sentry's Tracing integration to generate\n * spans based on component lifecycles.\n */\nclass Profiler extends React.Component<ProfilerProps> {\n /**\n * The span of the mount activity\n * Made protected for the React Native SDK to access\n */\n protected _mountSpan: Span | undefined = undefined;\n\n // eslint-disable-next-line @typescript-eslint/member-ordering\n public static defaultProps: Partial<ProfilerProps> = {\n disabled: false,\n includeRender: true,\n includeUpdates: true,\n };\n\n public constructor(props: ProfilerProps) {\n super(props);\n const { name, disabled = false } = this.props;\n\n if (disabled) {\n return;\n }\n\n const activeTransaction = getActiveTransaction();\n if (activeTransaction) {\n this._mountSpan = activeTransaction.startChild({\n description: `<${name}>`,\n op: REACT_MOUNT_OP,\n });\n }\n }\n\n // If a component mounted, we can finish the mount activity.\n public componentDidMount(): void {\n if (this._mountSpan) {\n this._mountSpan.finish();\n }\n }\n\n public componentDidUpdate({ updateProps, includeUpdates = true }: ProfilerProps): void {\n // Only generate an update span if hasUpdateSpan is true, if there is a valid mountSpan,\n // and if the updateProps have changed. It is ok to not do a deep equality check here as it is expensive.\n // We are just trying to give baseline clues for further investigation.\n if (includeUpdates && this._mountSpan && updateProps !== this.props.updateProps) {\n // See what props haved changed between the previous props, and the current props. This is\n // set as data on the span. We just store the prop keys as the values could be potenially very large.\n const changedProps = Object.keys(updateProps).filter(k => updateProps[k] !== this.props.updateProps[k]);\n if (changedProps.length > 0) {\n // The update span is a point in time span with 0 duration, just signifying that the component\n // has been updated.\n const now = timestampWithMs();\n this._mountSpan.startChild({\n data: {\n changedProps,\n },\n description: `<${this.props.name}>`,\n endTimestamp: now,\n op: REACT_UPDATE_OP,\n startTimestamp: now,\n });\n }\n }\n }\n\n // If a component is unmounted, we can say it is no longer on the screen.\n // This means we can finish the span representing the component render.\n public componentWillUnmount(): void {\n const { name, includeRender = true } = this.props;\n\n if (this._mountSpan && includeRender) {\n // If we were able to obtain the spanId of the mount activity, we should set the\n // next activity as a child to the component mount activity.\n this._mountSpan.startChild({\n description: `<${name}>`,\n endTimestamp: timestampWithMs(),\n op: REACT_RENDER_OP,\n startTimestamp: this._mountSpan.endTimestamp,\n });\n }\n }\n\n public render(): React.ReactNode {\n return this.props.children;\n }\n}\n\n/**\n * withProfiler is a higher order component that wraps a\n * component in a {@link Profiler} component. It is recommended that\n * the higher order component be used over the regular {@link Profiler} component.\n *\n * @param WrappedComponent component that is wrapped by Profiler\n * @param options the {@link ProfilerProps} you can pass into the Profiler\n */\nfunction withProfiler<P extends Record<string, any>>(\n WrappedComponent: React.ComponentType<P>,\n // We do not want to have `updateProps` given in options, it is instead filled through the HOC.\n options?: Pick<Partial<ProfilerProps>, Exclude<keyof ProfilerProps, 'updateProps'>>,\n): React.FC<P> {\n const componentDisplayName =\n (options && options.name) || WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;\n\n const Wrapped: React.FC<P> = (props: P) => (\n <Profiler {...options} name={componentDisplayName} updateProps={props}>\n <WrappedComponent {...props} />\n </Profiler>\n );\n\n Wrapped.displayName = `profiler(${componentDisplayName})`;\n\n // Copy over static methods from Wrapped component to Profiler HOC\n // See: https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over\n hoistNonReactStatics(Wrapped, WrappedComponent);\n return Wrapped;\n}\n\n/**\n *\n * `useProfiler` is a React hook that profiles a React component.\n *\n * Requires React 16.8 or above.\n * @param name displayName of component being profiled\n */\nfunction useProfiler(\n name: string,\n options: { disabled?: boolean; hasRenderSpan?: boolean } = {\n disabled: false,\n hasRenderSpan: true,\n },\n): void {\n const [mountSpan] = React.useState(() => {\n if (options && options.disabled) {\n return undefined;\n }\n\n const activeTransaction = getActiveTransaction();\n if (activeTransaction) {\n return activeTransaction.startChild({\n description: `<${name}>`,\n op: REACT_MOUNT_OP,\n });\n }\n\n return undefined;\n });\n\n React.useEffect(() => {\n if (mountSpan) {\n mountSpan.finish();\n }\n\n return (): void => {\n if (mountSpan && options.hasRenderSpan) {\n mountSpan.startChild({\n description: `<${name}>`,\n endTimestamp: timestampWithMs(),\n op: REACT_RENDER_OP,\n startTimestamp: mountSpan.endTimestamp,\n });\n }\n };\n // We only want this to run once.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n}\n\nexport { withProfiler, Profiler, useProfiler };\n\n/** Grabs active transaction off scope */\nexport function getActiveTransaction<T extends Transaction>(hub: Hub = getCurrentHub()): T | undefined {\n if (hub) {\n const scope = hub.getScope();\n if (scope) {\n return scope.getTransaction() as T | undefined;\n }\n }\n\n return undefined;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;AA0BA;;;;AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmFA;;AAEA;;;;;;;;AAQA;;;;AAIA;;;;;;;;;;;;;;;;AAgBA;;AAEA;;;;;;;AAOA;;;;;;AAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA;;AAIA;;;;;;;;;;AAUA;;;;;;"}
|