@parcel/profiler 2.12.1-dev.3151 → 2.12.1-dev.3185
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/lib/Tracer.d.ts +3 -3
- package/lib/Tracer.js +65 -29
- package/lib/types.d.ts +1 -3
- package/package.json +6 -5
- package/src/Tracer.js +78 -38
- package/src/types.js +1 -3
- package/test/Tracer.test.js +104 -55
package/lib/Tracer.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { TraceEvent, IDisposable, PluginTracer as IPluginTracer } from "@parcel/types";
|
|
1
|
+
import type { TraceEvent, IDisposable, MeasurementOptions, PluginTracer as IPluginTracer } from "@parcel/types";
|
|
2
2
|
import type { TraceMeasurement as ITraceMeasurement } from "./types";
|
|
3
3
|
export default class Tracer {
|
|
4
4
|
|
|
5
5
|
onTrace(cb: (event: TraceEvent) => unknown): IDisposable;
|
|
6
|
-
|
|
7
|
-
createMeasurement(name: string, category?: string, argumentName?: string, otherArgs?: Record<string, unknown>): ITraceMeasurement | null;
|
|
6
|
+
measure<T>({ args, categories, name }: MeasurementOptions, fn: () => T): T;
|
|
8
7
|
get enabled(): boolean;
|
|
9
8
|
enable(): void;
|
|
10
9
|
disable(): void;
|
|
@@ -24,5 +23,6 @@ export declare class PluginTracer implements IPluginTracer {
|
|
|
24
23
|
constructor(opts: TracerOpts);
|
|
25
24
|
get enabled(): boolean;
|
|
26
25
|
createMeasurement(name: string, category?: string, argumentName?: string, otherArgs?: Record<string, unknown>): ITraceMeasurement | null;
|
|
26
|
+
measure<T>(options: MeasurementOptions, fn: () => T): T;
|
|
27
27
|
}
|
|
28
28
|
export {};
|
package/lib/Tracer.js
CHANGED
|
@@ -62,38 +62,37 @@ class Tracer {
|
|
|
62
62
|
onTrace(cb) {
|
|
63
63
|
return this.#traceEmitter.addListener(cb);
|
|
64
64
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
createMeasurement(name, category = 'Core', argumentName, otherArgs) {
|
|
74
|
-
if (!this.enabled) return null;
|
|
75
|
-
|
|
76
|
-
// We create `args` in a fairly verbose way to avoid object
|
|
77
|
-
// allocation where not required.
|
|
78
|
-
let args;
|
|
79
|
-
if (typeof argumentName === 'string') {
|
|
80
|
-
args = {
|
|
81
|
-
name: argumentName
|
|
82
|
-
};
|
|
65
|
+
measure({
|
|
66
|
+
args = {},
|
|
67
|
+
categories,
|
|
68
|
+
name
|
|
69
|
+
}, fn) {
|
|
70
|
+
if (!this.enabled) {
|
|
71
|
+
return fn();
|
|
83
72
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
73
|
+
let measurement = new TraceMeasurement(this, name, pid, tid, {
|
|
74
|
+
categories,
|
|
75
|
+
args
|
|
76
|
+
});
|
|
77
|
+
let result;
|
|
78
|
+
let hasFinally = false;
|
|
79
|
+
try {
|
|
80
|
+
result = fn();
|
|
81
|
+
// @ts-expect-error TypeScript types cannot infer that finally can exist
|
|
82
|
+
if (result != null && typeof result === 'object' && typeof result.finally === 'function') {
|
|
83
|
+
hasFinally = true;
|
|
84
|
+
// @ts-expect-error
|
|
85
|
+
// $FlowFixMe[incompatible-use] This will run for a promise type, but it cannot be easily typed in Flow
|
|
86
|
+
result = result.finally(() => {
|
|
87
|
+
measurement === null || measurement === void 0 || measurement.end();
|
|
88
|
+
});
|
|
87
89
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
} finally {
|
|
91
|
+
if (!hasFinally) {
|
|
92
|
+
measurement === null || measurement === void 0 || measurement.end();
|
|
90
93
|
}
|
|
91
94
|
}
|
|
92
|
-
|
|
93
|
-
categories: [category],
|
|
94
|
-
args
|
|
95
|
-
};
|
|
96
|
-
return new TraceMeasurement(this, name, pid, tid, data);
|
|
95
|
+
return result;
|
|
97
96
|
}
|
|
98
97
|
get enabled() {
|
|
99
98
|
return this.#enabled;
|
|
@@ -125,7 +124,44 @@ class PluginTracer {
|
|
|
125
124
|
return tracer.enabled;
|
|
126
125
|
}
|
|
127
126
|
createMeasurement(name, category, argumentName, otherArgs) {
|
|
128
|
-
|
|
127
|
+
if (!this.enabled) return null;
|
|
128
|
+
|
|
129
|
+
// We create `args` in a fairly verbose way to avoid object
|
|
130
|
+
// allocation where not required.
|
|
131
|
+
let args;
|
|
132
|
+
if (typeof argumentName === 'string') {
|
|
133
|
+
args = {
|
|
134
|
+
name: argumentName
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (typeof otherArgs === 'object') {
|
|
138
|
+
if (typeof args == 'undefined') {
|
|
139
|
+
args = {};
|
|
140
|
+
}
|
|
141
|
+
for (const [k, v] of Object.entries(otherArgs)) {
|
|
142
|
+
args[k] = v;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const data = {
|
|
146
|
+
categories: [`${this.category}:${this.origin}${typeof category === 'string' ? `:${category}` : ''}`],
|
|
147
|
+
args
|
|
148
|
+
};
|
|
149
|
+
return new TraceMeasurement(tracer, name, pid, tid, data);
|
|
150
|
+
}
|
|
151
|
+
measure(options, fn) {
|
|
152
|
+
var _options$args;
|
|
153
|
+
if (!this.enabled) {
|
|
154
|
+
return fn();
|
|
155
|
+
}
|
|
156
|
+
return tracer.measure({
|
|
157
|
+
...options,
|
|
158
|
+
// $FlowFixMe[cannot-spread-inexact]
|
|
159
|
+
args: {
|
|
160
|
+
origin: this.origin,
|
|
161
|
+
...((_options$args = options.args) !== null && _options$args !== void 0 ? _options$args : {})
|
|
162
|
+
},
|
|
163
|
+
categories: [this.category, ...options.categories]
|
|
164
|
+
}, fn);
|
|
129
165
|
}
|
|
130
166
|
}
|
|
131
167
|
exports.PluginTracer = PluginTracer;
|
package/lib/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parcel/profiler",
|
|
3
|
-
"version": "2.12.1-dev.
|
|
3
|
+
"version": "2.12.1-dev.3185+298c035e0",
|
|
4
4
|
"description": "Blazing fast, zero configuration web application bundler",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -20,13 +20,14 @@
|
|
|
20
20
|
"node": ">= 12.0.0"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
|
-
"build-ts": "flow-to-ts src/*.js --write && tsc --emitDeclarationOnly --declaration --esModuleInterop --target es2015 --moduleResolution node16 --module node16 src/*.ts && mkdir -p lib && mv src/*.d.ts lib/. && rm src/*.ts && node build-ts.js",
|
|
23
|
+
"build-ts": "flow-to-ts src/*.js --write && rm -f ./src/*.d.ts && tsc --emitDeclarationOnly --declaration --esModuleInterop --target es2015 --moduleResolution node16 --module node16 src/*.ts && mkdir -p lib && mv src/*.d.ts lib/. && rm src/*.ts && node build-ts.js",
|
|
24
24
|
"check-ts": "tsc --noEmit lib/index.d.ts"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@parcel/diagnostic": "2.0.0-dev.
|
|
28
|
-
"@parcel/events": "2.0.0-dev.
|
|
27
|
+
"@parcel/diagnostic": "2.0.0-dev.1562+298c035e0",
|
|
28
|
+
"@parcel/events": "2.0.0-dev.1562+298c035e0",
|
|
29
|
+
"@parcel/types-internal": "2.12.1-dev.3185+298c035e0",
|
|
29
30
|
"chrome-trace-event": "^1.0.2"
|
|
30
31
|
},
|
|
31
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "298c035e0ffb82d7c5579ce233cc35dce2fe1061"
|
|
32
33
|
}
|
package/src/Tracer.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import type {
|
|
4
4
|
TraceEvent,
|
|
5
5
|
IDisposable,
|
|
6
|
+
MeasurementOptions,
|
|
6
7
|
PluginTracer as IPluginTracer,
|
|
7
8
|
} from '@parcel/types';
|
|
8
9
|
import type {
|
|
@@ -64,44 +65,44 @@ export default class Tracer {
|
|
|
64
65
|
return this.#traceEmitter.addListener(cb);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
measure<T>(
|
|
69
|
+
{args = {}, categories, name}: MeasurementOptions,
|
|
70
|
+
fn: () => T,
|
|
71
|
+
): T {
|
|
72
|
+
if (!this.enabled) {
|
|
73
|
+
return fn();
|
|
73
74
|
}
|
|
74
|
-
}
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
otherArgs?: {[key: string]: mixed},
|
|
81
|
-
): ITraceMeasurement | null {
|
|
82
|
-
if (!this.enabled) return null;
|
|
76
|
+
let measurement = new TraceMeasurement(this, name, pid, tid, {
|
|
77
|
+
categories,
|
|
78
|
+
args,
|
|
79
|
+
});
|
|
83
80
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
81
|
+
let result: T;
|
|
82
|
+
let hasFinally = false;
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
result = fn();
|
|
86
|
+
// @ts-expect-error TypeScript types cannot infer that finally can exist
|
|
87
|
+
if (
|
|
88
|
+
result != null &&
|
|
89
|
+
typeof result === 'object' &&
|
|
90
|
+
typeof result.finally === 'function'
|
|
91
|
+
) {
|
|
92
|
+
hasFinally = true;
|
|
93
|
+
// @ts-expect-error
|
|
94
|
+
// $FlowFixMe[incompatible-use] This will run for a promise type, but it cannot be easily typed in Flow
|
|
95
|
+
result = result.finally(() => {
|
|
96
|
+
measurement?.end();
|
|
97
|
+
});
|
|
93
98
|
}
|
|
94
|
-
|
|
95
|
-
|
|
99
|
+
} finally {
|
|
100
|
+
if (!hasFinally) {
|
|
101
|
+
measurement?.end();
|
|
96
102
|
}
|
|
97
103
|
}
|
|
98
104
|
|
|
99
|
-
|
|
100
|
-
categories: [category],
|
|
101
|
-
args,
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
return new TraceMeasurement(this, name, pid, tid, data);
|
|
105
|
+
return result;
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
get enabled(): boolean {
|
|
@@ -128,6 +129,7 @@ type TracerOpts = {|
|
|
|
128
129
|
origin: string,
|
|
129
130
|
category: string,
|
|
130
131
|
|};
|
|
132
|
+
|
|
131
133
|
export class PluginTracer implements IPluginTracer {
|
|
132
134
|
/** @private */
|
|
133
135
|
origin: string;
|
|
@@ -151,13 +153,51 @@ export class PluginTracer implements IPluginTracer {
|
|
|
151
153
|
argumentName?: string,
|
|
152
154
|
otherArgs?: {[key: string]: mixed},
|
|
153
155
|
): ITraceMeasurement | null {
|
|
154
|
-
return
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
156
|
+
if (!this.enabled) return null;
|
|
157
|
+
|
|
158
|
+
// We create `args` in a fairly verbose way to avoid object
|
|
159
|
+
// allocation where not required.
|
|
160
|
+
let args: {[key: string]: mixed};
|
|
161
|
+
if (typeof argumentName === 'string') {
|
|
162
|
+
args = {name: argumentName};
|
|
163
|
+
}
|
|
164
|
+
if (typeof otherArgs === 'object') {
|
|
165
|
+
if (typeof args == 'undefined') {
|
|
166
|
+
args = {};
|
|
167
|
+
}
|
|
168
|
+
for (const [k, v] of Object.entries(otherArgs)) {
|
|
169
|
+
args[k] = v;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const data: TraceMeasurementData = {
|
|
174
|
+
categories: [
|
|
175
|
+
`${this.category}:${this.origin}${
|
|
176
|
+
typeof category === 'string' ? `:${category}` : ''
|
|
177
|
+
}`,
|
|
178
|
+
],
|
|
179
|
+
args,
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
return new TraceMeasurement(tracer, name, pid, tid, data);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
measure<T>(options: MeasurementOptions, fn: () => T): T {
|
|
186
|
+
if (!this.enabled) {
|
|
187
|
+
return fn();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return tracer.measure(
|
|
191
|
+
{
|
|
192
|
+
...options,
|
|
193
|
+
// $FlowFixMe[cannot-spread-inexact]
|
|
194
|
+
args: {
|
|
195
|
+
origin: this.origin,
|
|
196
|
+
...(options.args ?? {}),
|
|
197
|
+
},
|
|
198
|
+
categories: [this.category, ...options.categories],
|
|
199
|
+
},
|
|
200
|
+
fn,
|
|
161
201
|
);
|
|
162
202
|
}
|
|
163
203
|
}
|
package/src/types.js
CHANGED
package/test/Tracer.test.js
CHANGED
|
@@ -5,74 +5,123 @@ import assert from 'assert';
|
|
|
5
5
|
describe('Tracer', () => {
|
|
6
6
|
let onTrace;
|
|
7
7
|
let traceDisposable;
|
|
8
|
+
let opts = {name: 'test', categories: ['tracer']};
|
|
9
|
+
|
|
8
10
|
beforeEach(() => {
|
|
9
11
|
onTrace = sinon.spy();
|
|
10
12
|
traceDisposable = tracer.onTrace(onTrace);
|
|
11
13
|
tracer.enable();
|
|
12
14
|
});
|
|
15
|
+
|
|
13
16
|
afterEach(() => {
|
|
14
17
|
traceDisposable.dispose();
|
|
15
18
|
});
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
20
|
+
describe('measure()', () => {
|
|
21
|
+
let cases = [
|
|
22
|
+
['synchronous', () => () => {}],
|
|
23
|
+
['asynchronous', () => async () => {}],
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
for (let [type, createFn] of cases) {
|
|
27
|
+
describe(`given a ${type} function`, () => {
|
|
28
|
+
it('does not trace when disabled', async () => {
|
|
29
|
+
tracer.disable();
|
|
30
|
+
|
|
31
|
+
let result = tracer.measure(opts, sinon.spy());
|
|
32
|
+
if (type === 'asynchronous') {
|
|
33
|
+
sinon.assert.notCalled(onTrace);
|
|
34
|
+
await result;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
assert(onTrace.notCalled);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('emits a basic trace event', async () => {
|
|
41
|
+
let result = tracer.measure(opts, createFn());
|
|
42
|
+
if (type === 'asynchronous') {
|
|
43
|
+
sinon.assert.notCalled(onTrace);
|
|
44
|
+
await result;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
sinon.assert.calledOnce(onTrace);
|
|
48
|
+
sinon.assert.calledWith(
|
|
49
|
+
onTrace,
|
|
50
|
+
sinon.match({
|
|
51
|
+
type: 'trace',
|
|
52
|
+
name: 'test',
|
|
53
|
+
args: {},
|
|
54
|
+
categories: ['tracer'],
|
|
55
|
+
duration: sinon.match.number,
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('emits a complex trace event', async () => {
|
|
61
|
+
let result = tracer.measure(
|
|
62
|
+
{...opts, args: {hello: 'world'}},
|
|
63
|
+
createFn(),
|
|
64
|
+
);
|
|
65
|
+
if (type === 'asynchronous') {
|
|
66
|
+
sinon.assert.notCalled(onTrace);
|
|
67
|
+
await result;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
sinon.assert.calledOnce(onTrace);
|
|
71
|
+
sinon.assert.calledWith(
|
|
72
|
+
onTrace,
|
|
73
|
+
sinon.match({
|
|
74
|
+
type: 'trace',
|
|
75
|
+
name: 'test',
|
|
76
|
+
args: {hello: 'world'},
|
|
77
|
+
categories: ['tracer'],
|
|
78
|
+
duration: sinon.match.number,
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
57
84
|
});
|
|
58
85
|
|
|
59
86
|
describe('PluginTracer', () => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
87
|
+
const pluginTracer = new PluginTracer({
|
|
88
|
+
origin: 'origin',
|
|
89
|
+
category: 'cat',
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe(`measure()`, () => {
|
|
93
|
+
it('emits events with origin and category', () => {
|
|
94
|
+
pluginTracer.measure(opts, sinon.spy());
|
|
95
|
+
|
|
96
|
+
sinon.assert.calledOnce(onTrace);
|
|
97
|
+
sinon.assert.calledWith(
|
|
98
|
+
onTrace,
|
|
99
|
+
sinon.match({
|
|
100
|
+
type: 'trace',
|
|
101
|
+
name: 'test',
|
|
102
|
+
args: {origin: 'origin'},
|
|
103
|
+
categories: ['cat', 'tracer'],
|
|
104
|
+
duration: sinon.match.number,
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('createMeasurement()', () => {
|
|
111
|
+
it('emits events with origin and category', () => {
|
|
112
|
+
pluginTracer.createMeasurement('test', 'customCat').end();
|
|
113
|
+
|
|
114
|
+
sinon.assert.calledOnce(onTrace);
|
|
115
|
+
sinon.assert.calledWith(
|
|
116
|
+
onTrace,
|
|
117
|
+
sinon.match({
|
|
118
|
+
type: 'trace',
|
|
119
|
+
name: 'test',
|
|
120
|
+
categories: ['cat:origin:customCat'],
|
|
121
|
+
duration: sinon.match.number,
|
|
122
|
+
}),
|
|
123
|
+
);
|
|
64
124
|
});
|
|
65
|
-
const measurement = pluginTracer.createMeasurement('test', 'customCat');
|
|
66
|
-
measurement.end();
|
|
67
|
-
sinon.assert.calledWith(
|
|
68
|
-
onTrace,
|
|
69
|
-
sinon.match({
|
|
70
|
-
type: 'trace',
|
|
71
|
-
name: 'test',
|
|
72
|
-
categories: ['cat:origin:customCat'],
|
|
73
|
-
duration: sinon.match.number,
|
|
74
|
-
}),
|
|
75
|
-
);
|
|
76
125
|
});
|
|
77
126
|
});
|
|
78
127
|
});
|