Thanks to visit codestin.com
Credit goes to github.com

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

+5-1
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

+2-1
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

+7-1
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+
}
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

+2-1
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)
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

+1-4
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

+6-6
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
/>
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

+1-1
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>

packages/devtools/client/components/TimelineItemFunction.vue

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
<script setup lang="ts">
22
import type { TimelineEventFunction } from '../../types'
33
import { computed } from 'vue'
4-
import { getHashColorFromString } from '~/composables/utils'
4+
import { getHslColorFromStringHash } from '../../../devtools-ui-kit/src/composables/color'
55
66
const props = defineProps<{
77
item: TimelineEventFunction
88
}>()
99
10-
const colorRaw = computed(() => getHashColorFromString(props.item.name, 50, 60, '_op_'))
10+
const colorRaw = computed(() => getHslColorFromStringHash(props.item.name, 50, 60, '_op_'))
1111
const color = computed(() => colorRaw.value.replace(/_op_/, '1'))
12-
const textColor = computed(() => getHashColorFromString(props.item.name, 50, 40))
12+
const textColor = computed(() => getHslColorFromStringHash(props.item.name, 50, 40))
1313
const colorBackground = computed(() => colorRaw.value.replace(/_op_/, '0.2'))
1414
</script>
1515

packages/devtools/client/components/TimelineList.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const emit = defineEmits<{
2525
font-mono
2626
:style="{
2727
color: event.type === 'function'
28-
? getHashColorFromString(event.name, 50, 60)
28+
? getHslColorFromStringHash(event.name, 50, 60)
2929
: '',
3030
}"
3131
>

packages/devtools/client/components/TimelineTable.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ useEventListener(scroller, 'wheel', (e: WheelEvent) => {
103103
position: 'absolute',
104104
top: `${item.layer * 4}px`,
105105
left: `${item.relativeStart * 100}%`,
106-
backgroundColor: getHashColorFromString(item.event.name, 50, 60),
106+
backgroundColor: getHslColorFromStringHash(item.event.name, 50, 60),
107107
}"
108108
/>
109109
<template v-if="segment.route">

packages/devtools/client/composables/client-services/shiki.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { CodeHighlightOptions } from '@nuxt/devtools-kit/types'
12
import type { BundledLanguage, BundledTheme, Highlighter } from './shiki.bundle'
23
import { shallowRef } from 'vue'
34
import { bundledLanguages, bundledThemes, createHighlighter } from './shiki.bundle'
@@ -6,7 +7,11 @@ export const shiki = shallowRef<Highlighter>()
67

78
let promise: Promise<any> | null = null
89

9-
export function renderCodeHighlight(code: string, lang: BundledLanguage | 'text' = 'text') {
10+
export function renderCodeHighlight(
11+
code: string,
12+
lang: BundledLanguage | 'text' = 'text',
13+
options?: CodeHighlightOptions,
14+
) {
1015
if (!promise && !shiki.value) {
1116
// Only loading when needed
1217
promise = createHighlighter({
@@ -27,6 +32,7 @@ export function renderCodeHighlight(code: string, lang: BundledLanguage | 'text'
2732

2833
return {
2934
code: shiki.value!.codeToHtml(code, {
35+
...options,
3036
lang,
3137
themes: {
3238
dark: 'vitesse-dark',

packages/devtools/client/composables/state.ts

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ export function useServerConfig() {
3939
return useAsyncState('getServerConfig', () => rpc.getServerConfig())
4040
}
4141

42+
export function useServerDebugContext() {
43+
return useAsyncState('getServerDebugContext', () => rpc.getServerDebugContext())
44+
}
45+
4246
export function useServerRuntimeConfig() {
4347
return useAsyncState('getServerRuntimeConfig', () => rpc.getServerRuntimeConfig())
4448
}

packages/devtools/client/composables/utils.ts

-8
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,6 @@ export function formatDuration(ms: number | string) {
137137
return `${(ms / 1000 / 60).toFixed(2)}min`
138138
}
139139

140-
export function getHashColorFromString(name: string, saturation = 65, lightness = 50, opacity: number | string = 1) {
141-
let hash = 0
142-
for (let i = 0; i < name.length; i++)
143-
hash = name.charCodeAt(i) + ((hash << 5) - hash)
144-
const h = hash % 360
145-
return `hsla(${h}, ${saturation}%, ${lightness}%, ${opacity})`
146-
}
147-
148140
export function useSessionState<T>(name: string, initialValue: T) {
149141
return useState(name, () => {
150142
return useSessionStorage(name, initialValue, { listenToStorageChanges: false })

packages/devtools/client/nuxt.config.ts

+2
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ export default defineNuxtConfig({
151151
includeWorkspace: true,
152152
},
153153

154+
debug: true,
155+
154156
eslint: {
155157
config: {
156158
standalone: false,

0 commit comments

Comments
 (0)