diff --git a/packages/devtools/src/node/rolldown/events-manager.ts b/packages/devtools/src/node/rolldown/events-manager.ts index 3e460cc6..201e4b5f 100644 --- a/packages/devtools/src/node/rolldown/events-manager.ts +++ b/packages/devtools/src/node/rolldown/events-manager.ts @@ -6,7 +6,7 @@ export type RolldownEvent = Event & { event_id: string } -type ModuleBuildHookEvents = Exclude & (HookResolveIdCallStart | HookResolveIdCallEnd | HookLoadCallStart | HookLoadCallEnd | HookTransformCallStart | HookTransformCallEnd) +type ModuleBuildHookEvents = (Exclude & (HookResolveIdCallStart | HookResolveIdCallEnd | HookLoadCallStart | HookLoadCallEnd | HookTransformCallStart | HookTransformCallEnd)) & { event_id: string } const DURATION_THRESHOLD = 10 const MODULE_BUILD_START_HOOKS = ['HookResolveIdCallStart', 'HookLoadCallStart', 'HookTransformCallStart'] @@ -43,21 +43,33 @@ export class RolldownEventsManager { const module_id = event.action === 'HookResolveIdCallEnd' ? event.resolved_id! : (event as HookLoadCallEnd | HookTransformCallEnd).module_id if (start) { const info = { - start_time: +start.timestamp, - end_time: +event.timestamp, + id: event.event_id, + timestamp_start: +start.timestamp, + timestamp_end: +event.timestamp, duration: +event.timestamp - +start.timestamp, plugin_id: event.plugin_id, plugin_name: event.plugin_name, } const module_build_metrics = this.module_build_metrics.get(module_id) ?? { resolve_ids: [], loads: [], transforms: [] } if (event.action === 'HookResolveIdCallEnd') { - module_build_metrics.resolve_ids.push(info) + module_build_metrics.resolve_ids.push({ + ...info, + type: 'resolve', + importer: (start as HookResolveIdCallStart).importer, + module_request: (start as HookResolveIdCallStart).module_request, + import_kind: (start as HookResolveIdCallStart).import_kind, + resolved_id: event.resolved_id, + }) } else if (event.action === 'HookLoadCallEnd') { if (!event.content && info.duration < DURATION_THRESHOLD) { return } - module_build_metrics.loads.push(info) + module_build_metrics.loads.push({ + ...info, + type: 'load', + content: event.content, + }) } else if (event.action === 'HookTransformCallEnd') { const _start = start as HookTransformCallStart @@ -69,6 +81,9 @@ export class RolldownEventsManager { module_build_metrics.transforms.push({ ...info, + type: 'transform', + content_from: _start.content, + content_to: _end.content, source_code_size: getContentByteSize(_start.content!), transformed_code_size: getContentByteSize(_end.content!), }) diff --git a/packages/devtools/src/node/rpc/functions/rolldown-get-module-info.ts b/packages/devtools/src/node/rpc/functions/rolldown-get-module-info.ts index e0bebe1b..6bfe216f 100644 --- a/packages/devtools/src/node/rpc/functions/rolldown-get-module-info.ts +++ b/packages/devtools/src/node/rpc/functions/rolldown-get-module-info.ts @@ -1,8 +1,6 @@ -import type { ModuleInfo, RolldownResolveInfo } from '../../../shared/types' +import type { ModuleInfo } from '../../../shared/types' import { defineRpcFunction } from '../utils' -const DURATION_THRESHOLD = 10 - export const rolldownGetModuleInfo = defineRpcFunction({ name: 'vite:rolldown:get-module-info', type: 'query', @@ -15,12 +13,12 @@ export const rolldownGetModuleInfo = defineRpcFunction({ if (!events.length) return null + const moduleInfo = reader.manager.modules.get(module) + const info: Omit = { id: module, - loads: [], imports: [], importers: [], - resolve_ids: [], chunks: [], assets: [], build_metrics: { @@ -28,66 +26,11 @@ export const rolldownGetModuleInfo = defineRpcFunction({ loads: [], transforms: [], }, - ...reader.manager.modules.get(module) || {}, + ...moduleInfo || {}, + loads: moduleInfo?.build_metrics?.loads ?? [], + resolve_ids: moduleInfo?.build_metrics?.resolve_ids ?? [], } - events.forEach((start, index) => { - if (start.action !== 'HookLoadCallStart' || start.module_id !== module) - return - - const end = events.find(e => e.action === 'HookLoadCallEnd' && e.call_id === start.call_id, index) - if (!end || end.action !== 'HookLoadCallEnd') { - console.error(`[rolldown] Load call end not found for ${start.call_id}`) - return - } - const duration = +end.timestamp - +start.timestamp - if (!end.content && duration < DURATION_THRESHOLD) - return - - info.loads.push({ - type: 'load', - id: start.event_id, - plugin_name: start.plugin_name, - plugin_id: start.plugin_id, - content: end.content, - timestamp_start: +start.timestamp, - timestamp_end: +end.timestamp, - duration, - }) - }) - - events.forEach((end) => { - if (end.action !== 'HookResolveIdCallEnd' || end.resolved_id !== module) - return - const start = events.find(e => e.action === 'HookResolveIdCallStart' && e.call_id === end.call_id) - if (!start || start.action !== 'HookResolveIdCallStart') { - console.error(`[rolldown] resolveId call start not found for ${end.event_id}`) - return - } - - const duration = +end.timestamp - +start.timestamp - const data: RolldownResolveInfo = { - type: 'resolve', - id: end.event_id, - importer: start.importer, - module_request: start.module_request, - import_kind: start.import_kind, - plugin_name: end.plugin_name, - plugin_id: end.plugin_id, - resolved_id: end.resolved_id, - timestamp_start: +start.timestamp, - timestamp_end: +end.timestamp, - duration, - } - - // In Rolldown, resolveId might be called multiple times with different threads of Rust - // If that happens, we only keep the last one - const existingIndex = info.resolve_ids.findIndex(r => r.importer === start.importer && r.module_request === start.module_request && r.import_kind === start.import_kind && r.plugin_id === end.plugin_id) - if (existingIndex >= 0) - info.resolve_ids.splice(existingIndex, 1) - info.resolve_ids.push(data) - }) - info.chunks = Array.from(reader.manager.chunks.values()) .filter(chunk => chunk.modules.includes(module)) .map(chunk => ({ diff --git a/packages/devtools/src/node/rpc/functions/rolldown-get-module-transforms.ts b/packages/devtools/src/node/rpc/functions/rolldown-get-module-transforms.ts index 0b8d5111..66c22cd1 100644 --- a/packages/devtools/src/node/rpc/functions/rolldown-get-module-transforms.ts +++ b/packages/devtools/src/node/rpc/functions/rolldown-get-module-transforms.ts @@ -1,9 +1,7 @@ -import type { RolldownModuleTransformInfo } from '../../../shared/types' +import type { RolldownModuleTransformInfo } from '~~/shared/types' import { diffLines } from 'diff' import { defineRpcFunction } from '../utils' -const DURATION_THRESHOLD = 10 - export const rolldownGetModuleTransforms = defineRpcFunction({ name: 'vite:rolldown:get-module-transforms', type: 'query', @@ -12,48 +10,33 @@ export const rolldownGetModuleTransforms = defineRpcFunction({ handler: async ({ session, module }: { session: string, module: string }) => { const reader = await manager.loadSession(session) const events = reader.manager.events - const transforms: RolldownModuleTransformInfo[] = [] - - if (!events.length) - return transforms - - events.forEach((start, index) => { - if (start.action !== 'HookTransformCallStart' || start.module_id !== module) - return - - const end = events.find(e => e.action === 'HookTransformCallEnd' && e.call_id === start.call_id, index) - if (!end || end.action !== 'HookTransformCallEnd') { - console.error(`[rolldown] Transform call end not found for ${start.event_id}`) - return - } - const duration = +end.timestamp - +start.timestamp - if (end.content === start.content && duration < DURATION_THRESHOLD) - return - + const moduleInfo = reader.manager.modules.get(module) + const transforms = moduleInfo?.build_metrics?.transforms ?? [] + + if (!events.length) { + return transforms.map(transform => ({ + ...transform, + diff_added: 0, + diff_removed: 0, + })) + } + + const normalizedTransforms: RolldownModuleTransformInfo[] = transforms.map((transform) => { let diff_added = 0 let diff_removed = 0 - if (start.content !== end.content && start.content != null && end.content != null) { - const delta = diffLines(start.content, end.content) + if (transform.content_from !== transform.content_to && transform.content_from != null && transform.content_to != null) { + const delta = diffLines(transform.content_from, transform.content_to) diff_added = delta.filter(d => d.added).map(d => d.value).join('').split(/\n/g).length diff_removed = delta.filter(d => d.removed).map(d => d.value).join('').split(/\n/g).length } - - transforms.push({ - type: 'transform', - id: start.event_id, - plugin_name: start.plugin_name, - plugin_id: start.plugin_id, - content_from: start.content, - content_to: end.content, + return { + ...transform, diff_added, diff_removed, - timestamp_start: +start.timestamp, - timestamp_end: +end.timestamp, - duration, - }) + } }) - return transforms.sort((a, b) => a.plugin_id - b.plugin_id) + return normalizedTransforms.sort((a, b) => a.plugin_id - b.plugin_id) }, } }, diff --git a/packages/devtools/src/shared/types/data.ts b/packages/devtools/src/shared/types/data.ts index 62c617ce..da66e12f 100644 --- a/packages/devtools/src/shared/types/data.ts +++ b/packages/devtools/src/shared/types/data.ts @@ -8,14 +8,14 @@ export interface BuildMetrics { duration: number source_code_size?: number transformed_code_size?: number - start_time: number - end_time: number + timestamp_start: number + timestamp_end: number } export interface ModuleBuildMetrics { - resolve_ids: BuildMetrics[] - loads: BuildMetrics[] - transforms: BuildMetrics[] + resolve_ids: RolldownResolveInfo[] + loads: RolldownModuleLoadInfo[] + transforms: Array & { source_code_size: number, transformed_code_size: number }> } export type { PluginItem }