Skip to content

Commit fd046b6

Browse files
antfuhannoeru
andauthored
feat: inspector (#77)
Co-authored-by: hanlee <me@hanlee.co>
1 parent bf73012 commit fd046b6

48 files changed

Lines changed: 1297 additions & 191 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,12 @@ import './my-custom.css'
438438
import 'uno:utilities.css'
439439
```
440440

441+
### Inspector
442+
443+
From v0.7.0, our Vite plugin now ships with a inspector for you to inspect and degbug your setup. Visit `http://localhost:3000/__unocss` in your Vite dev server to see the inspector.
444+
445+
<img src="https://user-images.githubusercontent.com/11247099/140885990-1827f5ce-f12a-4ed4-9d63-e5145a65fb4a.png">
446+
441447
### CSS Scoping
442448

443449
> 🚧 This part is still under experiment. You might want to read the code to see how it works currently.

package.json

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
"lint:fix": "nr lint -- --fix",
1111
"play": "npm -C playground run dev",
1212
"play:build": "pnpm run build && npm -C playground run build",
13-
"size": "esmo scripts/size.ts",
1413
"release": "bumpp package.json packages/*/package.json --commit --push --tag",
14+
"size": "esmo scripts/size.ts",
1515
"test": "jest",
1616
"test:update": "jest -u"
1717
},
@@ -26,7 +26,9 @@
2626
"@iconify-json/tabler": "^1.0.1",
2727
"@iconify-json/twemoji": "^1.0.2",
2828
"@iconify-json/uim": "^1.0.2",
29+
"@types/codemirror": "^5.60.5",
2930
"@types/jest": "^27.0.2",
31+
"@types/lz-string": "^1.3.34",
3032
"@types/node": "^16.11.6",
3133
"@types/ws": "^8.2.0",
3234
"@unocss/core": "workspace:*",
@@ -35,20 +37,32 @@
3537
"@unocss/preset-uno": "workspace:*",
3638
"@unocss/reset": "workspace:*",
3739
"@unocss/vite": "workspace:*",
40+
"@vitejs/plugin-vue": "^1.9.4",
3841
"@vueuse/core": "^6.7.4",
3942
"brotli-size": "^4.0.0",
4043
"bumpp": "^7.1.1",
44+
"codemirror": "^5.63.3",
45+
"codemirror-theme-vars": "^0.1.1",
4146
"eslint": "^8.1.0",
4247
"eslint-plugin-jest": "^25.2.2",
4348
"esno": "^0.10.1",
4449
"fast-glob": "^3.2.7",
4550
"gzip-size": "^6.0.0",
4651
"jest": "^27.3.1",
52+
"lz-string": "^1.4.4",
53+
"prettier": "^2.4.1",
54+
"splitpanes": "^3.0.6",
4755
"terser": "^5.9.0",
4856
"ts-jest": "^27.0.7",
4957
"tsup": "^5.5.0",
5058
"typescript": "^4.4.4",
5159
"unocss": "workspace:*",
52-
"ws": "^8.2.3"
60+
"unplugin-auto-import": "^0.4.13",
61+
"unplugin-vue-components": "^0.17.2",
62+
"vite": "^2.6.13",
63+
"vite-plugin-inspect": "^0.3.9",
64+
"vite-plugin-pages": "^0.18.2",
65+
"vue": "^3.2.21",
66+
"vue-router": "^4.0.12"
5367
}
5468
}

