1/*@internal*/ 2namespace ts { 3 // The following definitions provide the minimum compatible support for the Web Performance User Timings API 4 // between browsers and NodeJS: 5 6 export interface PerformanceHooks { 7 /** Indicates whether we should write native performance events */ 8 shouldWriteNativeEvents: boolean; 9 performance: Performance; 10 PerformanceObserver: PerformanceObserverConstructor; 11 } 12 13 export interface Performance { 14 mark(name: string): void; 15 measure(name: string, startMark?: string, endMark?: string): void; 16 now(): number; 17 timeOrigin: number; 18 } 19 20 export interface PerformanceEntry { 21 name: string; 22 entryType: string; 23 startTime: number; 24 duration: number; 25 } 26 27 export interface PerformanceObserverEntryList { 28 getEntries(): PerformanceEntryList; 29 getEntriesByName(name: string, type?: string): PerformanceEntryList; 30 getEntriesByType(type: string): PerformanceEntryList; 31 } 32 33 export interface PerformanceObserver { 34 disconnect(): void; 35 observe(options: { entryTypes: readonly string[] }): void; 36 } 37 38 export type PerformanceObserverConstructor = new (callback: (list: PerformanceObserverEntryList, observer: PerformanceObserver) => void) => PerformanceObserver; 39 export type PerformanceEntryList = PerformanceEntry[]; 40 41 // Browser globals for the Web Performance User Timings API 42 declare const process: any; 43 declare const performance: Performance | undefined; 44 declare const PerformanceObserver: PerformanceObserverConstructor | undefined; 45 46 // eslint-disable-next-line @typescript-eslint/naming-convention 47 function hasRequiredAPI(performance: Performance | undefined, PerformanceObserver: PerformanceObserverConstructor | undefined) { 48 return typeof performance === "object" && 49 typeof performance.timeOrigin === "number" && 50 typeof performance.mark === "function" && 51 typeof performance.measure === "function" && 52 typeof performance.now === "function" && 53 typeof PerformanceObserver === "function"; 54 } 55 56 function tryGetWebPerformanceHooks(): PerformanceHooks | undefined { 57 if (typeof performance === "object" && 58 typeof PerformanceObserver === "function" && 59 hasRequiredAPI(performance, PerformanceObserver)) { 60 return { 61 // For now we always write native performance events when running in the browser. We may 62 // make this conditional in the future if we find that native web performance hooks 63 // in the browser also slow down compilation. 64 shouldWriteNativeEvents: true, 65 performance, 66 PerformanceObserver 67 }; 68 } 69 } 70 71 function tryGetNodePerformanceHooks(): PerformanceHooks | undefined { 72 if (typeof process !== "undefined" && process.nextTick && !process.browser && typeof module === "object" && typeof require === "function") { 73 try { 74 let performance: Performance; 75 const { performance: nodePerformance, PerformanceObserver } = require("perf_hooks") as typeof import("perf_hooks"); 76 if (hasRequiredAPI(nodePerformance, PerformanceObserver)) { 77 performance = nodePerformance; 78 // There is a bug in Node's performance.measure prior to 12.16.3/13.13.0 that does not 79 // match the Web Performance API specification. Node's implementation did not allow 80 // optional `start` and `end` arguments for `performance.measure`. 81 // See https://github.com/nodejs/node/pull/32651 for more information. 82 const version = new Version(process.versions.node); 83 const range = new VersionRange("<12.16.3 || 13 <13.13"); 84 if (range.test(version)) { 85 performance = { 86 get timeOrigin() { return nodePerformance.timeOrigin; }, 87 now() { return nodePerformance.now(); }, 88 mark(name) { return nodePerformance.mark(name); }, 89 measure(name, start = "nodeStart", end?) { 90 if (end === undefined) { 91 end = "__performance.measure-fix__"; 92 nodePerformance.mark(end); 93 } 94 nodePerformance.measure(name, start, end); 95 if (end === "__performance.measure-fix__") { 96 nodePerformance.clearMarks("__performance.measure-fix__"); 97 } 98 } 99 }; 100 } 101 return { 102 // By default, only write native events when generating a cpu profile or using the v8 profiler. 103 shouldWriteNativeEvents: false, 104 performance, 105 PerformanceObserver 106 }; 107 } 108 } 109 catch { 110 // ignore errors 111 } 112 } 113 } 114 115 // Unlike with the native Map/Set 'tryGet' functions in corePublic.ts, we eagerly evaluate these 116 // since we will need them for `timestamp`, below. 117 const nativePerformanceHooks = tryGetWebPerformanceHooks() || tryGetNodePerformanceHooks(); 118 const nativePerformance = nativePerformanceHooks?.performance; 119 120 export function tryGetNativePerformanceHooks() { 121 return nativePerformanceHooks; 122 } 123 124 /** Gets a timestamp with (at least) ms resolution */ 125 export const timestamp = 126 nativePerformance ? () => nativePerformance.now() : 127 Date.now ? Date.now : 128 () => +(new Date()); 129}