Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@iconify-json/catppuccin": "catalog:icons",
"@iconify-json/codicon": "catalog:icons",
"@iconify-json/fluent": "catalog:icons",
"@iconify-json/fluent-emoji-flat": "catalog:icons",
"@iconify-json/logos": "catalog:icons",
"@iconify-json/octicon": "catalog:icons",
"@iconify-json/ph": "catalog:icons",
Expand Down
21 changes: 18 additions & 3 deletions packages/core/src/client/standalone/App.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<script setup lang="ts">
import type { DocksContext } from '@vitejs/devtools-kit/client'
import { getDevToolsRpcClient } from '@vitejs/devtools-kit/client'
import { markRaw, useTemplateRef } from 'vue'
import { markRaw, ref, useTemplateRef, watch } from 'vue'
import DockEntries from '../webcomponents/components/DockEntries.vue'
import VitePlus from '../webcomponents/components/icons/VitePlus.vue'
import ViewBuiltinClientAuthNotice from '../webcomponents/components/ViewBuiltinClientAuthNotice.vue'
import ViewEntry from '../webcomponents/components/ViewEntry.vue'
import { createDocksContext } from '../webcomponents/state/context'
import { PersistedDomViewsManager } from '../webcomponents/utils/PersistedDomViewsManager'
Expand All @@ -21,11 +22,25 @@ const context: DocksContext = await createDocksContext(
rpc,
)

context.docks.selectedId ||= context.docks.entries[0]?.id ?? null
const isRpcTrusted = ref(context.rpc.isTrusted)
context.rpc.events.on('rpc:is-trusted:updated', (isTrusted) => {
isRpcTrusted.value = isTrusted
})

watch(
() => context.docks.entries,
() => {
context.docks.selectedId ||= context.docks.entries[0]?.id ?? null
},
{ immediate: true },
)
</script>