packages/core/src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export function resolveConfig(
6565
mergeSelectors: true,
6666
warnExcluded: true,
6767
excluded: [],
68+
presets: [],
6869
sortLayers: layers => layers,
6970
...config,
7071
envMode: config.envMode || 'build',

packages/core/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ export interface UserOnlyOptions<Theme extends {} = {}> {
213213
export interface UserConfig<Theme extends {} = {}> extends ConfigBase<Theme>, UserOnlyOptions<Theme>, GeneratorOptions {}
214214
export interface UserConfigDefaults<Theme extends {} = {}> extends ConfigBase<Theme>, UserOnlyOptions<Theme> {}
215215

216-
export interface ResolvedConfig extends Omit<Required<UserConfig>, 'presets' | 'rules' | 'shortcuts'> {
216+
export interface ResolvedConfig extends Omit<Required<UserConfig>, 'rules' | 'shortcuts'> {
217217
shortcuts: Shortcut[]
218218
variants: VariantObject[]
219219
rulesSize: number

packages/inspector/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# @unocss/inspector
2+
3+
The inspector UI for UnoCSS. Ships with `unocss` and `@unocss/vite`.
4+
5+
Visit `http://localhost:3000/__unocss` in your Vite dev server to see the inspector.
6+
7+
<img src="https://user-images.githubusercontent.com/11247099/140885990-1827f5ce-f12a-4ed4-9d63-e5145a65fb4a.png">
8+
<img src="https://user-images.githubusercontent.com/11247099/140886020-7014f412-f020-4aed-a169-d025cc1bbcd3.png">
9+
10+
## TODO
11+
12+
- [x] Basic Overview
13+
- [x] Basic REPL
14+
- [x] Basic file view
15+
- [ ] Data caches (move the fetches to shared modules instead of in components)
16+
- [ ] Manual refresh button
17+
- [ ] Resizeable sidebar (use `splitpanes`, refer to playground)
18+
- [ ] Auto reload on file changes (reuse Vite's hmr if possible)
19+
- [ ] Config view
20+
- [ ] Edit files directly
21+
- [ ] CSS Prettify
22+
23+
> 🙌 Contribution welcome!
24+
25+
## License
26+
27+
MIT License © 2021-PRESENT [Anthony Fu](https://github.com/antfu)

packages/inspector/client/App.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<template>
2+
<div h-full grid="~ cols-[1fr,4fr]">
3+
<Sidebar />
4+
<div h-full of-hidden>
5+
<RouterView />
6+
</div>
7+
</div>
8+
</template>
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// Generated by 'unplugin-auto-import'
2+
// We suggest you to commit this file into source control
3+
declare global {
4+
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
5+
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
6+
const biSyncRef: typeof import('@vueuse/core')['biSyncRef']
7+
const computed: typeof import('vue')['computed']
8+
const computedInject: typeof import('@vueuse/core')['computedInject']
9+
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
10+
const controlledRef: typeof import('@vueuse/core')['controlledRef']
11+
const createApp: typeof import('vue')['createApp']
12+
const createEventHook: typeof import('@vueuse/core')['createEventHook']
13+
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
14+
const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
15+
const customRef: typeof import('vue')['customRef']
16+
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
17+
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
18+
const defineComponent: typeof import('vue')['defineComponent']
19+
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
20+
const effectScope: typeof import('vue')['effectScope']
21+
const EffectScope: typeof import('vue')['EffectScope']
22+
const extendRef: typeof import('@vueuse/core')['extendRef']
23+
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
24+
const getCurrentScope: typeof import('vue')['getCurrentScope']
25+
const h: typeof import('vue')['h']
26+
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
27+
const inject: typeof import('vue')['inject']
28+
const isDefined: typeof import('@vueuse/core')['isDefined']
29+
const isReadonly: typeof import('vue')['isReadonly']
30+
const isRef: typeof import('vue')['isRef']
31+
const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
32+
const markRaw: typeof import('vue')['markRaw']
33+
const nextTick: typeof import('vue')['nextTick']
34+
const onActivated: typeof import('vue')['onActivated']
35+
const onBeforeMount: typeof import('vue')['onBeforeMount']
36+
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
37+
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
38+
const onClickOutside: typeof import('@vueuse/core')['onClickOutside']
39+
const onDeactivated: typeof import('vue')['onDeactivated']
40+
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
41+
const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke']
42+
const onMounted: typeof import('vue')['onMounted']
43+
const onRenderTracked: typeof import('vue')['onRenderTracked']
44+
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
45+
const onScopeDispose: typeof import('vue')['onScopeDispose']
46+
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
47+
const onStartTyping: typeof import('@vueuse/core')['onStartTyping']
48+
const onUnmounted: typeof import('vue')['onUnmounted']
49+
const onUpdated: typeof import('vue')['onUpdated']
50+
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
51+
const provide: typeof import('vue')['provide']
52+
const reactify: typeof import('@vueuse/core')['reactify']
53+
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
54+
const reactive: typeof import('vue')['reactive']
55+
const reactivePick: typeof import('@vueuse/core')['reactivePick']
56+
const readonly: typeof import('vue')['readonly']
57+
const ref: typeof import('vue')['ref']
58+
const refDefault: typeof import('@vueuse/core')['refDefault']
59+
const shallowReactive: typeof import('vue')['shallowReactive']
60+
const shallowReadonly: typeof import('vue')['shallowReadonly']
61+
const shallowRef: typeof import('vue')['shallowRef']
62+
const syncRef: typeof import('@vueuse/core')['syncRef']
63+
const templateRef: typeof import('@vueuse/core')['templateRef']
64+
const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
65+
const toRaw: typeof import('vue')['toRaw']
66+
const toReactive: typeof import('@vueuse/core')['toReactive']
67+
const toRef: typeof import('vue')['toRef']
68+
const toRefs: typeof import('vue')['toRefs']
69+
const triggerRef: typeof import('vue')['triggerRef']
70+
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
71+
const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted']
72+
const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose']
73+
const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted']
74+
const unref: typeof import('vue')['unref']
75+
const unrefElement: typeof import('@vueuse/core')['unrefElement']
76+
const until: typeof import('@vueuse/core')['until']
77+
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
78+
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
79+
const useAttrs: typeof import('vue')['useAttrs']
80+
const useBattery: typeof import('@vueuse/core')['useBattery']
81+
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
82+
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
83+
const useClipboard: typeof import('@vueuse/core')['useClipboard']
84+
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
85+
const useCounter: typeof import('@vueuse/core')['useCounter']
86+
const useCssModule: typeof import('vue')['useCssModule']
87+
const useCssVar: typeof import('@vueuse/core')['useCssVar']
88+
const useDark: typeof import('@vueuse/core')['useDark']
89+
const useDebounce: typeof import('@vueuse/core')['useDebounce']
90+
const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
91+
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
92+
const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion']
93+
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
94+
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
95+
const useDevicesList: typeof import('@vueuse/core')['useDevicesList']
96+
const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia']
97+
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
98+
const useDraggable: typeof import('@vueuse/core')['useDraggable']
99+
const useElementBounding: typeof import('@vueuse/core')['useElementBounding']
100+
const useElementHover: typeof import('@vueuse/core')['useElementHover']
101+
const useElementSize: typeof import('@vueuse/core')['useElementSize']
102+
const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility']
103+
const useEventBus: typeof import('@vueuse/core')['useEventBus']
104+
const useEventListener: typeof import('@vueuse/core')['useEventListener']
105+
const useEventSource: typeof import('@vueuse/core')['useEventSource']
106+
const useFavicon: typeof import('@vueuse/core')['useFavicon']
107+
const useFetch: typeof import('@vueuse/core')['useFetch']
108+
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
109+
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
110+
const useIdle: typeof import('@vueuse/core')['useIdle']
111+
const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
112+
const useInterval: typeof import('@vueuse/core')['useInterval']
113+
const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn']
114+
const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier']
115+
const useLastChanged: typeof import('@vueuse/core')['useLastChanged']
116+
const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage']
117+
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
118+
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
119+
const useMediaControls: typeof import('@vueuse/core')['useMediaControls']
120+
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
121+
const useMouse: typeof import('@vueuse/core')['useMouse']
122+
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
123+
const useMousePressed: typeof import('@vueuse/core')['useMousePressed']
124+
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
125+
const useNetwork: typeof import('@vueuse/core')['useNetwork']
126+
const useNow: typeof import('@vueuse/core')['useNow']
127+
const useOnline: typeof import('@vueuse/core')['useOnline']
128+
const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
129+
const useParallax: typeof import('@vueuse/core')['useParallax']
130+
const usePermission: typeof import('@vueuse/core')['usePermission']
131+
const usePointer: typeof import('@vueuse/core')['usePointer']
132+
const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
133+
const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
134+
const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
135+
const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
136+
const useRafFn: typeof import('@vueuse/core')['useRafFn']
137+
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
138+
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
139+
const useRoute: typeof import('vue-router')['useRoute']
140+
const useRouter: typeof import('vue-router')['useRouter']
141+
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
142+
const useScroll: typeof import('@vueuse/core')['useScroll']
143+
const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
144+
const useShare: typeof import('@vueuse/core')['useShare']
145+
const useSlots: typeof import('vue')['useSlots']
146+
const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
147+
const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
148+
const useStorage: typeof import('@vueuse/core')['useStorage']
149+
const useSwipe: typeof import('@vueuse/core')['useSwipe']
150+
const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
151+
const useThrottle: typeof import('@vueuse/core')['useThrottle']
152+
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
153+
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
154+
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
155+
const useTimeout: typeof import('@vueuse/core')['useTimeout']
156+
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
157+
const useTimestamp: typeof import('@vueuse/core')['useTimestamp']
158+
const useTitle: typeof import('@vueuse/core')['useTitle']
159+
const useToggle: typeof import('@vueuse/core')['useToggle']
160+
const useTransition: typeof import('@vueuse/core')['useTransition']
161+
const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
162+
const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
163+
const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
164+
const useVModel: typeof import('@vueuse/core')['useVModel']
165+
const useVModels: typeof import('@vueuse/core')['useVModels']
166+
const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
167+
const useWebSocket: typeof import('@vueuse/core')['useWebSocket']
168+
const useWebWorker: typeof import('@vueuse/core')['useWebWorker']
169+
const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn']
170+
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
171+
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
172+
const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
173+
const watch: typeof import('vue')['watch']
174+
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
175+
const watchEffect: typeof import('vue')['watchEffect']
176+
const watchOnce: typeof import('@vueuse/core')['watchOnce']
177+
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
178+
const whenever: typeof import('@vueuse/core')['whenever']
179+
}
180+
export {}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// generated by unplugin-vue-components
2+
// We suggest you to commit this file into source control
3+
// Read more: https://github.com/vuejs/vue-next/pull/3399
4+
5+
declare module 'vue' {
6+
export interface GlobalComponents {
7+
CodeMirror: typeof import('./components/CodeMirror.vue')['default']
8+
FileIcon: typeof import('./components/FileIcon.vue')['default']
9+
ModuleId: typeof import('./components/ModuleId.vue')['default']
10+
ModuleInfo: typeof import('./components/ModuleInfo.vue')['default']
11+
ModuleList: typeof import('./components/ModuleList.vue')['default']
12+
ModuleTree: typeof import('./components/ModuleTree.vue')['default']
13+
ModuleTreeNode: typeof import('./components/ModuleTreeNode.vue')['default']
14+
NarBar: typeof import('./components/NarBar.vue')['default']
15+
Overview: typeof import('./components/Overview.vue')['default']
16+
Repl: typeof import('./components/Repl.vue')['default']
17+
REPL: typeof import('./components/REPL.vue')['default']
18+
ReplPlayground: typeof import('./components/ReplPlayground.vue')['default']
19+
Sidebar: typeof import('./components/Sidebar.vue')['default']
20+
StatusBar: typeof import('./components/StatusBar.vue')['default']
21+
TitleBar: typeof import('./components/TitleBar.vue')['default']
22+
}
23+
}
24+
25+
export { }

playground/src/components/CodeMirror.vue renamed to packages/inspector/client/components/CodeMirror.vue

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,33 @@
11
<script setup lang="ts">
2-
import { getMatchedPositions } from '../logics/pos'
3-
import { useCodeMirror } from '../logics/codemirror'
2+
import { getMatchedPositions } from '../composables/pos'
3+
import { useCodeMirror } from '../composables/codemirror'
44
5+
const emit = defineEmits<{ (input: any): void }>()
56
const props = defineProps<{
67
modelValue: string
78
mode?: string
89
readOnly?: boolean
9-
matched?: Set<string>
10-
}>()
11-
const emit = defineEmits<{
12-
(input: any): void
10+
matched?: Set<string> | string[]
1311
}>()
1412
13+
const modeMap: Record<string, string> = {
14+
html: 'htmlmixed',
15+
vue: 'htmlmixed',
16+
js: 'javascript',
17+
mjs: 'javascript',
18+
cjs: 'javascript',
19+
ts: 'typescript',
20+
mts: 'typescript',
21+
}
22+
1523
const el = ref<HTMLTextAreaElement>()
1624
const input = useVModel(props, 'modelValue', emit, { passive: true })
1725
1826
onMounted(async() => {
19-
const cm = useCodeMirror(el, input, props)
27+
const cm = useCodeMirror(el, input, {
28+
...props,
29+
mode: modeMap[props.mode || ''] || props.mode,
30+
})
2031
cm.setSize('100%', '100%')
2132
setTimeout(() => cm.refresh(), 100)
2233
const decorations: CodeMirror.TextMarker<CodeMirror.MarkerRange>[] = []
@@ -32,15 +43,15 @@ onMounted(async() => {
3243
function highlight() {
3344
// clear previous
3445
decorations.forEach(i => i.clear())
35-
36-
getMatchedPositions(input.value, props.matched || new Set())
46+
getMatchedPositions(props.modelValue, Array.from(props.matched || []))
3747
.forEach(i => mark(...i))
3848
}
3949
40-
watchEffect(() => {
50+
watch(() => [props.modelValue, props.matched], async() => {
51+
await nextTick()
4152
if (props.matched)
4253
highlight()
43-
})
54+
}, { immediate: true })
4455
})
4556
</script>
4657

@@ -114,4 +125,8 @@ html.dark {
114125
--cm-line-highlight-background: #444444;
115126
--cm-selection-background: #44444450;
116127
}
128+
129+
.highlighted {
130+
border-bottom: 1px dashed currentColor;
131+
}
117132
</style>

0 commit comments

Comments
 (0)