Skip to content

Commit 31c99e3

Browse files
committed
feat: some basic idea of new UI style
1 parent 7351b65 commit 31c99e3

File tree

9 files changed

+266
-10
lines changed

9 files changed

+266
-10
lines changed

packages/devtools/src/app/components/display/ModuleId.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,8 @@ const gridStyles = computed(() => {
131131
132132
// todo: handle slot, not being used
133133
134-
if (isVirtual.value)
135-
gridColumns.push('min-content')
134+
// if (isVirtual.value)
135+
// gridColumns.push('min-content')
136136
137137
return `grid-template-columns: ${gridColumns.join(' ')};`
138138
})
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<script setup lang="ts">
2+
const props = defineProps<{
3+
lines?: {
4+
top?: boolean
5+
bottom?: boolean
6+
}
7+
classNodeOuter?: string
8+
classNodeInner?: string
9+
}>()
10+
</script>
11+
12+
<template>
13+
<div flex="~ col" relative>
14+
<div v-if="props.lines?.top" absolute top-0 left-10 border="r base" h="1/2" max-h-4 z-flowmap-line />
15+
<div v-if="props.lines?.bottom" absolute bottom-0 left-10 border="r base" h="1/2" max-h-4 z-flowmap-line />
16+
<slot name="before" />
17+
<div flex="~">
18+
<div :class="props.classNodeOuter" border="~ base rounded-full" bg-base>
19+
<div px3 py1 :class="props.classNodeInner" flex="~ inline gap-2 items-center">
20+
<slot name="content" />
21+
</div>
22+
</div>
23+
<slot name="inline-after" />
24+
</div>
25+
<slot name="after" />
26+
</div>
27+
</template>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script setup lang="ts">
2+
import { useRoute } from '#app/composables/router'
3+
import { useAsyncState } from '@vueuse/core'
4+
import { backend } from '../../../state/backend'
5+
6+
const params = useRoute().params as {
7+
build: string
8+
}
9+
const query = useRoute().query
10+
11+
const events = useAsyncState(
12+
async () => {
13+
return await backend.value!.functions['vite:rolldown:get-module-raw-events']?.({
14+
build: params.build as string,
15+
module: query.module as string,
16+
})
17+
},
18+
{
19+
events: [],
20+
},
21+
)
22+
</script>
23+
24+
<template>
25+
<div>
26+
<DataRawEventsTable v-if="events.state.value" :events="events.state.value.events" />
27+
</div>
28+
</template>