<template>
<div class="h-screen w-screen of-hidden grid cols-[max-content_1fr]">
<div v-if="!isRpcTrusted" class="h-screen w-screen of-hidden">
<ViewBuiltinClientAuthNotice :context="context" />
</div>
<div v-else class="h-screen w-screen of-hidden grid cols-[max-content_1fr]">
<div class="border-r border-base flex flex-col">
<div class="p2 border-b border-base flex">
<VitePlus class="w-7 h-7 ma" />
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/client/standalone/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ export default defineConfig({
name: 'setup',
async configureServer(viteDevServer) {
const context = await createDevToolsContext(viteDevServer.config, viteDevServer)
const host = viteDevServer.config.server.host === true
? '0.0.0.0'
: viteDevServer.config.server.host || 'localhost'
const { middleware } = await createDevToolsMiddleware({
cwd: viteDevServer.config.root,
hostWebSocket: host,
context,
})
viteDevServer.middlewares.use('/.devtools', middleware)
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/client/webcomponents/.generated/css.ts

Large diffs are not rendered by default.

47 changes: 42 additions & 5 deletions packages/core/src/client/webcomponents/components/Dock.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import type { DocksContext } from '@vitejs/devtools-kit/client'
import { useEventListener, useScreenSafeArea } from '@vueuse/core'
import { computed, onMounted, reactive, ref, useTemplateRef, watchEffect } from 'vue'
import { BUILTIN_ENTRY_CLIENT_AUTH_NOTICE } from '../constants'
import DockEntries from './DockEntries.vue'
import BracketLeft from './icons/BracketLeft.vue'
import BracketRight from './icons/BracketRight.vue'
Expand Down Expand Up @@ -64,6 +65,13 @@ function onPointerDown(e: PointerEvent) {
draggingOffset.y = e.clientY - top - height / 2
}

const isRpcTrusted = ref(context.rpc.isTrusted)
context.rpc.events.on('rpc:is-trusted:updated', (isTrusted) => {
isRpcTrusted.value = isTrusted
if (isTrusted && context.docks.selected?.id === BUILTIN_ENTRY_CLIENT_AUTH_NOTICE.id)
context.docks.switchEntry(null)
})

onMounted(() => {
windowSize.width = window.innerWidth
windowSize.height = window.innerHeight
Expand Down Expand Up @@ -220,7 +228,10 @@ const panelStyle = computed(() => {
})

onMounted(() => {
bringUp()
if (context.panel.store.open && !isRpcTrusted.value)
context.panel.store.open = false
if (isRpcTrusted.value)
bringUp()
recalculateCounter.value++
})
</script>
Expand Down Expand Up @@ -264,13 +275,39 @@ onMounted(() => {
class="vite-devtools-dock-bracket absolute right--1 top-1/2 translate-y--1/2 bottom-0 w-2.5 op75 transition-opacity duration-300"
:class="context.panel.isVertical ? 'scale-y--100' : ''"
/>
<VitePlusCore
<div
class="w-3 h-3 absolute left-1/2 top-1/2 translate-x--1/2 translate-y--1/2 transition-opacity duration-300"
:class="isMinimized ? 'op100' : 'op0'"
/>
:class="[
isMinimized ? 'op100' : 'op0',
context.panel.isVertical ? 'rotate-270' : 'rotate-0',
]"
>
<VitePlusCore />
<div v-if="!isRpcTrusted" class="i-fluent-emoji-flat-warning absolute bottom-0 right--1px w-1.5 h-1.5" />
</div>
<div
v-if="!isRpcTrusted"
class="transition duration-300 delay-200"
:class="isMinimized ? 'opacity-0 pointer-events-none ws-nowrap text-sm text-orange of-hidden' : 'opacity-100'"
>
<button
class="p2 transition hover:bg-active rounded-full px4"
@click="context.docks.toggleEntry(BUILTIN_ENTRY_CLIENT_AUTH_NOTICE.id)"
>
<div class="flex items-center gap-1">
<div
class="i-fluent-emoji-flat-warning flex-none"
:class="context.panel.isVertical ? 'rotate-270' : 'rotate-0'"
/>
<div class="ws-nowrap text-amber">
Unauthorized
</div>
</div>
</button>
</div>
<DockEntries
:entries="context.docks.entries"
class="transition duration-200 flex items-center w-full h-full justify-center"
class="transition duration-200 flex items-center w-full h-full justify-center px3"
:class="isMinimized ? 'opacity-0 pointer-events-none' : 'opacity-100'"
:is-vertical="context.panel.isVertical"
:selected="context.docks.selected"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ onMounted(() => {
<div
v-show="context.docks.selected && context.docks.selected.type !== 'action'"
ref="dockPanel"
class="bg-glass rounded-lg border border-base shadow"
class="bg-glass:75 rounded-lg border border-base shadow"
:style="panelStyle"
>
<DockPanelResizer :panel="context.panel" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script setup lang="ts">
import type { DocksContext } from '@vitejs/devtools-kit/client'
import VitePlus from './icons/VitePlus.vue'

defineProps<{
context: DocksContext
}>()
</script>

<template>
<div class="w-full h-full flex flex-col items-center justify-center p20">
<div class="max-w-150 flex flex-col items-center justify-center gap-2">
<VitePlus class="w-20 h-20" />
<h1 class="text-2xl font-bold text-violet mb2">
Vite DevTools is Unauthorized
</h1>
<p class="op75">
Vite DevTools offers advanced features that can access your server, view your filesystem, and execute commands.
</p>
<p class="op75">
To protect your project from unauthorized access, please authorize your browser before proceeding.
</p>
<p class="font-bold bg-green:5 p1 px3 rounded mt8 text-green">
Check your terminal for the authorization prompt and come back.
</p>
</div>
</div>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { DevToolsDockEntry } from '@vitejs/devtools-kit'
import type { DocksContext } from '@vitejs/devtools-kit/client'
import type { CSSProperties } from 'vue'
import type { PersistedDomViewsManager } from '../utils/PersistedDomViewsManager'
import ViewBuiltinClientAuthNotice from './ViewBuiltinClientAuthNotice.vue'
import ViewBuiltinTerminals from './ViewBuiltinTerminals.vue'
import ViewCustomRenderer from './ViewCustomRenderer.vue'
import ViewIframe from './ViewIframe.vue'
Expand All @@ -24,6 +25,10 @@ defineProps<{
:context
:entry
/>
<ViewBuiltinClientAuthNotice
v-else-if="entry.id === '~client-auth-notice'"
:context
/>
<div v-else>
Unknown builtin entry: {{ entry }}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<path d="M21.6002 31.5389C23.0982 32.7047 26.7882 30.4688 29.842 26.5449C32.8958 22.621 34.1571 18.4949 32.6591 17.3291C31.1611 16.1633 27.4711 18.3991 24.4173 22.3231C21.3635 26.247 20.1022 30.3731 21.6002 31.5389Z" fill="#2BFDD2" />
</g>
</g>
<path d="M6.95763 10C3.02563 15.628 3.00263 24.351 6.95763 30H9.61363C5.65963 24.35 5.68363 15.627 9.61363 10H6.95763ZM33.9386 20H36.5956C36.5946 16.407 35.6056 12.816 33.6386 10H30.9826C32.9486 12.816 33.9366 16.407 33.9386 20ZM38.6276 24.907H35.9626C36.1589 24.1665 36.3102 23.4148 36.4156 22.656H33.7586C33.6531 23.4148 33.5019 24.1665 33.3056 24.907H30.6366C30.3961 25.8176 30.0804 26.7067 29.6926 27.565H32.3616C31.9785 28.4179 31.5165 29.2331 30.9816 30H33.6376C34.1725 29.2331 34.6345 28.4179 35.0176 27.565H37.6826C38.0686 26.714 38.3836 25.823 38.6276 24.907Z" fill="#08060D" />
<path d="M6.95763 10C3.02563 15.628 3.00263 24.351 6.95763 30H9.61363C5.65963 24.35 5.68363 15.627 9.61363 10H6.95763ZM33.9386 20H36.5956C36.5946 16.407 35.6056 12.816 33.6386 10H30.9826C32.9486 12.816 33.9366 16.407 33.9386 20ZM38.6276 24.907H35.9626C36.1589 24.1665 36.3102 23.4148 36.4156 22.656H33.7586C33.6531 23.4148 33.5019 24.1665 33.3056 24.907H30.6366C30.3961 25.8176 30.0804 26.7067 29.6926 27.565H32.3616C31.9785 28.4179 31.5165 29.2331 30.9816 30H33.6376C34.1725 29.2331 34.6345 28.4179 35.0176 27.565H37.6826C38.0686 26.714 38.3836 25.823 38.6276 24.907Z" fill="#08060D" class="fill-hex-08060D dark:fill-hex-fff" />
<defs>
<filter id="filter0_f_3_2" x="1.62683" y="17.2322" width="25.6599" height="17.8001" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/client/webcomponents/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { DevToolsViewBuiltin } from '@vitejs/devtools-kit'

export const BUILTIN_ENTRY_CLIENT_AUTH_NOTICE: DevToolsViewBuiltin = Object.freeze({
type: '~builtin',
id: '~client-auth-notice',
title: 'Unauthorized',
icon: 'i-fluent-emoji-flat-warning',
})

export const BUILTIN_ENTRIES: readonly DevToolsViewBuiltin[] = Object.freeze([
BUILTIN_ENTRY_CLIENT_AUTH_NOTICE,
])
77 changes: 48 additions & 29 deletions packages/core/src/client/webcomponents/state/context.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { DevToolsRpcClient, DockClientScriptContext, DockEntryState, DockPanelStorage, DocksContext } from '@vitejs/devtools-kit/client'
import type { Ref } from 'vue'
import { computed, markRaw, reactive, ref, toRefs, watchEffect } from 'vue'
import { BUILTIN_ENTRIES } from '../constants'
import { createDockEntryState, DEFAULT_DOCK_PANEL_STORE, useDocksEntries } from './docks'
import { executeSetupScript } from './setup-script'

Expand All @@ -14,9 +15,13 @@ export async function createDocksContext(
return _docksContext
}

const selectedId = ref<string | null>(null)
const dockEntries = await useDocksEntries(rpc)
const selected = computed(() => dockEntries.value.find(entry => entry.id === selectedId.value) ?? null)
const selectedId = ref<string | null>(null)
const selected = computed(
() => dockEntries.value.find(entry => entry.id === selectedId.value)
?? BUILTIN_ENTRIES.find(entry => entry.id === selectedId.value)
?? null,
)

const dockEntryStateMap: Map<string, DockEntryState> = reactive(new Map())
watchEffect(() => {
Expand All @@ -34,6 +39,45 @@ export async function createDocksContext(

panelStore ||= ref(DEFAULT_DOCK_PANEL_STORE())

const switchEntry = async (id: string | null = null) => {
if (id == null) {
selectedId.value = null
return true
}
if (id === '~client-auth-notice') {
selectedId.value = id
panelStore.value.open = true
return true
}
const entry = dockEntries.value.find(e => e.id === id)
if (!entry)
return false

// If has import script, run it
if (
(entry.type === 'action')
|| (entry.type === 'custom-render')
|| (entry.type === 'iframe' && entry.clientScript)
) {
const current = dockEntryStateMap.get(id)!
const scriptContext: DockClientScriptContext = reactive({
...toRefs(_docksContext!) as any,
current,
})
await executeSetupScript(entry, scriptContext)
}

selectedId.value = entry.id
panelStore.value.open = true
return true
}

const toggleEntry = async (id: string) => {
if (selectedId.value === id)
return switchEntry(null)
return switchEntry(id)
}

_docksContext = reactive({
panel: {
store: panelStore,
Expand All @@ -47,33 +91,8 @@ export async function createDocksContext(
entries: dockEntries,
entryToStateMap: markRaw(dockEntryStateMap),
getStateById: (id: string) => dockEntryStateMap.get(id),
switchEntry: async (id: string | null = null) => {
if (id == null) {
selectedId.value = null
return true
}
const entry = dockEntries.value.find(e => e.id === id)
if (!entry)
return false

// If has import script, run it
if (
(entry.type === 'action')
|| (entry.type === 'custom-render')
|| (entry.type === 'iframe' && entry.clientScript)
) {
const current = dockEntryStateMap.get(id)!
const scriptContext: DockClientScriptContext = reactive({
...toRefs(_docksContext!) as any,
current,
})
await executeSetupScript(entry, scriptContext)
}

selectedId.value = entry.id
panelStore.value.open = true
return true
},
switchEntry,
toggleEntry,
},
rpc,
clientType,
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/client/webcomponents/state/docks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,19 @@ export async function useDocksEntries(rpc: DevToolsRpcClient): Promise<Ref<DevTo
}
const dockEntries = _docksEntriesRef = shallowRef<DevToolsDockEntry[]>([])
async function updateDocksEntries() {
if (!rpc.isTrusted) {
console.warn('[VITE DEVTOOLS] Untrusted client, skipping docks entries update')
return
}
dockEntries.value = (await rpc.call('vite:internal:docks:list'))
.map(entry => Object.freeze(entry))
// eslint-disable-next-line no-console
console.log('[VITE DEVTOOLS] Docks Entries Updated', [...dockEntries.value])
}
rpc.events.on('rpc:is-trusted:updated', (isTrusted) => {
if (isTrusted)
updateDocksEntries()
})
rpc.client.register({
name: 'vite:internal:docks:updated' satisfies keyof DevToolsRpcClientFunctions,
type: 'action',
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/client/webcomponents/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
}

#vite-devtools-anchor #vite-devtools-dock {
--uno: h-full rounded-full select-none touch-none px4 ma h-[40px];
--uno: h-full rounded-full select-none touch-none ma h-[40px];
--uno: shadow text-white bg-glass;
--uno: transition-all duration-500;
width: calc-size(max-content, size);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/client/webcomponents/uno.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default defineConfig({
'z-floating-anchor': 'z-[2147483644]',
'z-floating-tooltip': 'z-[2147483645]',
},
[/^bg-glass(:\d+)?$/, ([, opacity = ':50']) => `bg-white${opacity} dark:bg-#111${opacity} backdrop-blur-5`],
[/^bg-glass(:\d+)?$/, ([, opacity = ':50']) => `bg-white${opacity} dark:bg-#111${opacity} backdrop-blur-7`],
],
transformers: [
transformerDirectives(),
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/node/cli-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export async function start(options: StartOptions) {

const { h3 } = await createDevToolsMiddleware({
cwd: devtools.config.root,
hostWebSocket: host,
context: devtools.context,
})

Expand Down
Loading
Loading