Skip to content

Commit e1617b2

Browse files
authored
feat: chunk graph selector (#144)
1 parent b518f84 commit e1617b2

File tree

9 files changed

+346
-144
lines changed

9 files changed

+346
-144
lines changed

packages/vite/src/app/components/chunks/BaseInfo.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import { computed } from 'vue'
77
const props = withDefaults(defineProps<{
88
chunk: RolldownChunkInfo | RolldownChunkImport
99
link?: boolean
10+
basic?: boolean
1011
}>(), {
1112
link: false,
13+
basic: false,
1214
})
1315
const route = useRoute()
1416
const normalizedImports = computed(() => Array.isArray(props.chunk.imports) ? props.chunk.imports.length : props.chunk.imports)
@@ -32,7 +34,7 @@ const normalizedModules = computed(() => Array.isArray(props.chunk.modules) ? pr
3234

3335
<div flex-auto />
3436

35-
<div flex="~ items-center gap-2">
37+
<div v-if="!basic" flex="~ items-center gap-2">
3638
<span op50 font-mono>#{{ chunk.chunk_id }}</span>
3739
<div flex="~ gap-1 items-center" :title="`${normalizedImports} imports`">
3840
<div i-ph-file-arrow-up-duotone />

packages/vite/src/app/components/chunks/FlatList.vue

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
<script setup lang="ts">
22
import type { RolldownChunkInfo, SessionContext } from '~~/shared/types'
33
4-
defineProps<{
5-
chunks: RolldownChunkInfo[]
4+
withDefaults(defineProps<{
5+
chunks: Array<RolldownChunkInfo & { id: string }>
66
session: SessionContext
7+
link?: boolean
8+
basic?: boolean
9+
}>(), {
10+
link: true,
11+
basic: false,
12+
})
13+
14+
const emit = defineEmits<{
15+
(e: 'select', chunk: RolldownChunkInfo & { id: string }): void
716
}>()
817
</script>
918

@@ -13,8 +22,8 @@ defineProps<{
1322
key-prop="chunk_id"
1423
>
1524
<template #default="{ item }">
16-
<div flex pb2>
17-
<ChunksBaseInfo :chunk="item" link w-full font-mono border="~ rounded base" px2 py1 text-sm hover="bg-active" flex="~ gap-4 items-center">
25+
<div flex pb2 @click="emit('select', item)">
26+
<ChunksBaseInfo :chunk="item" :basic="basic" :link="link" w-full font-mono border="~ rounded base" px2 py1 text-sm hover="bg-active" flex="~ gap-4 items-center">
1827
<template #left-after>
1928
<DisplayBadge v-if="item.is_initial" text="initial" />
2029
</template>

packages/vite/src/app/components/chunks/Graph.vue

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ import { createModuleGraph } from '~/composables/moduleGraph'
99
type ChunkInfo = RolldownChunkInfo & {
1010
id: string
1111
}
12-
const props = defineProps<{
12+
const props = withDefaults(defineProps<{
1313
session: SessionContext
1414
chunks: ChunkInfo[]
15-
}>()
15+
entryId?: string
16+
}>(), {
17+
entryId: '',
18+
})
1619
1720
const chunks = computed(() => props.chunks)
1821
const route = useRoute()
@@ -32,7 +35,7 @@ createModuleGraph<ChunkInfo, ChunkImport>({
3235
width.value = window.innerWidth
3336
height.value = window.innerHeight
3437
35-
const entryChunks = chunks.value.filter(chunk => chunk.reason === 'entry')
38+
const entryChunks = chunks.value.filter(chunk => props.entryId ? chunk.id === props.entryId : chunk.reason === 'entry')
3639
3740
const seen = new Set<ChunkInfo>()
3841
const root = hierarchy<ModuleGraphNode<ChunkInfo, ChunkImport>>(

packages/vite/src/app/components/modules/PathSelector.vue renamed to packages/vite/src/app/components/data/PathSelector.vue

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,66 @@
1-
<script setup lang="ts">
2-
import type { ModuleListItem, SessionContext } from '~~/shared/types'
1+
<script setup lang="ts" generic="T extends { id:string, imports: Record<string, unknown>[] }">
2+
import type { SessionContext } from '~~/shared/types'
3+
import type { GraphPathSelector } from '~/composables/graph-path-selector'
34
import { computed, watch } from 'vue'
4-
import { useModulePathSelector } from '~/composables/moduleGraph'
5+
import { useGraphPathSelector } from '~/composables/graph-path-selector'
56
67
const props = defineProps<{
78
session: SessionContext
8-
modules: ModuleListItem[]
9+
data: T[]
10+
importIdKey: string
11+
searchKeys?: string[]
912
}>()
1013
1114
const emit = defineEmits<{
1215
(e: 'close'): void
1316
(e: 'select', nodes: { start: string, end: string }): void
1417
}>()
1518
16-
const modulesMap = computed(() => {
17-
const map = new Map<string, ModuleListItem>()
18-
props.modules.forEach((m) => {
19+
defineSlots<{
20+
list: (props: {
21+
select: (module: T) => void
22+
data: T[]
23+
}) => void
24+
item: (props: {
25+
id: string
26+
}) => void
27+
}>()
28+
29+
const dataMap = computed(() => {
30+
const map = new Map<string, T>()
31+
props.data.forEach((m) => {
1932
map.set(m.id, m)
2033
})
2134
return map
2235
})
2336
24-
const startSelector = useModulePathSelector({
37+
const startSelector: GraphPathSelector<T> = useGraphPathSelector<T>({
38+
searchKeys: props.searchKeys,
2539
getModules: () => {
2640
if (!startSelector.state.value.search) {
27-
return props.modules
41+
return props.data
2842
}
2943
else {
3044
return startSelector.fuse.value!.value?.search(startSelector.state.value.search).map(r => r.item) ?? []
3145
}
3246
},
3347
})
3448
35-
startSelector.initSelector(computed(() => props.modules))
49+
startSelector.initSelector(computed(() => props.data))
3650
37-
function getAllImports(moduleId: string, visited = new Set<string>()): ModuleListItem[] {
51+
function getAllImports(moduleId: string, visited = new Set<string>()): T[] {
3852
if (visited.has(moduleId))
3953
return []
4054
visited.add(moduleId)
4155
42-
const module = modulesMap.value.get(moduleId)
56+
const module = dataMap.value.get(moduleId)
4357
if (!module?.imports?.length)
4458
return []
4559
46-
const res: ModuleListItem[] = []
60+
const res: T[] = []
4761
4862
for (const importItem of module.imports) {
49-
const importedModule = modulesMap.value.get(importItem.module_id)
63+
const importedModule = dataMap.value.get(`${importItem[props.importIdKey]}`)
5064
if (!importedModule)
5165
continue
5266
@@ -59,7 +73,8 @@ function getAllImports(moduleId: string, visited = new Set<string>()): ModuleLis
5973
return res
6074
}
6175
62-
const endSelector = useModulePathSelector({
76+
const endSelector = useGraphPathSelector<T>({
77+
searchKeys: props.searchKeys,
6378
getModules: () => {
6479
return startSelector.state.value.selected ? getAllImports(startSelector.state.value.selected) : []
6580
},
@@ -82,39 +97,60 @@ watch([() => startSelector.state.value.selected, () => endSelector.state.value.s
8297
end: endSelector.state.value.selected ?? '',
8398
})
8499
})
100+
101+
function close() {
102+
emit('select', {
103+
start: '',
104+
end: '',
105+
})
106+
emit('close')
107+
}
85108
</script>
86109

87110
<template>
88-
<div h12 px4 p2 relative flex="~ gap2 items-center">
89-
<div flex="~ items-center gap2" class="flex-1" min-w-0>
90-
<ModulesPathSelectorItem
111+
<div h10 px4 p1 relative flex="~ gap2 items-center">
112+
<div flex="~ items-center gap2" class="flex-1 h-full" min-w-0>
113+
<DataPathSelectorItem
91114
v-model:search="startSelector.state.value.search"
92115
placeholder="Start"
93116
:selector="startSelector"
94117
:session="session"
95-
:modules="startSelector.modules.value"
118+
:data="startSelector.modules.value"
96119
@clear="() => { startSelector.clear(); endSelector.clear() }"
97-
/>
120+
>
121+
<template #list>
122+
<slot name="list" :select="startSelector.select" :data="startSelector.modules.value" />
123+
</template>
124+
<template #item>
125+
<slot :id="startSelector.state.value.selected!" name="item" />
126+
</template>
127+
</DataPathSelectorItem>
98128
<div class="i-carbon-arrow-right op50" flex-shrink-0 />
99129

100-
<ModulesPathSelectorItem
130+
<DataPathSelectorItem
101131
v-model:search="endSelector.state.value.search"
102132
placeholder="End"
103133
:selector="endSelector"
104134
:session="session"
105-
:modules="filteredEndModules"
135+
:data="filteredEndModules"
106136
@clear="endSelector.clear"
107137
>
138+
<template #list>
139+
<slot name="list" :select="endSelector.select" :data="filteredEndModules" />
140+
</template>
141+
<template #item>
142+
<slot :id="endSelector.state.value.selected!" name="item" />
143+
</template>
108144
<template #empty>
109145
<div flex="~ items-center justify-center" w-full h-20>
110146
<span italic op50>
111147
{{ startSelector.state.value.selected ? 'No modules' : 'Select a start module to get end modules' }}
112148
</span>
113149
</div>
114150
</template>
115-
</ModulesPathSelectorItem>
151+
</DataPathSelectorItem>
116152
</div>
117153

118-
<DisplayCloseButton class="mr--2" @click="emit('close')" />
154+
<DisplayCloseButton class="mr--2" @click="close" />
119155
</div>
120156
</template>

packages/vite/src/app/components/modules/PathSelectorItem.vue renamed to packages/vite/src/app/components/data/PathSelectorItem.vue

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
<script setup lang="ts">
2-
import type { ModuleListItem, SessionContext } from '~~/shared/types'
3-
import type { ModulePathSelector } from '~/composables/moduleGraph'
1+
<script setup lang="ts" generic="T extends { id:string, imports: any[] }">
2+
import type { SessionContext } from '~~/shared/types'
3+
import type { GraphPathSelector } from '~/composables/graph-path-selector'
44
import { hideAllPoppers, Menu as VMenu } from 'floating-vue'
55
66
withDefaults(
77
defineProps<{
8-
selector: ModulePathSelector
8+
selector: GraphPathSelector<T>
99
placeholder: string
1010
session: SessionContext
11-
modules?: ModuleListItem[]
11+
data?: T[]
1212
emptyStateText?: string
1313
onClear?: () => void
1414
}>(),
1515
{
16-
modules: undefined,
16+
data: undefined,
1717
emptyStateText: undefined,
1818
onClear: undefined,
1919
},
@@ -23,40 +23,32 @@ const emit = defineEmits<{
2323
(e: 'clear'): void
2424
}>()
2525
26+
defineSlots<{
27+
list: () => void
28+
item: () => void
29+
empty: () => void
30+
}>()
31+
2632
const search = defineModel<string>('search', { required: true })
2733
</script>
2834

2935
<template>
30-
<div flex-1 w-0>
36+
<div flex-1 w-0 h-full>
3137
<div v-if="selector.state.value.selected" w-full overflow-hidden flex="~ items-center" border="~ base rounded" p1 relative>
32-
<div overflow-hidden text-ellipsis pr6 py0.5 w-0 flex-1>
33-
<DisplayModuleId
34-
:id="selector.state.value.selected"
35-
:session="session"
36-
block text-nowrap
37-
:link="false"
38-
:disable-tooltip="true"
39-
/>
38+
<div overflow-hidden text-ellipsis pr6 w-0 flex-1>
39+
<slot name="item" />
4040
</div>
4141
<button i-carbon-clean text-4 hover="op100" op50 title="Clear" absolute right-2 @click="emit('clear')" />
4242
</div>
43-
<VMenu v-else :distance="15" :triggers="['click']" :auto-hide="false" :delay="{ show: 300, hide: 150 }">
43+
<VMenu v-else :distance="15" :triggers="['click']" :auto-hide="false" :delay="{ show: 300, hide: 150 }" class="h-full">
4444
<input
4545
v-model="search"
46-
p1
47-
px4 w-full border="~ base rounded-1" style="outline: none" :placeholder="placeholder"
46+
py1 px4 w-full h-full border="~ base rounded-1" style="outline: none" :placeholder="placeholder"
4847
@blur="hideAllPoppers"
4948
>
5049
<template #popper>
5150
<div class="p2 w100" flex="~ col gap2">
52-
<ModulesFlatList
53-
v-if="modules?.length"
54-
:session="session"
55-
:modules="modules"
56-
disable-tooltip
57-
:link="false"
58-
@select="selector.select"
59-
/>
51+
<slot v-if="data?.length" name="list" />
6052
<slot v-else name="empty" />
6153
</div>
6254
</template>

0 commit comments

Comments
 (0)