@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 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
- wrap(name: string, fn: () => unknown): Promise<void>;
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
- async wrap(name, fn) {
66
- let measurement = this.createMeasurement(name);
67
- try {
68
- await fn();
69
- } finally {
70
- measurement && measurement.end();
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
- if (typeof otherArgs === 'object') {
85
- if (typeof args == 'undefined') {
86
- args = {};
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
- for (const [k, v] of Object.entries(otherArgs)) {
89
- args[k] = v;
90
+ } finally {
91
+ if (!hasFinally) {
92
+ measurement === null || measurement === void 0 || measurement.end();
90
93
  }
91
94
  }
92
- const data = {
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
- return tracer.createMeasurement(name, `${this.category}:${this.origin}${typeof category === 'string' ? `:${category}` : ''}`, argumentName, otherArgs);
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
@@ -1,6 +1,4 @@
1
- export interface TraceMeasurement {
2
- end(): void;
3
- }
1
+ export type { TraceMeasurement } from "@parcel/types-internal";
4
2
  export type TraceMeasurementData = {
5
3
  readonly categories: string[];
6
4
  readonly args?: Record<string, unknown>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parcel/profiler",
3
- "version": "2.12.1-dev.3151+70889ca07",
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.1528+70889ca07",
28
- "@parcel/events": "2.0.0-dev.1528+70889ca07",
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": "70889ca07dccb95e21e4c6a2844d632e3723faf4"
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
- async wrap(name: string, fn: () => mixed): Promise<void> {
68
- let measurement = this.createMeasurement(name);
69
- try {
70
- await fn();
71
- } finally {
72
- measurement && measurement.end();
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
- createMeasurement(
77
- name: string,
78
- category: string = 'Core',
79
- argumentName?: string,
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
- // We create `args` in a fairly verbose way to avoid object
85
- // allocation where not required.
86
- let args: {[key: string]: mixed};
87
- if (typeof argumentName === 'string') {
88
- args = {name: argumentName};
89
- }
90
- if (typeof otherArgs === 'object') {
91
- if (typeof args == 'undefined') {
92
- args = {};
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
- for (const [k, v] of Object.entries(otherArgs)) {
95
- args[k] = v;
99
+ } finally {
100
+ if (!hasFinally) {
101
+ measurement?.end();
96
102
  }
97
103
  }
98
104
 
99
- const data: TraceMeasurementData = {
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 tracer.createMeasurement(
155
- name,
156
- `${this.category}:${this.origin}${
157
- typeof category === 'string' ? `:${category}` : ''
158
- }`,
159
- argumentName,
160
- otherArgs,
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
@@ -1,8 +1,6 @@
1
1
  // @flow
2
2
 
3
- export interface TraceMeasurement {
4
- end(): void;
5
- }
3
+ export type {TraceMeasurement} from '@parcel/types-internal';
6
4
 
7
5
  export type TraceMeasurementData = {|
8
6
  +categories: string[],
@@ -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
- it('returns no measurement when disabled', () => {
18
- tracer.disable();
19
- const measurement = tracer.createMeasurement('test');
20
- assert(measurement == null);
21
- assert(onTrace.notCalled);
22
- });
23
- it('emits a basic trace event', () => {
24
- const measurement = tracer.createMeasurement('test');
25
- measurement.end();
26
- sinon.assert.calledWith(
27
- onTrace,
28
- sinon.match({
29
- type: 'trace',
30
- name: 'test',
31
- args: undefined,
32
- duration: sinon.match.number,
33
- }),
34
- );
35
- });
36
- it('emits a complex trace event', () => {
37
- const measurement = tracer.createMeasurement('test', 'myPlugin', 'aaargh', {
38
- extra: 'data',
39
- });
40
- measurement.end();
41
- sinon.assert.calledWith(
42
- onTrace,
43
- sinon.match({
44
- type: 'trace',
45
- name: 'test',
46
- categories: ['myPlugin'],
47
- args: {extra: 'data', name: 'aaargh'},
48
- duration: sinon.match.number,
49
- }),
50
- );
51
- });
52
- it('calling end twice on measurment should be a no-op', () => {
53
- const measurement = tracer.createMeasurement('test');
54
- measurement.end();
55
- measurement.end();
56
- sinon.assert.calledOnce(onTrace);
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
- it('emits events with proper origin/category', () => {
61
- const pluginTracer = new PluginTracer({
62
- origin: 'origin',
63
- category: 'cat',
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
  });