diff --git a/packages/ui/client/components/FileDetails.vue b/packages/ui/client/components/FileDetails.vue index f1c841224..6b23e147b 100644 --- a/packages/ui/client/components/FileDetails.vue +++ b/packages/ui/client/components/FileDetails.vue @@ -2,6 +2,7 @@ import type { ModuleGraph } from '~/composables/module-graph' import type { Params } from '~/composables/params' import { hasFailedSnapshot } from '@vitest/ws-client' +import { toJSON } from 'flatted' import { browserState, client, @@ -18,6 +19,7 @@ const draft = ref(false) const hasGraphBeenDisplayed = ref(false) const loadingModuleGraph = ref(false) const currentFilepath = ref(undefined) +const hideNodeModules = ref(true) const graphData = computed(() => { const c = current.value @@ -61,10 +63,12 @@ function onDraft(value: boolean) { draft.value = value } -async function loadModuleGraph() { +const nodeModuleRegex = /[/\\]node_modules[/\\]/ + +async function loadModuleGraph(force = false) { if ( loadingModuleGraph.value - || graphData.value?.filepath === currentFilepath.value + || (graphData.value?.filepath === currentFilepath.value && !force) ) { return } @@ -76,20 +80,39 @@ async function loadModuleGraph() { try { const gd = graphData.value if (!gd) { + loadingModuleGraph.value = false return } if ( - !currentFilepath.value + force + || !currentFilepath.value || gd.filepath !== currentFilepath.value || (!graph.value.nodes.length && !graph.value.links.length) ) { + let moduleGraph = await client.rpc.getModuleGraph( + gd.projectName, + gd.filepath, + !!browserState, + ) + // remove node_modules from the graph when enabled + if (hideNodeModules.value) { + // when using static html reporter, we've the meta as global, we need to clone it + if (isReport) { + moduleGraph + = typeof window.structuredClone !== 'undefined' + ? window.structuredClone(moduleGraph) + : toJSON(moduleGraph) + } + moduleGraph.inlined = moduleGraph.inlined.filter( + n => !nodeModuleRegex.test(n), + ) + moduleGraph.externalized = moduleGraph.externalized.filter( + n => !nodeModuleRegex.test(n), + ) + } graph.value = getModuleGraph( - await client.rpc.getModuleGraph( - gd.projectName, - gd.filepath, - !!browserState, - ), + moduleGraph, gd.filepath, ) currentFilepath.value = gd.filepath @@ -103,10 +126,11 @@ async function loadModuleGraph() { } debouncedWatch( - () => [graphData.value, viewMode.value] as const, - ([, vm]) => { + () => [graphData.value, viewMode.value, hideNodeModules.value] as const, + ([, vm, hide], old) => { if (vm === 'graph') { - loadModuleGraph() + // only force reload when hide is changed + loadModuleGraph(old && hide !== old[2]) } }, { debounce: 100, immediate: true }, @@ -221,6 +245,7 @@ const projectNameTextColor = computed(() => {
() +const hideNodeModules = defineModel({ required: true }) + const { graph } = toRefs(props) const el = ref() @@ -46,7 +48,7 @@ onUnmounted(() => { controller.value?.shutdown() }) -watch(graph, resetGraphController) +watch(graph, () => resetGraphController()) function setFilter(name: ModuleType, value: boolean) { controller.value?.filterNodesByType(value, name) @@ -57,8 +59,16 @@ function setSelectedModule(id: string) { modalShow.value = true } -function resetGraphController() { +function resetGraphController(reset = false) { controller.value?.shutdown() + + // Force reload the module graph only when node_modules are shown. + // The module graph doesn't contain node_modules entries. + if (reset && !hideNodeModules.value) { + hideNodeModules.value = true + return + } + if (!graph.value || !el.value) { return } @@ -154,6 +164,28 @@ function bindOnClick(
+
+ + +