Skip to content

Commit f7e9ab5

Browse files
authored
feat: debug page of module mutation (#770)
1 parent 68df38e commit f7e9ab5

File tree

20 files changed

+356
-30
lines changed

20 files changed

+356
-30
lines changed

packages/devtools-kit/src/_types/client-api.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,13 @@ export interface NuxtDevtoolsHostClient {
113113
syncClient: () => NuxtDevtoolsHostClient
114114
}
115115

116+
export interface CodeHighlightOptions {
117+
grammarContextCode?: string
118+
}
119+
116120
export interface NuxtDevtoolsClient {
117121
rpc: BirpcReturn<ServerFunctions, ClientFunctions>
118-
renderCodeHighlight: (code: string, lang?: BuiltinLanguage) => {
122+
renderCodeHighlight: (code: string, lang?: BuiltinLanguage, options?: CodeHighlightOptions) => {
119123
code: string
120124
supported: boolean
121125
}

packages/devtools-kit/src/_types/rpc.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import type { AnalyzeBuildsInfo } from './analyze-build'
66
import type { ModuleCustomTab } from './custom-tabs'
77
import type { AssetEntry, AssetInfo, AutoImportsWithMetadata, ComponentRelationship, HookInfo, ImageMeta, NpmCommandOptions, NpmCommandType, PackageUpdateInfo, ScannedNitroTasks, ServerRouteInfo } from './integrations'
88
import type { ModuleOptions, NuxtDevToolsOptions } from './options'
9-
import type { InstallModuleReturn } from './server-ctx'
9+
import type { InstallModuleReturn, ServerDebugContext } from './server-ctx'
1010
import type { TerminalAction, TerminalInfo } from './terminals'
1111
import type { GetWizardArgs, WizardActions } from './wizard'
1212

1313
export interface ServerFunctions {
1414
// Static RPCs (can be provide on production build in the future)
1515
getServerConfig: () => NuxtOptions
16+
getServerDebugContext: () => Promise<ServerDebugContext | undefined>
1617
getServerData: (token: string) => Promise<NuxtServerData>
1718
getServerRuntimeConfig: () => Record<string, any>
1819
getModuleOptions: () => ModuleOptions

packages/devtools-kit/src/_types/server-ctx.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { BirpcGroup } from 'birpc'
2-
import type { Nuxt } from 'nuxt/schema'
2+
import type { Nuxt, NuxtDebugModuleMutationRecord } from 'nuxt/schema'
33
import type { ModuleOptions } from './options'
44
import type { ClientFunctions, ServerFunctions } from './rpc'
55

@@ -42,3 +42,9 @@ export interface InstallModuleReturn {
4242
commands: string[]
4343
processId: string
4444
}
45+
46+
export type ServerDebugModuleMutationRecord = (Omit<NuxtDebugModuleMutationRecord, 'module'> & { name: string })
47+
48+
export interface ServerDebugContext {
49+
moduleMutationRecords: ServerDebugModuleMutationRecord[]
50+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<script setup lang="ts">
2+
import { computed } from 'vue'
3+
import { getHslColorFromStringHash } from '../composables/color'
4+
import NBadge from './NBadge.vue'
5+
6+
const props = defineProps<{
7+
text: string
8+
}>()
9+
10+
const color = computed(() => {
11+
const foreground = getHslColorFromStringHash(props.text, 50, 60)
12+
const background = getHslColorFromStringHash(props.text, 50, 60, 0.05)
13+
return { color: foreground, background }
14+
})
15+
</script>
16+
17+
<template>
18+
<NBadge :style="color">
19+
{{ text }}<slot />
20+
</NBadge>
21+
</template>

packages/devtools-ui-kit/src/components/NCodeBlock.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const props = withDefaults(
1010
lang?: BuiltinLanguage | 'text'
1111
lines?: boolean
1212
inline?: boolean
13+
grammarContextCode?: string
1314
transformRendered?: (code: string) => string
1415
}>(),
1516
{
@@ -22,7 +23,7 @@ const emit = defineEmits(['loaded'])
2223
const rendered = computed(() => {
2324
const result = props.lang === 'text'
2425
? { code: props.code, supported: false }
25-
: devToolsClient.value?.devtools.renderCodeHighlight(props.code, props.lang) || { code: props.code, supported: false }
26+
: devToolsClient.value?.devtools.renderCodeHighlight(props.code, props.lang, { grammarContextCode: props.grammarContextCode }) || { code: props.code, supported: false }
2627
if (result.supported && props.transformRendered)
2728
result.code = props.transformRendered(result.code)
2829
if (result.supported)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function getHslColorFromStringHash(name: string, saturation = 65, lightness = 50, opacity: number | string = 1) {
2+
let hash = 0
3+
for (let i = 0; i < name.length; i++)
4+
hash = name.charCodeAt(i) + ((hash << 5) - hash)
5+
const h = hash % 360
6+
return `hsla(${h}, ${saturation}%, ${lightness}%, ${opacity})`
7+
}

packages/devtools-ui-kit/src/module.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export interface ModuleOptions {
1616

1717
export default defineNuxtModule<ModuleOptions>({
1818
meta: {
19-
name: 'devtools-ui-kit',
19+
name: '@nuxt/devtools-ui-kit',
2020
configKey: 'devtoolsUIKit',
2121
},
2222
defaults: {
@@ -35,9 +35,6 @@ export default defineNuxtModule<ModuleOptions>({
3535
if (!options.dev)
3636
nuxt.options.unocss = extendUnocssOptions(nuxt.options.unocss)
3737

38-
// eslint-disable-next-line ts/ban-ts-comment
39-
// @ts-ignore - module options
40-
nuxt.options.vueuse = nuxt.options.vueuse || {}
4138
// eslint-disable-next-line ts/ban-ts-comment
4239
// @ts-ignore - module options
4340
nuxt.options.colorMode = defu(nuxt.options.colorMode, { classSuffix: '' })

packages/devtools/client/components/BuildAnalyzeDetails.vue

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,18 @@ async function clear(name: string) {
5757
<button
5858
px4 py2 border="r base"
5959
hover="bg-active"
60-
:class="tab.id === selectedTab.id ? '' : 'border-b'"
60+
:class="tab.id === selectedTab?.id ? '' : 'border-b'"
6161
@click="selectedTab = tab"
6262
>
63-
<div :class="tab.id === selectedTab.id ? '' : 'op30' ">
63+
<div :class="tab.id === selectedTab?.id ? '' : 'op30' ">
6464
{{ tab.name }}
6565
</div>
6666
</button>
6767
</template>
6868
<div border="b base" flex-auto />
6969
</div>
7070
<div
71-
v-if="selectedTab.id === 'overview'"
71+
v-if="selectedTab?.id === 'overview'"
7272
flex="~ col gap-4 items-center justify-center" p4
7373
>
7474
<div flex-auto />
@@ -126,17 +126,17 @@ async function clear(name: string) {
126126
</NButton>
127127
</div>
128128
<iframe
129-
v-lazy-show="selectedTab.id === 'bundle-client'"
129+
v-lazy-show="selectedTab?.id === 'bundle-client'"
130130
:src="`${ROUTE_ANALYZE}${current.slug}/client.html`"
131131
h-full w-full
132132
/>
133133
<iframe
134-
v-lazy-show="selectedTab.id === 'bundle-nitro'"
134+
v-lazy-show="selectedTab?.id === 'bundle-nitro'"
135135
:src="`${ROUTE_ANALYZE}${current.slug}/nitro.html`"
136136
h-full w-full
137137
/>
138138
<iframe
139-
v-lazy-show="selectedTab.id === 'vite-inspect'"
139+
v-lazy-show="selectedTab?.id === 'vite-inspect'"
140140
:src="`${ROUTE_ANALYZE}${current.slug}/.vite-inspect/`"
141141
h-full w-full
142142
/>
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<script setup lang="ts">
2+
import type { ServerDebugModuleMutationRecord } from '@nuxt/devtools-kit/types'
3+
import { computed, ref } from 'vue'
4+
5+
const props = defineProps<{
6+
moduleMutationRecords: ServerDebugModuleMutationRecord[]
7+
}>()
8+
9+
function isPath(path: string) {
10+
return path.startsWith('/') || path.match(/^[a-z]:[\\/]/i)
11+
}
12+
13+
// const search = ref('')
14+
const showBuiltin = ref(false)
15+
const showTemplates = ref(false)
16+
const showTranspile = ref(false)
17+
const showPlugins = ref(false)
18+
const showEmptyInitial = ref(false)
19+
const moduleFilter = ref('')
20+
21+
const items = computed(() => {
22+
let arr = props.moduleMutationRecords
23+
if (!showBuiltin.value) {
24+
arr = arr.filter(i => !i.name.startsWith('nuxt:') && i.name !== '@nuxt/devtools')
25+
}
26+
if (!showTemplates.value) {
27+
arr = arr.filter(i => i.keys.join('.') !== 'build.templates')
28+
}
29+
if (!showTranspile.value) {
30+
arr = arr.filter(i => i.keys.join('.') !== 'build.transpile')
31+
}
32+
if (!showPlugins.value) {
33+
arr = arr.filter(i => i.keys.join('.') !== 'plugins')
34+
}
35+
if (!showEmptyInitial.value) {
36+
arr = arr.filter(i => i.method || (i.value !== '[]' && i.value !== '{}'))
37+
}
38+
if (moduleFilter.value) {
39+
arr = arr.filter(i => i.name === moduleFilter.value)
40+
}
41+
return arr
42+
})
43+
</script>
44+
45+
<template>
46+
<div flex="~ gap-2 col" mb4>
47+
<!-- <NTextInput v-model="search" placeholder="Search" w-full /> -->
48+
<div flex="~ gap-3 items-center">
49+
<NCheckbox v-model="showBuiltin" n="primary">
50+
<span ws-nowrap op75>Builtin Modules</span>
51+
</NCheckbox>
52+
<NCheckbox v-model="showTemplates" n="primary">
53+
<span ws-nowrap op75>Templates</span>
54+
</NCheckbox>
55+
<NCheckbox v-model="showTranspile" n="primary">
56+
<span ws-nowrap op75>Transpile</span>
57+
</NCheckbox>
58+
<NCheckbox v-model="showPlugins" n="primary">
59+
<span ws-nowrap op75>Plugins</span>
60+
</NCheckbox>
61+
<NCheckbox v-model="showEmptyInitial" n="primary">
62+
<span ws-nowrap op75>Empty Initial</span>
63+
</NCheckbox>
64+
<div v-if="moduleFilter" flex="~ gap-1" items-center p1 border="~ base rounded">
65+
<NBadgeHashed font-mono :text="moduleFilter" />
66+
<NButton icon="carbon-close" :border="false" @click="moduleFilter = ''" />
67+
</div>
68+
</div>
69+
</div>
70+
<table max-w-full of-auto>
71+
<thead border="b base">
72+
<tr>
73+
<th ws-nowrap p1 text-center font-bold>
74+
Index
75+
</th>
76+
<th ws-nowrap p1 text-center font-bold>
77+
Module
78+
</th>
79+
<th ws-nowrap p1 text-center font-bold>
80+
Key Path
81+
</th>
82+
<th ws-nowrap p1 text-center font-bold>
83+
Method
84+
</th>
85+
<th ws-nowrap p1 text-center font-bold>
86+
Value
87+
</th>
88+
</tr>
89+
</thead>
90+
<tbody>
91+
<tr
92+
v-for="record of items"
93+
:key="moduleMutationRecords.indexOf(record)"
94+
border="b dashed transparent hover:base"
95+
>
96+
<td text-center op50>
97+
<div>{{ moduleMutationRecords.indexOf(record) + 1 }}</div>
98+
</td>
99+
<td>
100+
<FilepathItem v-if="record.name && isPath(record.name)" :filepath="record.name" />
101+
<NBadgeHashed
102+
v-else
103+
role="button" font-mono
104+
:text="record.name"
105+
@click="moduleFilter = record.name"
106+
/>
107+
</td>
108+
<td>
109+
<code flex="~" px4>
110+
<template v-for="key, idy of record.keys" :key="idy">
111+
<span>{{ key }}</span>
112+
<span v-if="idy < record.keys.length - 1" op50>
113+
.
114+
</span>
115+
</template>
116+
</code>
117+
</td>
118+
<td px2 text-center>
119+
<NBadgeHashed font-mono :text="record.method || '='" :class="record.method ? '' : 'saturate-0'" />
120+
</td>
121+
<td of-auto>
122+
<NCodeBlock
123+
:code="String(record.value)"
124+
lang="ts"
125+
grammar-context-code="let a = "
126+
ws-normal break-all py1
127+
:lines="false" :inline="true"
128+
/>
129+
</td>
130+
</tr>
131+
</tbody>
132+
</table>
133+
</template>

packages/devtools/client/components/HooksTable.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ function toggleSortedBy(by: SortBy) {
9292
<td w-0 ws-nowrap text-center text-sm op25>
9393
{{ startTimes.indexOf(item.start) }}
9494
</td>
95-
<td w-0 ws-nowrap text-right :style="{ color: getHashColorFromString(getNamePrefix(item.name)) }">
95+
<td w-0 ws-nowrap text-right :style="{ color: getHslColorFromStringHash(getNamePrefix(item.name)) }">
9696
<code text-sm>{{ getNamePrefix(item.name) }}</code>
9797
</td>
9898
<td ws-nowrap>

0 commit comments

Comments
 (0)