Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions packages/devtools/src/node/rolldown/events-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export type RolldownEvent = Event & {
event_id: string
}

type ModuleBuildHookEvents = Exclude<Event, 'StringRef'> & (HookResolveIdCallStart | HookResolveIdCallEnd | HookLoadCallStart | HookLoadCallEnd | HookTransformCallStart | HookTransformCallEnd)
type ModuleBuildHookEvents = (Exclude<Event, 'StringRef'> & (HookResolveIdCallStart | HookResolveIdCallEnd | HookLoadCallStart | HookLoadCallEnd | HookTransformCallStart | HookTransformCallEnd)) & { event_id: string }

const DURATION_THRESHOLD = 10
const MODULE_BUILD_START_HOOKS = ['HookResolveIdCallStart', 'HookLoadCallStart', 'HookTransformCallStart']
Expand Down Expand Up @@ -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
Expand All @@ -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!),
})
Expand Down
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -15,79 +13,24 @@ export const rolldownGetModuleInfo = defineRpcFunction({
if (!events.length)
return null

const moduleInfo = reader.manager.modules.get(module)

const info: Omit<ModuleInfo, 'transforms'> = {
id: module,
loads: [],
imports: [],
importers: [],
resolve_ids: [],
chunks: [],
assets: [],
build_metrics: {
resolve_ids: [],
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 => ({
Expand Down
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -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<RolldownModuleTransformInfo>(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)
},
}
},
Expand Down
10 changes: 5 additions & 5 deletions packages/devtools/src/shared/types/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Omit<RolldownModuleTransformInfo, 'diff_added' | 'diff_removed'> & { source_code_size: number, transformed_code_size: number }>
}
export type { PluginItem }

Expand Down
Loading