packages/devtools/src/app/pages/build/[build]/transform.vue

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,103 @@ const params = useRoute().params as {
88
}
99
const query = useRoute().query
1010
11-
const events = useAsyncState(
11+
const { state: info } = useAsyncState(
1212
async () => {
1313
return await backend.value!.functions['vite:rolldown:get-module-info']?.({
1414
build: params.build as string,
1515
module: query.module as string,
1616
})
1717
},
18-
{
19-
events: [],
20-
},
18+
null,
2119
)
2220
</script>
2321

2422
<template>
25-
<div>
26-
<DataRawEventsTable v-if="events.state.value" :events="events.state.value.events" />
23+
<div v-if="info" p4>
24+
<FlowmapNode :lines="{ bottom: true }" py2>
25+
<template #content>
26+
<div p2>
27+
<DisplayModuleId :id="(query.module as string)" />
28+
</div>
29+
</template>
30+
</FlowmapNode>
31+
32+
<FlowmapNode :lines="{ top: true, bottom: true }" pl4 py2>
33+
<template #content>
34+
<div i-ph-magnifying-glass-duotone /> Resolve Id
35+
</template>
36+
</FlowmapNode>
37+
38+
<FlowmapNode :lines="{ top: true }" pl4 py2>
39+
<template #content>
40+
<div i-ph-upload-simple-duotone /> Load
41+
</template>
42+
<template #inline-after>
43+
<div w-8 relative>
44+
<div absolute top="1/2" left-0 bottom--4 right="1/2" border="t r base rounded-rt-2xl" z-flowmap-line />
45+
</div>
46+
<button>
47+
<div i-ph-caret-down />
48+
</button>
49+
</template>
50+
<template #after>
51+
<div pl-12 pt2>
52+
<template v-for="(load, idx) of info.loads" :key="load.plugin_name">
53+
<FlowmapNode :lines="{ top: idx > 0, bottom: idx < info.loads.length - 1 }" pl4 py1>
54+
<template #content>
55+
<DisplayPluginName :name="load.plugin_name" class="font-mono text-sm" />
56+
</template>
57+
</FlowmapNode>
58+
</template>
59+
</div>
60+
</template>
61+
</FlowmapNode>
62+
63+
<FlowmapNode :lines="{ top: true }" pl4 py2>
64+
<template #content>
65+
<div i-ph-magic-wand-duotone /> Transform
66+
</template>
67+
<template #inline-after>
68+
<div w-8 relative>
69+
<div absolute top="1/2" left-0 bottom--4 right="1/2" border="t r base rounded-rt-2xl" z-flowmap-line />
70+
</div>
71+
<button>
72+
<div i-ph-caret-down />
73+
</button>
74+
</template>
75+
<template #after>
76+
<div pl-12 pt2>
77+
<template v-for="(transform, idx) of info.transforms" :key="transform.plugin_name">
78+
<FlowmapNode :lines="{ top: idx > 0, bottom: idx < info.transforms.length - 1 }" pl4 py1>
79+
<template #content>
80+
<DisplayPluginName :name="transform.plugin_name" class="font-mono text-sm" />
81+
</template>
82+
</FlowmapNode>
83+
</template>
84+
</div>
85+
</template>
86+
</FlowmapNode>
87+
88+
<FlowmapNode :lines="{ top: true, bottom: true }" pl4 py2>
89+
<template #content>
90+
<div i-ph-shapes-duotone /> Chunk
91+
</template>
92+
</FlowmapNode>
93+
94+
<FlowmapNode :lines="{ top: true, bottom: true }" pl4 py2>
95+
<template #content>
96+
<div i-ph-tree-duotone /> Tree shake
97+
</template>
98+
</FlowmapNode>
99+
100+
<FlowmapNode :lines="{ top: true }" pl4 py2>
101+
<template #content>
102+
<div i-ph-package-duotone /> Generate
103+
</template>
104+
</FlowmapNode>
105+
106+
<!-- <pre>
107+
{{ info.state }}
108+
</pre> -->
27109
</div>
28110
</template>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function bytesToHumanSize(bytes: number, digits = 2) {
2+
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
3+
const i = Math.floor(Math.log(bytes) / Math.log(1024))
4+
if (i === 0)
5+
return ['<1', 'K']
6+
return [(+(bytes / 1024 ** i).toFixed(digits)).toLocaleString(), sizes[i]]
7+
}

packages/devtools/src/node/rpc/functions/rolldown-get-module-info.ts

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,37 @@ import { join } from 'pathe'
22
import { RolldownEventsReader } from '../../rolldown/events-reader'
33
import { defineRpcFunction } from '../utils'
44

5+
export interface ModuleInfo {
6+
id: string
7+
loads: RolldownModuleLoadInfo[]
8+
transforms: RolldownModuleTransformInfo[]
9+
10+
// TODO: Awaits https://github.com/rolldown/rolldown/issues/4135
11+
deps: string[]
12+
importers: string[]
13+
}
14+
15+
export interface RolldownModuleLoadInfo {
16+
id: string
17+
plugin_name: string
18+
source: string | null
19+
timestamp_start: number
20+
timestamp_end: number
21+
duration: number
22+
}
23+
24+
export interface RolldownModuleTransformInfo {
25+
id: string
26+
plugin_name: string
27+
source_from: string | null
28+
source_to: string | null
29+
timestamp_start: number
30+
timestamp_end: number
31+
duration: number
32+
}
33+
34+
const DURATION_THRESHOLD = 10
35+
536
export const rolldownGetModuleInfo = defineRpcFunction({
637
name: 'vite:rolldown:get-module-info',
738
type: 'query',
@@ -11,9 +42,67 @@ export const rolldownGetModuleInfo = defineRpcFunction({
1142
const reader = RolldownEventsReader.get(join(cwd, '.rolldown', build, 'log.json'))
1243
await reader.read()
1344
const events = reader.manager.events.filter(event => event.module_id === module)
14-
return {
15-
events,
45+
46+
if (!events.length)
47+
return null
48+
49+
const info: ModuleInfo = {
50+
id: module,
51+
loads: [],
52+
transforms: [],
53+
deps: [],
54+
importers: [],
1655
}
56+
57+
for (const event of events) {
58+
if (event.kind === 'HookLoadCallEnd') {
59+
// TODO: use ID to pair start and end
60+
const start = events.find(e => e.kind === 'HookLoadCallStart' && e.module_id === event.module_id && e.plugin_name === event.plugin_name)
61+
if (!start) {
62+
console.error(`[rolldown] Load call start not found for ${event.event_id}`)
63+
continue
64+
}
65+
const duration = +event.timestamp - +start.timestamp
66+
if (!event.source && duration < DURATION_THRESHOLD)
67+
continue
68+
info.loads.push({
69+
id: event.event_id,
70+
plugin_name: event.plugin_name,
71+
source: event.source,
72+
timestamp_start: +start.timestamp,
73+
timestamp_end: +event.timestamp,
74+
duration,
75+
})
76+
}
77+
}
78+
79+
for (const event of events) {
80+
if (event.kind === 'HookTransformCallEnd') {
81+
// TODO: use ID to pair start and end
82+
const start = events.find(e => e.kind === 'HookTransformCallStart' && e.module_id === event.module_id && e.plugin_name === event.plugin_name)
83+
if (!start || start.kind !== 'HookTransformCallStart') {
84+
console.error(`[rolldown] Transform call start not found for ${event.event_id}`)
85+
continue
86+
}
87+
const duration = +event.timestamp - +start.timestamp
88+
if (start.source === event.transformed_source && duration < DURATION_THRESHOLD)
89+
continue
90+
info.transforms.push({
91+
id: event.event_id,
92+
plugin_name: event.plugin_name,
93+
source_from: start.source,
94+
source_to: event.transformed_source,
95+
timestamp_start: +start.timestamp,
96+
timestamp_end: +event.timestamp,
97+
duration,
98+
})
99+
}
100+
}
101+
102+
info.loads.sort((a, b) => a.timestamp_start - b.timestamp_start)
103+
info.transforms.sort((a, b) => a.timestamp_start - b.timestamp_start)
104+
105+
return info
17106
},
18107
}
19108
},
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { join } from 'pathe'
2+
import { RolldownEventsReader } from '../../rolldown/events-reader'
3+
import { defineRpcFunction } from '../utils'
4+
5+
export const rolldownGetModuleRawEvents = defineRpcFunction({
6+
name: 'vite:rolldown:get-module-raw-events',
7+
type: 'query',
8+
setup: ({ cwd }) => {
9+
return {
10+
handler: async ({ build, module }: { build: string, module: string }) => {
11+
const reader = RolldownEventsReader.get(join(cwd, '.rolldown', build, 'log.json'))
12+
await reader.read()
13+
const events = reader.manager.events.filter(event => event.module_id === module)
14+
return {
15+
events,
16+
}
17+
},
18+
}
19+
},
20+
})

packages/devtools/src/node/rpc/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { openInEditor } from './functions/open-in-editor'
44
import { openInFinder } from './functions/open-in-finder'
55
import { rolldownGetModuleInfo } from './functions/rolldown-get-module-info'
66
import { rolldownGetModuleList } from './functions/rolldown-get-module-list'
7+
import { rolldownGetModuleRawEvents } from './functions/rolldown-get-module-raw-events'
78
import { rolldownGetRawEvents } from './functions/rolldown-get-raw-events'
89
import { rolldownListBuilds } from './functions/rolldown-list-builds'
910

@@ -15,6 +16,7 @@ export const rpcFunctions = [
1516
rolldownGetRawEvents,
1617
rolldownGetModuleList,
1718
rolldownGetModuleInfo,
19+
rolldownGetModuleRawEvents,
1820
] as const
1921

2022
export type ServerFunctions = DefinitionsToFunctions<typeof rpcFunctions>

packages/devtools/src/uno.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export default defineConfig({
3434

3535
'icon-catppuccin': 'light:filter-invert-100 light:filter-hue-rotate-180 light:filter-brightness-80',
3636

37+
'z-flowmap-line': 'z--1',
3738
'z-graph-bg': 'z-5',
3839
'z-graph-link': 'z-10',
3940
'z-graph-node': 'z-11',

0 commit comments

Comments
 (0)