Skip to content

Commit 3f4afb2

Browse files
committed
chore: update dependencies and remove unused packages
- Removed '@unocss/runtime' from pnpm-lock.yaml and pnpm-workspace.yaml. - Added 'dompurify' with version ^3.4.15 to pnpm-lock.yaml and pnpm-workspace.yaml. - Updated '@types/trusted-types' to version 2.0.7 in pnpm-lock.yaml. - Cleaned up unnecessary entries in the lock file.
1 parent 1a15066 commit 3f4afb2

15 files changed

Lines changed: 184 additions & 298 deletions

File tree

packages/devtools-ui-kit/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"@vueuse/integrations": "catalog:frontend",
4747
"@vueuse/nuxt": "catalog:buildtools",
4848
"defu": "catalog:prod",
49+
"dompurify": "catalog:frontend",
4950
"focus-trap": "catalog:frontend",
5051
"splitpanes": "catalog:frontend",
5152
"unocss": "catalog:buildtools",
Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
<script setup lang="ts">
2-
defineProps<{
2+
import { ref, watchEffect } from 'vue'
3+
import { getIconifySvg } from '../composables/iconify'
4+
5+
const props = defineProps<{
36
icon?: string
47
}>()
8+
9+
const svg = ref<string | undefined>()
10+
11+
watchEffect(async () => {
12+
svg.value = props.icon ? await getIconifySvg(props.icon) : undefined
13+
})
514
</script>
615

716
<template>
8-
<div class="n-icon" :class="icon" />
17+
<div
18+
v-if="svg"
19+
class="n-icon"
20+
inline-block align-middle
21+
v-html="svg"
22+
/>
23+
<div v-else class="n-icon" :class="icon" />
924
</template>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { parseIconWithLoader } from '@unocss/preset-icons/browser'
2+
import DOMPurify from 'dompurify'
3+
4+
// The client can be embedded directly into a host page's DOM as a
5+
// shadow-rooted custom element with no iframe of its own. UnoCSS's atomic
6+
// classes (build-time and `@unocss/runtime` alike) inject/observe against
7+
// `document`, which is the host page's single document either way — outside
8+
// the shadow boundary, invisible to anything mounted inside it. Icons are the
9+
// one part of this UI whose class names aren't all known at the client's own
10+
// build time (an installed Nuxt module can report any Iconify id as its
11+
// icon), so they can't be fully covered by the build-time UnoCSS extraction
12+
// either. Fetching and inlining the SVG ourselves sidesteps both problems —
13+
// no CSS generation, no DOM root to get wrong.
14+
const cache = new Map<string, Promise<string | undefined>>()
15+
16+
async function fetchIconifySvg(collection: string, icon: string): Promise<string | undefined> {
17+
const url = `https://api.iconify.design/${collection}/${icon}.svg?color=currentColor&width=1.2em&height=1.2em`
18+
try {
19+
const res = await fetch(url, { signal: AbortSignal.timeout(10_000) })
20+
if (!res.ok)
21+
return undefined
22+
return DOMPurify.sanitize(await res.text(), { USE_PROFILES: { svg: true } })
23+
}
24+
catch {
25+
// Offline / flaky CDN — degrade to a blank icon rather than throwing out
26+
// of the caller's async effect.
27+
return undefined
28+
}
29+
}
30+
31+
/**
32+
* Resolve a UnoCSS-style icon id (`carbon-tree-view-alt`, `i-logos-vue`,
33+
* `carbon:settings`, ...) to inline, sanitized SVG markup, fetched from the
34+
* Iconify API and cached in-memory. Returns `undefined` when the id doesn't
35+
* parse as a known Iconify collection, or the fetch fails.
36+
*/
37+
export function getIconifySvg(id: string): Promise<string | undefined> {
38+
const cached = cache.get(id)
39+
if (cached)
40+
return cached
41+
42+
const promise = parseIconWithLoader(id.replace(/^i-/, ''), fetchIconifySvg)
43+
.then(result => result?.svg)
44+
.catch(() => undefined)
45+
cache.set(id, promise)
46+
// Don't cache a failed lookup — a later render (e.g. once back online) can
47+
// retry it.
48+
promise.then(svg => svg === undefined && cache.delete(id))
49+
return promise
50+
}

packages/devtools/client/app.vue

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@ import 'vanilla-jsoneditor/themes/jse-theme-dark.css'
1717
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
1818
import './styles/global.css'
1919
20-
if (import.meta.client)
21-
import('./setup/unocss-runtime')
22-
2320
useHead({
2421
title: 'Nuxt DevTools',
2522
meta: [

packages/devtools/client/components/AssetListItem.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const icon = computed(() => {
4646
border="b base"
4747
@click="isCollection ? open = !open : model = item"
4848
>
49-
<div :class="icon" />
49+
<NIcon :icon="icon" />
5050
<span :class="{ 'flex items-center': isCollection }" flex-auto text-start text-sm font-mono>
5151
{{ item.path }}
5252
<NIcon v-if="item.layer" icon="i-carbon-layers" bg-primary />

packages/devtools/client/components/FileIcon.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ const icon = computed(() => {
1717
</script>
1818

1919
<template>
20-
<div :class="icon" />
20+
<NIcon :icon="icon" />
2121
</template>

packages/devtools/client/components/ModuleTreeNode.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const activeId = computed(() => (route.params as { id?: string }).id)
2525
flex="~ gap2"
2626
>
2727
<div carbon-arrow />
28-
<div :class="icon" />
28+
<NIcon :icon="icon" />
2929
{{ node.name }}
3030
</summary>
3131

packages/devtools/client/components/TabIcon.vue

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
<script setup lang="ts">
2-
withDefaults(defineProps<{
2+
import { ref, watchEffect } from 'vue'
3+
import { getIconifySvg } from '../../../devtools-ui-kit/src/composables/iconify'
4+
5+
const props = withDefaults(defineProps<{
36
icon?: string
47
title?: string
58
showTitle?: boolean
69
}>(), {
710
showTitle: true,
811
})
12+
13+
const svg = ref<string | undefined>()
14+
15+
watchEffect(async () => {
16+
svg.value = props.icon ? await getIconifySvg(props.icon) : undefined
17+
})
918
</script>
1019

1120
<template>
@@ -19,6 +28,16 @@ withDefaults(defineProps<{
1928
:src="icon"
2029
:alt="title"
2130
>
31+
<div
32+
v-else-if="svg"
33+
:style="{
34+
width: '1em',
35+
height: '1em',
36+
}"
37+
v-bind="$attrs"
38+
:title="showTitle ? title : undefined"
39+
v-html="svg"
40+
/>
2241
<div
2342
v-else
2443
:style="{

packages/devtools/client/nuxt.config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ export default defineNuxtConfig({
137137
optimizeDeps: {
138138
include: [
139139
'@unocss/preset-icons/browser',
140-
'@unocss/runtime',
141140
'cronstrue',
142141
'diff',
143142
'error-stack-parser-es',

packages/devtools/client/setup/unocss-runtime.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)