Skip to content

Commit

Permalink
feat: error tab (#520)
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu authored Nov 22, 2023
1 parent 6129fa0 commit 68b8cfc
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 30 deletions.
42 changes: 42 additions & 0 deletions packages/devtools/client/components/StacktraceList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
import type { StackFrame } from 'error-stack-parser-es'
defineProps<{
stacktrace: StackFrame[]
}>()
const config = useServerConfig()
function urlToFilepath(url: string) {
try {
let pathname = new URL(url).pathname
if (pathname.startsWith('/_nuxt/'))
pathname = pathname.slice(6)
if (pathname.startsWith('/@id/virtual:nuxt:'))
return `#build/${pathname.split('/.nuxt/')[1]}`.replace(/\.m?js$/, '')
if (pathname.includes('/@fs/'))
return `/${pathname.split('/@fs/')[1]}`
return (config.value?.rootDir || '') + pathname
}
catch (e) {
return url
}
}
</script>

<template>
<div mt2 grid="~ cols-[max-content_1fr] gap-x-4" font-mono>
<template v-for="item, idx of stacktrace" :key="idx">
<div text-right>
{{ item.functionName || `(anonymous)` }}
</div>
<div ws-nowrap>
<FilepathItem
v-if="item.fileName"
:filepath="`${urlToFilepath(item.fileName)}:${item.lineNumber}:${item.columnNumber}`"
subpath
/>
</div>
</template>
</div>
</template>
30 changes: 4 additions & 26 deletions packages/devtools/client/components/TimelineDetailsFunction.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,8 @@ const props = defineProps<{
record: TimelineEventFunction
}>()
const config = useServerConfig()
const timeAgo = useTimeAgo(() => props.record.start, { showSecond: true })
function urlToFilepath(url: string) {
let pathname = new URL(url).pathname
if (pathname.startsWith('/_nuxt/'))
pathname = pathname.slice(6)
if (pathname.startsWith('/@id/virtual:nuxt:'))
return `#build/${pathname.split('/.nuxt/')[1]}`.replace(/\.m?js$/, '')
if (pathname.includes('/@fs/'))
return `/${pathname.split('/@fs/')[1]}`
return (config.value?.rootDir || '') + pathname
}
const autoImports = useAutoImports()
const importsMetadata = computed(() => autoImports.value?.metadata)
const importItem = computed(() => {
Expand Down Expand Up @@ -60,19 +48,9 @@ const importItem = computed(() => {
</div>
</div>

<div v-if="record.stacktrace" class="text-xs text-gray-400" mt2 grid="~ cols-[max-content_1fr] gap-x-4" font-mono>
<template v-for="item, idx of record.stacktrace" :key="idx">
<div text-right>
{{ item.functionName || `(anonymous)` }}
</div>
<div ws-nowrap>
<FilepathItem
v-if="item.fileName"
:filepath="`${urlToFilepath(item.fileName)}:${item.lineNumber}:${item.columnNumber}`"
subpath
/>
</div>
</template>
</div>
<StacktraceList
v-if="record.stacktrace" :stacktrace="record.stacktrace"
class="text-xs text-gray-400"
/>
</div>
</template>
78 changes: 78 additions & 0 deletions packages/devtools/client/pages/modules/error.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<script setup lang="ts">
import { parse as parseStrackTrace } from 'error-stack-parser-es'
definePageMeta({
icon: 'i-carbon-warning-alt-filled text-red',
title: 'Error',
category: 'app',
show() {
const client = useClient()
return () => client.value?.nuxt?.payload?.error
},
})
const client = useClient()
const error = computed(() => {
const err = client.value?.nuxt?.payload?.error as {
url?: string
statusCode?: number
statusMessage?: string
message?: string
description?: string
data?: any
} & Error
if (err) {
console.error('[Nuxt DevTools] Error in payload:')
console.error(err)
console.error({ ...err })
}
return err
})
const stacks = computed(() => {
if (!error.value?.stack)
return []
try {
// Nuxt server returns a HTML rendered stacktrace, workaround by removing all HTML tags
if (error.value.stack.startsWith('<pre>')) {
return parseStrackTrace({
stack: error.value.stack.replace(/<.*?>/g, ''),
} as any)
}
return parseStrackTrace(error.value)
}
catch (e) {
console.error(e)
return []
}
})
</script>

<template>
<div p6>
<div v-if="error">
<NTip n="red" icon="i-carbon-warning-alt-filled" mb5>
Error occurred in this page
</NTip>
<div text-6xl>
{{ error.statusCode || 'Client Error' }}
</div>
<div v-if="error.statusMessage" op75>
{{ error.statusMessage }}
</div>
<div my4 text-xl text-red>
{{ error.message || error.description || 'Unknown error' }}
</div>
<div v-if="stacks.length || error.stack" of-auto rounded bg-active p2>
<div px1 op50>
Stacktrace
</div>
<StacktraceList v-if="stacks.length" px2 :stacktrace="stacks" />
<pre v-else v-text="error.stack" />
</div>
</div>
<div v-else op50>
No error
</div>
</div>
</template>
4 changes: 2 additions & 2 deletions packages/devtools/src/runtime/plugins/devtools.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ export default defineNuxtPlugin((nuxt: any) => {
})

import('./view/client')
.then(({ setupDevToolsClient }) => {
setupDevToolsClient({
.then(async ({ setupDevToolsClient }) => {
await setupDevToolsClient({
nuxt,
clientHooks,
timeMetric,
Expand Down
2 changes: 2 additions & 0 deletions packages/devtools/src/runtime/plugins/view/Main.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ const draggingOffset = reactive({ x: 0, y: 0 })
const mousePosition = reactive({ x: 0, y: 0 })
function onPointerDown(e: PointerEvent) {
if (!panelEl.value)
return
isDragging.value = true
const { left, top, width, height } = panelEl.value!.getBoundingClientRect()
draggingOffset.x = e.clientX - left - width / 2
Expand Down
3 changes: 3 additions & 0 deletions playgrounds/tab-timeline/components/GlobalNav.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
<NButton n="primary sm" to="/dynamic-bar" active-class="n-solid">
/dynamic-bar
</NButton>
<NButton n="primary sm" to="/error" active-class="n-solid">
/error
</NButton>
</div>
</div>
</template>
2 changes: 1 addition & 1 deletion playgrounds/tab-timeline/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default defineNuxtConfig({
'../../packages/devtools-ui-kit/src/module',
'../../local',
],
ssr: false,
ssr: true,
vite: {
clearScreen: false,
},
Expand Down
1 change: 0 additions & 1 deletion playgrounds/tab-timeline/pages/empty.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script setup lang="ts">
</script>

<template>
Expand Down
9 changes: 9 additions & 0 deletions playgrounds/tab-timeline/pages/error.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script setup lang="ts">
throw new Error('This is an error thrown from error.vue')
</script>

<template>
<div>
Error
</div>
</template>

0 comments on commit 68b8cfc

Please sign in to comment.