11import process from 'node:process'
22
33export interface HmrTimingDetails {
4+ emit ?: boolean
45 file ?: string
6+ hooks ?: Record < string , HmrTimingHookSummary >
7+ metric ?: 'hook' | 'total'
8+ wallMs ?: number
9+ }
10+
11+ export interface HmrTimingHookSummary {
12+ count : number
13+ durationMs : number
14+ maxMs : number
15+ }
16+
17+ type HmrTimingBundler = 'vite' | 'webpack' | 'gulp'
18+
19+ interface HmrTimingSession {
20+ hooks : Record < string , HmrTimingHookSummary >
21+ startedAt ?: number
22+ totalMs : number
23+ }
24+
25+ export interface HmrTimingRecorder {
26+ emitTotal : ( phase ?: string ) => void
27+ measure : < T > ( phase : string , task : ( ) => T | Promise < T > , details ?: HmrTimingDetails ) => Promise < T >
28+ record : ( phase : string , durationMs : number , details ?: HmrTimingDetails ) => void
529}
630
731export function shouldEmitHmrTiming ( ) {
@@ -15,7 +39,7 @@ function shouldEmitHumanReadableTiming() {
1539}
1640
1741export function emitHmrTiming (
18- bundler : 'vite' | 'webpack' | 'gulp' ,
42+ bundler : HmrTimingBundler ,
1943 phase : string ,
2044 durationMs : number ,
2145 details : HmrTimingDetails = { } ,
@@ -24,15 +48,83 @@ export function emitHmrTiming(
2448 return
2549 }
2650
51+ const serializableDetails = { ...details }
52+ delete serializableDetails . emit
2753 const payload = {
2854 bundler,
2955 phase,
3056 durationMs : Math . max ( 0 , Math . round ( durationMs ) ) ,
31- ...details ,
57+ ...serializableDetails ,
58+ ...( typeof details . wallMs === 'number' ? { wallMs : Math . max ( 0 , Math . round ( details . wallMs ) ) } : { } ) ,
3259 }
3360 process . stdout . write ( `[weapp-tailwindcss:hmr] ${ JSON . stringify ( payload ) } \n` )
3461 if ( shouldEmitHumanReadableTiming ( ) ) {
3562 const fileSuffix = details . file ? ` file=${ details . file } ` : ''
63+ if ( details . metric === 'total' ) {
64+ const hooks = details . hooks
65+ ? Object . entries ( details . hooks )
66+ . map ( ( [ hook , summary ] ) => `${ hook } =${ Math . max ( 0 , Math . round ( summary . durationMs ) ) } ms/${ summary . count } ` )
67+ . join ( ', ' )
68+ : ''
69+ const hookSuffix = hooks ? ` (${ hooks } )` : ''
70+ const wallSuffix = typeof payload . wallMs === 'number' ? ` wall=${ payload . wallMs } ms` : ''
71+ process . stdout . write ( `[weapp-tailwindcss] ${ bundler } :weapp-tailwindcss 总耗时 ${ payload . durationMs } ms${ wallSuffix } ${ hookSuffix } \n` )
72+ return
73+ }
3674 process . stdout . write ( `[weapp-tailwindcss] ${ bundler } :${ phase } 耗时 ${ payload . durationMs } ms${ fileSuffix } \n` )
3775 }
3876}
77+
78+ export function createHmrTimingRecorder ( bundler : HmrTimingBundler ) : HmrTimingRecorder {
79+ const session : HmrTimingSession = {
80+ hooks : { } ,
81+ totalMs : 0 ,
82+ }
83+
84+ const record = ( phase : string , durationMs : number , details : HmrTimingDetails = { } ) => {
85+ const roundedDuration = Math . max ( 0 , Math . round ( durationMs ) )
86+ if ( session . startedAt === undefined ) {
87+ session . startedAt = performance . now ( ) - Math . max ( 0 , durationMs )
88+ }
89+ session . totalMs += Math . max ( 0 , durationMs )
90+ const current = session . hooks [ phase ] ?? { count : 0 , durationMs : 0 , maxMs : 0 }
91+ current . count += 1
92+ current . durationMs += roundedDuration
93+ current . maxMs = Math . max ( current . maxMs , roundedDuration )
94+ session . hooks [ phase ] = current
95+ if ( details . emit !== false ) {
96+ emitHmrTiming ( bundler , phase , durationMs , details )
97+ }
98+ }
99+
100+ const measure = async < T > ( phase : string , task : ( ) => T | Promise < T > , details : HmrTimingDetails = { } ) => {
101+ const startedAt = performance . now ( )
102+ try {
103+ return await task ( )
104+ }
105+ finally {
106+ record ( phase , performance . now ( ) - startedAt , details )
107+ }
108+ }
109+
110+ const emitTotal = ( phase = 'total' ) => {
111+ if ( session . totalMs <= 0 ) {
112+ return
113+ }
114+ const wallMs = session . startedAt === undefined ? session . totalMs : performance . now ( ) - session . startedAt
115+ emitHmrTiming ( bundler , phase , session . totalMs , {
116+ hooks : session . hooks ,
117+ metric : 'total' ,
118+ wallMs,
119+ } )
120+ session . hooks = { }
121+ delete session . startedAt
122+ session . totalMs = 0
123+ }
124+
125+ return {
126+ emitTotal,
127+ measure,
128+ record,
129+ }
130+ }
0 commit comments