From f99a3f29b098581a7af306546706dd9884dbb561 Mon Sep 17 00:00:00 2001 From: arlo Date: Sun, 17 Mar 2024 18:42:28 +0800 Subject: [PATCH] feat: pinia panel --- packages/devtools/client/app.vue | 2 + .../devtools/client/composables/state-tabs.ts | 4 +- .../client/composables/vue-devtools.ts | 7 + .../devtools/client/pages/modules/pinia.vue | 16 ++ .../devtools/client/setup/vue-devtools.ts | 56 +++++++ packages/devtools/package.json | 3 + .../devtools/src/integrations/vue-devtools.ts | 28 ++++ packages/devtools/src/module-main.ts | 2 + .../src/runtime/vue-devtools/overlay.js | 6 + pnpm-lock.yaml | 145 ++++++++++++++++-- 10 files changed, 259 insertions(+), 10 deletions(-) create mode 100644 packages/devtools/client/composables/vue-devtools.ts create mode 100644 packages/devtools/client/pages/modules/pinia.vue create mode 100644 packages/devtools/client/setup/vue-devtools.ts create mode 100644 packages/devtools/src/integrations/vue-devtools.ts create mode 100644 packages/devtools/src/runtime/vue-devtools/overlay.js diff --git a/packages/devtools/client/app.vue b/packages/devtools/client/app.vue index adcfdcd96f..932708ce59 100644 --- a/packages/devtools/client/app.vue +++ b/packages/devtools/client/app.vue @@ -5,6 +5,7 @@ import 'vue-virtual-scroller/dist/vue-virtual-scroller.css' import './styles/global.css' import { useEyeDropper } from '@vueuse/core' import { setupClientRPC } from './setup/client-rpc' +import { setupVueDevTools } from './setup/vue-devtools' import { splitScreenAvailable } from '~/composables/storage' if (process.client) @@ -27,6 +28,7 @@ useHead({ ], }) +setupVueDevTools() setupClientRPC() const client = useClient() diff --git a/packages/devtools/client/composables/state-tabs.ts b/packages/devtools/client/composables/state-tabs.ts index 5e505cbd1a..c7d9d55d84 100644 --- a/packages/devtools/client/composables/state-tabs.ts +++ b/packages/devtools/client/composables/state-tabs.ts @@ -6,10 +6,12 @@ export function useAllTabs() { const customTabs = useCustomTabs() const settings = useDevToolsUIOptions() const router = useRouter() - + const vueDevToolsState = useVueDevToolsState() + const piniaDetected = computed(() => vueDevToolsState.activeAppRecord.value?.moduleDetectives?.pinia) const builtin = computed(() => [ ...router.getRoutes() .filter(route => route.path.startsWith('/modules/') && route.meta.title && !route.meta.wip) + .filter(route => route.path.startsWith('/modules/pinia') ? (piniaDetected.value ? route : false) : route) .filter(route => !route.meta.experimental || (route.meta.experimental && settings.showExperimentalFeatures.value)) .sort((a, b) => (a.meta.order || 100) - (b.meta.order || 100)) .map((i): ModuleBuiltinTab => { diff --git a/packages/devtools/client/composables/vue-devtools.ts b/packages/devtools/client/composables/vue-devtools.ts new file mode 100644 index 0000000000..a04cee5de6 --- /dev/null +++ b/packages/devtools/client/composables/vue-devtools.ts @@ -0,0 +1,7 @@ +import { activeAppRecord } from '../setup/vue-devtools' + +export function useVueDevToolsState() { + return { + activeAppRecord, + } +} diff --git a/packages/devtools/client/pages/modules/pinia.vue b/packages/devtools/client/pages/modules/pinia.vue new file mode 100644 index 0000000000..6b3fa1138a --- /dev/null +++ b/packages/devtools/client/pages/modules/pinia.vue @@ -0,0 +1,16 @@ + + + diff --git a/packages/devtools/client/setup/vue-devtools.ts b/packages/devtools/client/setup/vue-devtools.ts new file mode 100644 index 0000000000..2262e1a212 --- /dev/null +++ b/packages/devtools/client/setup/vue-devtools.ts @@ -0,0 +1,56 @@ +import { HandShakeServer, getDevToolsState, initDevToolsSeparateWindow, initDevToolsSeparateWindowBridge, onDevToolsStateUpdated, setupDevToolsBridge } from '@vue/devtools-core' +import type { AppRecord } from '@vue/devtools-kit' +import { toggleHighPerfMode } from '@vue/devtools-kit' + +export type DevtoolsBridgeAppRecord = Pick + +const appRecords = ref>([]) +const activeAppRecordId = ref(null) +export const activeAppRecord = computed(() => appRecords.value.find(r => r.id === activeAppRecordId.value)) + +export function initVueDevToolsState() { + getDevToolsState().then((_data) => { + const data = _data! + appRecords.value = data.appRecords + activeAppRecordId.value = data.activeAppRecordId + }) + + onDevToolsStateUpdated((data) => { + appRecords.value = data.appRecords + activeAppRecordId.value = data.activeAppRecordId + }) + + return { + appRecords, + activeAppRecord, + } +} + +export function setupVueDevTools() { + const state = useDevToolsFrameState() + + const isInPopup = window.__NUXT_DEVTOOLS_IS_POPUP__ + + watchEffect(() => { + if (isInPopup) + toggleHighPerfMode(false) + + else + toggleHighPerfMode(!state.value?.open) + }) + + initDevToolsSeparateWindow({ + onConnected(channel) { + const bridge = initDevToolsSeparateWindowBridge(channel) + setupDevToolsBridge(bridge) + new HandShakeServer(bridge).onnConnect().then(() => { + bridge.emit('devtools:client-ready') + initVueDevToolsState() + }) + bridge.on('disconnect', () => { + channel.close() + initDevToolsSeparateWindow() + }) + }, + }) +} diff --git a/packages/devtools/package.json b/packages/devtools/package.json index f760691761..03b5ead206 100644 --- a/packages/devtools/package.json +++ b/packages/devtools/package.json @@ -47,6 +47,9 @@ "@nuxt/devtools-kit": "workspace:*", "@nuxt/devtools-wizard": "workspace:*", "@nuxt/kit": "^3.10.3", + "@vue/devtools-applet": "^7.0.18", + "@vue/devtools-core": "^7.0.18", + "@vue/devtools-kit": "^7.0.18", "birpc": "^0.2.17", "consola": "^3.2.3", "destr": "^2.0.3", diff --git a/packages/devtools/src/integrations/vue-devtools.ts b/packages/devtools/src/integrations/vue-devtools.ts new file mode 100644 index 0000000000..ea86da28b6 --- /dev/null +++ b/packages/devtools/src/integrations/vue-devtools.ts @@ -0,0 +1,28 @@ +import { addVitePlugin } from '@nuxt/kit' +import { join } from 'pathe' +import type { NuxtDevtoolsServerContext } from '../types' +import { runtimeDir } from '../dirs' + +export function setup({ nuxt }: NuxtDevtoolsServerContext) { + if (!nuxt.options.dev || nuxt.options.test) + return + + addVitePlugin({ + name: 'vue:devtools', + async resolveId(importee: string) { + if (importee.startsWith('virtual:vue-devtools-path:')) { + const resolved = importee.replace('virtual:vue-devtools-path:', join(runtimeDir, 'vue-devtools/')) + return resolved + } + }, + transform(code, id) { + const [filename] = id.split('?', 2) + const appendTo = /\/entry\.m?js$/ + + if (appendTo.test(filename)) + code = `import 'virtual:vue-devtools-path:overlay.js';\n${code}` + + return code + }, + }) +} diff --git a/packages/devtools/src/module-main.ts b/packages/devtools/src/module-main.ts index 13fe4117c1..7bd8f11298 100644 --- a/packages/devtools/src/module-main.ts +++ b/packages/devtools/src/module-main.ts @@ -185,6 +185,8 @@ window.__NUXT_DEVTOOLS_TIME_METRIC__.appInit = Date.now() await import('./integrations/plugin-metrics').then(({ setup }) => setup(ctx)) + await import('./integrations/vue-devtools').then(({ setup }) => setup(ctx)) + if (options.viteInspect !== false) await import('./integrations/vite-inspect').then(({ setup }) => setup(ctx)) diff --git a/packages/devtools/src/runtime/vue-devtools/overlay.js b/packages/devtools/src/runtime/vue-devtools/overlay.js new file mode 100644 index 0000000000..439a588891 --- /dev/null +++ b/packages/devtools/src/runtime/vue-devtools/overlay.js @@ -0,0 +1,6 @@ +import { devtools } from '@vue/devtools-kit' +import { initAppSeparateWindow } from '@vue/devtools-core' + +devtools.init() + +initAppSeparateWindow() diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f35185747c..b48ff7989f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -113,6 +113,15 @@ importers: '@nuxt/kit': specifier: ^3.10.3 version: 3.10.3(rollup@3.29.4) + '@vue/devtools-applet': + specifier: ^7.0.18 + version: 7.0.18(@unocss/reset@0.58.5)(floating-vue@5.0.2)(fuse.js@7.0.0)(unocss@0.58.5)(vite@5.1.4)(vue@3.4.20) + '@vue/devtools-core': + specifier: ^7.0.18 + version: 7.0.18(vite@5.1.4)(vue@3.4.20) + '@vue/devtools-kit': + specifier: ^7.0.18 + version: 7.0.18(vue@3.4.20) birpc: specifier: ^0.2.17 version: 0.2.17 @@ -420,7 +429,7 @@ importers: version: 10.9.0(vue@3.4.20) '@vueuse/integrations': specifier: ^10.9.0 - version: 10.9.0(focus-trap@7.5.4)(vue@3.4.20) + version: 10.9.0(focus-trap@7.5.4)(fuse.js@7.0.0)(vue@3.4.20) '@vueuse/nuxt': specifier: ^10.9.0 version: 10.9.0(nuxt@3.10.3)(rollup@3.29.4)(vue@3.4.20) @@ -1734,17 +1743,14 @@ packages: resolution: {integrity: sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ==} dependencies: '@floating-ui/utils': 0.1.2 - dev: true /@floating-ui/dom@1.1.1: resolution: {integrity: sha512-TpIO93+DIujg3g7SykEAGZMDtbJRrmnYRCNYSjJlvIbGhBjRSNTLVbNeDQBrzy9qDgUbiWdc7KA0uZHZ2tJmiw==} dependencies: '@floating-ui/core': 1.4.1 - dev: true /@floating-ui/utils@0.1.2: resolution: {integrity: sha512-ou3elfqG/hZsbmF4bxeJhPHIf3G2pm0ujc39hYEZrfVqt7Vk/Zji6CXc3W0pmYM8BW1g40U+akTl9DKZhFhInQ==} - dev: true /@fortawesome/fontawesome-common-types@6.5.1: resolution: {integrity: sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==} @@ -2732,6 +2738,7 @@ packages: dependencies: is-glob: 4.0.3 micromatch: 4.0.5 + napi-wasm: 1.1.0 bundledDependencies: - napi-wasm @@ -4074,6 +4081,102 @@ packages: /@vue/devtools-api@6.6.1: resolution: {integrity: sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==} + /@vue/devtools-applet@7.0.18(@unocss/reset@0.58.5)(floating-vue@5.0.2)(fuse.js@7.0.0)(unocss@0.58.5)(vite@5.1.4)(vue@3.4.20): + resolution: {integrity: sha512-6Vc5d+SIq1OzzHIOEFzbr0afqg/rT4DVrWiMMVTlEGYJnAeb5jVK9+99AxBRwhDDnRRh9+KLSr35YSUaB7IksA==} + peerDependencies: + vue: ^3.0.0 + dependencies: + '@vue/devtools-core': 7.0.18(vite@5.1.4)(vue@3.4.20) + '@vue/devtools-kit': 7.0.18(vue@3.4.20) + '@vue/devtools-shared': 7.0.18 + '@vue/devtools-ui': 7.0.18(@unocss/reset@0.58.5)(floating-vue@5.0.2)(fuse.js@7.0.0)(unocss@0.58.5)(vue@3.4.20) + perfect-debounce: 1.0.0 + splitpanes: 3.1.5 + vue: 3.4.20(typescript@5.3.3) + transitivePeerDependencies: + - '@unocss/reset' + - '@vue/composition-api' + - async-validator + - axios + - change-case + - drauu + - floating-vue + - fuse.js + - idb-keyval + - jwt-decode + - nprogress + - qrcode + - sortablejs + - universal-cookie + - unocss + - vite + dev: false + + /@vue/devtools-core@7.0.18(vite@5.1.4)(vue@3.4.20): + resolution: {integrity: sha512-ayLoB3CRPJBDc9iz1dxWt8AISReZagQZJlYHQdvFBAPiwZ2rhz5flKniHqBfT6e9f0sVZeox7qcA/lsJGXXR/g==} + dependencies: + '@vue/devtools-kit': 7.0.18(vue@3.4.20) + '@vue/devtools-shared': 7.0.18 + mitt: 3.0.1 + nanoid: 3.3.7 + pathe: 1.1.2 + vite-hot-client: 0.2.3(vite@5.1.4) + transitivePeerDependencies: + - vite + - vue + dev: false + + /@vue/devtools-kit@7.0.18(vue@3.4.20): + resolution: {integrity: sha512-sLq9GZgoMG2/yb6HOjXE5PzHplV7+Xy3QvMo9Kz43Hhj0B0S0LYfk0EBdU5yZ84JRlH1LhJCp65y0L+NLbK09A==} + peerDependencies: + vue: ^3.0.0 + dependencies: + '@vue/devtools-shared': 7.0.18 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 1.0.0 + speakingurl: 14.0.1 + vue: 3.4.20(typescript@5.3.3) + dev: false + + /@vue/devtools-shared@7.0.18: + resolution: {integrity: sha512-j06/+32P+Uy39hT7g5MGNEkg2nY2DZJxpSnIxz+POm5FDkqT3o4jPsk3TAsKD15C4RoVasd0xIScU6Xf3Hf5aA==} + dependencies: + rfdc: 1.3.1 + dev: false + + /@vue/devtools-ui@7.0.18(@unocss/reset@0.58.5)(floating-vue@5.0.2)(fuse.js@7.0.0)(unocss@0.58.5)(vue@3.4.20): + resolution: {integrity: sha512-M48xdJahe6QhwjuyNto8OIW+9Hd0c+EQwjI1JypBNSvtD0/jyWZzXR2P0wNw75umwgCdC+Tk5YyUBFd43mtBDw==} + peerDependencies: + '@unocss/reset': '>=0.50.0-0' + floating-vue: '>=2.0.0-0' + unocss: '>=0.50.0-0' + vue: '>=3.0.0-0' + dependencies: + '@unocss/reset': 0.58.5 + '@vueuse/components': 10.9.0(vue@3.4.20) + '@vueuse/core': 10.9.0(vue@3.4.20) + '@vueuse/integrations': 10.9.0(focus-trap@7.5.4)(fuse.js@7.0.0)(vue@3.4.20) + colord: 2.9.3 + floating-vue: 5.0.2(@nuxt/kit@3.10.3)(vue@3.4.20) + focus-trap: 7.5.4 + unocss: 0.58.5(@unocss/webpack@0.58.5)(postcss@8.4.35)(rollup@3.29.4)(vite@5.1.4) + vue: 3.4.20(typescript@5.3.3) + transitivePeerDependencies: + - '@vue/composition-api' + - async-validator + - axios + - change-case + - drauu + - fuse.js + - idb-keyval + - jwt-decode + - nprogress + - qrcode + - sortablejs + - universal-cookie + dev: false + /@vue/language-core@1.8.27(typescript@5.3.3): resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==} peerDependencies: @@ -4123,6 +4226,17 @@ packages: /@vue/shared@3.4.20: resolution: {integrity: sha512-KTEngal0aiUvNJ6I1Chk5Ew5XqChsFsxP4GKAYXWb99zKJWjNU72p2FWEOmZWHxHcqtniOJsgnpd3zizdpfEag==} + /@vueuse/components@10.9.0(vue@3.4.20): + resolution: {integrity: sha512-BHQpA0yIi3y7zKa1gYD0FUzLLkcRTqVhP8smnvsCK6GFpd94Nziq1XVPD7YpFeho0k5BzbBiNZF7V/DpkJ967A==} + dependencies: + '@vueuse/core': 10.9.0(vue@3.4.20) + '@vueuse/shared': 10.9.0(vue@3.4.20) + vue-demi: 0.14.7(vue@3.4.20) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + /@vueuse/core@10.9.0(vue@3.4.20): resolution: {integrity: sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==} dependencies: @@ -4146,7 +4260,7 @@ packages: vue: 3.4.20(typescript@5.3.3) dev: true - /@vueuse/integrations@10.9.0(focus-trap@7.5.4)(vue@3.4.20): + /@vueuse/integrations@10.9.0(focus-trap@7.5.4)(fuse.js@7.0.0)(vue@3.4.20): resolution: {integrity: sha512-acK+A01AYdWSvL4BZmCoJAcyHJ6EqhmkQEXbQLwev1MY7NBnS+hcEMx/BzVoR9zKI+UqEPMD9u6PsyAuiTRT4Q==} peerDependencies: async-validator: '*' @@ -4190,6 +4304,7 @@ packages: '@vueuse/core': 10.9.0(vue@3.4.20) '@vueuse/shared': 10.9.0(vue@3.4.20) focus-trap: 7.5.4 + fuse.js: 7.0.0 vue-demi: 0.14.7(vue@3.4.20) transitivePeerDependencies: - '@vue/composition-api' @@ -6482,7 +6597,6 @@ packages: '@nuxt/kit': 3.10.3(rollup@3.29.4) vue: 3.4.20(typescript@5.3.3) vue-resize: 2.0.0-alpha.1(vue@3.4.20) - dev: true /focus-trap@7.5.4: resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} @@ -6558,7 +6672,6 @@ packages: /fuse.js@7.0.0: resolution: {integrity: sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==} engines: {node: '>=10'} - dev: true /fuzzysearch@1.0.3: resolution: {integrity: sha512-s+kNWQuI3mo9OALw0HJ6YGmMbLqEufCh2nX/zzV5CrICQ/y4AwPxM+6TIiF9ItFCHXFCyM/BfCCmN57NTIJuPg==} @@ -8385,6 +8498,10 @@ packages: resolution: {integrity: sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==} dev: true + /mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + dev: false + /mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} @@ -8463,6 +8580,9 @@ packages: hasBin: true dev: true + /napi-wasm@1.1.0: + resolution: {integrity: sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg==} + /natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} dev: true @@ -9919,6 +10039,10 @@ packages: resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} dev: true + /rfdc@1.3.1: + resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} + dev: false + /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true @@ -10330,6 +10454,11 @@ packages: /spdx-license-ids@3.0.13: resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} + /speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} + dev: false + /split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -11410,7 +11539,6 @@ packages: vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 dependencies: vite: 5.1.4(@types/node@20.11.20) - dev: true /vite-node@1.3.1(@types/node@20.11.20): resolution: {integrity: sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==} @@ -11749,7 +11877,6 @@ packages: vue: ^3.0.0 dependencies: vue: 3.4.20(typescript@5.3.3) - dev: true /vue-router@4.3.0(vue@3.4.20): resolution: {integrity: sha512-dqUcs8tUeG+ssgWhcPbjHvazML16Oga5w34uCUmsk7i0BcnskoLGwjpa15fqMr2Fa5JgVBrdL2MEgqz6XZ/6IQ==}