Skip to content

Commit

Permalink
feat(ui): add dedicated view for errors (#93)
Browse files Browse the repository at this point in the history
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
3 people committed Aug 13, 2023
1 parent e436ab9 commit 93a2f60
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 20 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"@antfu/utils": "^0.7.5",
"@rollup/pluginutils": "^5.0.2",
"debug": "^4.3.4",
"error-stack-parser-es": "^0.1.1",
"fs-extra": "^11.1.1",
"open": "^9.1.0",
"picocolors": "^1.0.0",
Expand Down
15 changes: 12 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/client/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ declare module 'vue' {
Badge: typeof import('./components/Badge.vue')['default']
Container: typeof import('./components/Container.vue')['default']
DiffEditor: typeof import('./components/DiffEditor.vue')['default']
ErrorDisplay: typeof import('./components/ErrorDisplay.vue')['default']
FilepathItem: typeof import('./components/FilepathItem.vue')['default']
Graph: typeof import('./components/Graph.vue')['default']
ModuleId: typeof import('./components/ModuleId.vue')['default']
ModuleList: typeof import('./components/ModuleList.vue')['default']
Expand Down
38 changes: 38 additions & 0 deletions src/client/components/ErrorDisplay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script setup lang="ts">
import type { ParsedError } from '../../types'
defineProps<{
error: ParsedError
}>()
function normalizeFilename(filename?: string) {
return (filename || '')
.replace(/^async\s+/, '')
.replace(/^file:\/\//, '')
}
</script>

<template>
<div of-auto p4 font-mono flex="~ col gap-4">
<div text-xl text-red7 dark:text-red flex="~ gap-2 items-center">
<div i-carbon:warning-square />
Error
</div>
<pre text-sm text-red7 dark:text-red>{{ error.message }}</pre>
<div border="t main" h-1px w-full />
<div class="text-xs" mt2 grid="~ cols-[max-content_1fr] gap-x-4 gap-y-1" font-mono>
<template v-for="item, idx of error.stack" :key="idx">
<div text-right op50>
{{ item.functionName || `(anonymous)` }}
</div>
<div ws-nowrap>
<FilepathItem
:filepath="normalizeFilename(item.fileName)"
:line="item.lineNumber"
:column="item.columnNumber"
/>
</div>
</template>
</div>
</div>
</template>
29 changes: 29 additions & 0 deletions src/client/components/FilepathItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script setup lang="ts">
const props = defineProps<{
filepath: string
line?: number
column?: number
}>()
async function openInEditor() {
await fetch(`/__open-in-editor?file=${encodeURI(props.filepath)}:${props.line}:${props.column}`)
}
const display = computed(() => {
const path = props.filepath.replace(/\\/g, '/')
if (props.filepath.includes('/node_modules/')) {
const match = path.match(/.*\/node_modules\/(@[^/]+\/[^/]+|[^/]+)(\/.*)?$/)
if (match)
return [match[1], match[2]]
}
return [path]
})
</script>

<template>
<button flex="~" hover="underline" @click="openInEditor">
<span>{{ display[0] }}</span>
<span op60>{{ display[1] }}</span>
<span v-if="props.line != null && props.column != null" op50>:{{ props.line }}:{{ props.column }}</span>
</button>
</template>
2 changes: 1 addition & 1 deletion src/client/components/ModuleId.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const isVirtual = computed(() => list.value?.modules.find(i => i.id === props.id

<Badge
v-if="isVirtual"
ml1 bg-teal-400:10 text-teal-400
class="ml1 bg-teal-400:10 text-green-700 dark:text-teal-400"
v-text="'virtual'"
/>
</div>
Expand Down
25 changes: 16 additions & 9 deletions src/client/pages/index/module.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ getHot().then((hot) => {
<ModuleId v-if="id" :id="id" />
<Badge
v-if="inspectSSR"
bg-teal-400:10 font-bold text-teal-400
class="bg-teal-400:10 font-bold text-green-700 dark:text-teal-400"
>
SSR
</Badge>
Expand Down Expand Up @@ -128,14 +128,14 @@ getHot().then((hot) => {
flex="~ col" border="r main"
overflow-y-auto
>
<div flex="~ gap2 items-center" p2 tracking-widest op50>
<div flex="~ gap2 items-center" p2 tracking-widest class="op75 dark:op50">
<span flex-auto text-center text-sm>{{ inspectSSR ? 'SSR ' : '' }}TRANSFORM STACK</span>
<button class="icon-btn" title="Toggle bailout plugins" @click="showBailout = !showBailout">
<div :class="showBailout ? 'opacity-100 i-carbon-view' : 'opacity-50 i-carbon-view-off'" />
</button>
</div>
<div border="b main" />
<template v-for="tr of filteredTransforms" :key="tr.name">
<template v-for="tr of filteredTransforms" :key="tr.index">
<button
border="b main"
flex="~ gap-1 wrap"
Expand All @@ -154,37 +154,44 @@ getHot().then((hot) => {
</span>
<Badge
v-if="!tr.result"
bg-gray-400:10 text-gray-400
class="bg-gray-400:10 text-gray-700 dark:text-gray-400"
v-text="'bailout'"
/>
<Badge
v-else-if="tr.noChange"
bg-orange-400:10 text-orange-400
class="bg-orange-400:10 text-orange-800 dark:text-orange-400"
v-text="'no change'"
/>
<Badge
v-if="tr.load"
class="bg-light-blue-400/10 text-light-blue-400"
class="bg-light-blue-400/10 text-blue-700 dark:text-light-blue-400"
v-text="'load'"
/>
<Badge
v-if="tr.order && tr.order !== 'normal'"
bg-rose-400:10 text-rose-400
class="bg-violet-400:10 text-violet-700 dark:text-violet-400"
:title="tr.order.includes('-') ? `Using object hooks ${tr.order}` : tr.order"
v-text="tr.order"
/>
<Badge
v-if="tr.error"
bg-red-400:10 text-red-400
class="bg-red-400:10 text-red7 dark:text-red-400"
v-text="'error'"
/>
<span flex-auto text-right text-xs op50>{{ msToTime(tr.end - tr.start) }}</span>
<span flex-auto text-right text-xs class="op75 dark:op60">{{ msToTime(tr.end - tr.start) }}</span>
</button>
</template>
</Pane>
<Pane min-size="5">
<div h-full of-auto>
<ErrorDisplay
v-if="currentTransform?.error"
:key="`error-${id}`"
:error="currentTransform.error"
/>
<DiffEditor
v-else
:key="id"
:one-column="showOneColumn || !!currentTransform?.error"
:diff="enableDiff && !currentTransform?.error"
:from="from" :to="to"
Expand Down
21 changes: 16 additions & 5 deletions src/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { isAbsolute, join, resolve } from 'node:path'
import { createServer } from 'node:http'
import type { AddressInfo } from 'node:net'
import process from 'node:process'
import { parse as parseErrorStacks } from 'error-stack-parser-es'
import fs from 'fs-extra'
import _debug from 'debug'
import type { Connect, Plugin, ResolvedConfig, ViteDevServer } from 'vite'
Expand All @@ -12,7 +13,7 @@ import { createFilter } from '@rollup/pluginutils'
import { createRPCServer } from 'vite-dev-rpc'
import { hash } from 'ohash'
import c from 'picocolors'
import type { HMRData, ModuleInfo, ModuleTransformInfo, PluginMetricInfo, RPCFunctions, ResolveIdInfo, TransformInfo } from '../types'
import type { HMRData, ModuleInfo, ModuleTransformInfo, ParsedError, PluginMetricInfo, RPCFunctions, ResolveIdInfo, TransformInfo } from '../types'
import { DIR_CLIENT } from '../dir'

const debug = _debug('vite-plugin-inspect')
Expand Down Expand Up @@ -282,7 +283,7 @@ export default function PluginInspect(options: Options = {}): Plugin {
}
const end = Date.now()

const result = error ? stringifyError(error) : (typeof _result === 'string' ? _result : _result?.code)
const result = error ? '[Error]' : (typeof _result === 'string' ? _result : _result?.code)
if (filter(id)) {
const sourcemaps = typeof _result === 'string' ? null : _result?.map
const map = ssr ? transformMapSSR : transformMap
Expand All @@ -297,7 +298,7 @@ export default function PluginInspect(options: Options = {}): Plugin {
end,
order,
sourcemaps,
error,
error: error ? parseError(error) : undefined,
})
}

Expand All @@ -323,7 +324,7 @@ export default function PluginInspect(options: Options = {}): Plugin {
}
const end = Date.now()

const result = error ? stringifyError(error) : (typeof _result === 'string' ? _result : _result?.code)
const result = error ? '[Error]' : (typeof _result === 'string' ? _result : _result?.code)
const sourcemaps = typeof _result === 'string' ? null : _result?.map

const map = ssr ? transformMapSSR : transformMap
Expand All @@ -334,7 +335,7 @@ export default function PluginInspect(options: Options = {}): Plugin {
start,
end,
sourcemaps,
error,
error: error ? parseError(error) : undefined,
}]
}

Expand Down Expand Up @@ -713,3 +714,13 @@ export default function PluginInspect(options: Options = {}): Plugin {
PluginInspect.getViteInspectAPI = function (plugins: Plugin[]): ViteInspectAPI | undefined {
return plugins.find(p => p.name === NAME)?.api
}

function parseError(error: any): ParsedError {
const stack = parseErrorStacks(error)
const message = error.message || String(error)
return {
message,
stack,
raw: error,
}
}
11 changes: 9 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Awaitable } from '@antfu/utils'
import type { StackFrame } from 'error-stack-parser-es'

export interface TransformInfo {
name: string
Expand All @@ -7,7 +8,7 @@ export interface TransformInfo {
end: number
order?: string
sourcemaps?: any
error?: any
error?: ParsedError
}

export interface ResolveIdInfo {
Expand All @@ -16,7 +17,13 @@ export interface ResolveIdInfo {
start: number
end: number
order?: string
error?: any
error?: ParsedError
}

export interface ParsedError {
message: string
stack: StackFrame[]
raw?: any
}

export interface ModuleInfo {
Expand Down

0 comments on commit 93a2f60

Please sign in to comment.