]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
feat(devtools): display only relevant stores
authorEduardo San Martin Morote <posva13@gmail.com>
Wed, 12 May 2021 22:43:39 +0000 (00:43 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Wed, 12 May 2021 22:43:39 +0000 (00:43 +0200)
src/devtools/plugin.ts
src/store.ts

index 5e14011cfccf8733decf6a628da0c4e35addf8e5..2716dc89bb03816ee0feb43088fab2c7364f31f2 100644 (file)
@@ -1,5 +1,5 @@
 import { setupDevtoolsPlugin, TimelineEvent } from '@vue/devtools-api'
-import { App } from 'vue'
+import { App, ComponentPublicInstance } from 'vue'
 import { PiniaPluginContext, setActivePinia } from '../rootStore'
 import {
   Store,
@@ -19,7 +19,7 @@ import {
 /**
  * Registered stores used for devtools.
  */
-const registeredStores = /*#__PURE__*/ new Set<Store>()
+const registeredStores = /*#__PURE__*/ new Map<string, Store>()
 
 let isAlreadyInstalled: boolean | undefined
 // timeline can be paused when directly changing the state
@@ -30,8 +30,11 @@ const MUTATIONS_LAYER_ID = 'pinia:mutations'
 const INSPECTOR_ID = 'pinia'
 
 export function addDevtools(app: App, store: Store) {
-  registeredStores.add(store)
-  componentStateTypes.push('🍍 ' + store.$id)
+  if (!registeredStores.has(store.$id)) {
+    registeredStores.set(store.$id, store)
+    componentStateTypes.push('🍍 ' + store.$id)
+  }
+
   setupDevtoolsPlugin(
     {
       id: 'dev.esm.pinia',
@@ -43,35 +46,6 @@ export function addDevtools(app: App, store: Store) {
       app,
     },
     (api) => {
-      // watch(router.currentRoute, () => {
-      //   // @ts-ignore
-      //   api.notifyComponentUpdate()
-      // })
-
-      // TODO: only load stores used by the component?
-      api.on.inspectComponent((payload, ctx) => {
-        if (payload.instanceData) {
-          payload.instanceData.state.push({
-            type: '🍍 ' + store.$id,
-            key: 'state',
-            editable: false,
-            value: store.$state,
-          })
-
-          if (store._getters?.length) {
-            payload.instanceData.state.push({
-              type: '🍍 ' + store.$id,
-              key: 'getters',
-              editable: false,
-              value: store._getters.reduce((getters, key) => {
-                getters[key] = store[key]
-                return getters
-              }, {} as GettersTree<StateTree>),
-            })
-          }
-        }
-      })
-
       if (!isAlreadyInstalled) {
         api.addTimelineLayer({
           id: MUTATIONS_LAYER_ID,
@@ -86,9 +60,44 @@ export function addDevtools(app: App, store: Store) {
           treeFilterPlaceholder: 'Search stores',
         })
 
+        api.on.inspectComponent((payload, ctx) => {
+          if (
+            (
+              payload.componentInstance?.proxy as
+                | ComponentPublicInstance
+                | undefined
+            )?._pStores
+          ) {
+            const piniaStores = (
+              payload.componentInstance.proxy as ComponentPublicInstance
+            )._pStores!
+
+            Object.values(piniaStores).forEach((store) => {
+              payload.instanceData.state.push({
+                type: '🍍 ' + store.$id,
+                key: 'state',
+                editable: false,
+                value: store.$state,
+              })
+
+              if (store._getters?.length) {
+                payload.instanceData.state.push({
+                  type: '🍍 ' + store.$id,
+                  key: 'getters',
+                  editable: false,
+                  value: store._getters.reduce((getters, key) => {
+                    getters[key] = store[key]
+                    return getters
+                  }, {} as GettersTree<StateTree>),
+                })
+              }
+            })
+          }
+        })
+
         api.on.getInspectorTree((payload) => {
           if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
-            const stores = Array.from(registeredStores)
+            const stores = Array.from(registeredStores.values())
 
             payload.rootNodes = (
               payload.filter
@@ -104,7 +113,7 @@ export function addDevtools(app: App, store: Store) {
 
         api.on.getInspectorState((payload) => {
           if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
-            const store = Array.from(registeredStores).find(
+            const store = Array.from(registeredStores.values()).find(
               (store) => store.$id === payload.nodeId
             )
 
@@ -125,7 +134,7 @@ export function addDevtools(app: App, store: Store) {
 
         api.on.editInspectorState((payload) => {
           if (payload.app === app && payload.inspectorId === INSPECTOR_ID) {
-            const store = Array.from(registeredStores).find(
+            const store = Array.from(registeredStores.values()).find(
               (store) => store.$id === payload.nodeId
             )
 
index f927028fbec8c13d0c36f9130dfabf1a6d4ab6a3..87eae11f9691ae30767a9934f3c4b3c01e7e589b 100644 (file)
@@ -380,11 +380,11 @@ export function defineStore<
   const { id, state, getters, actions } = options
 
   function useStore(pinia?: Pinia | null): Store<Id, S, G, A> {
-    const hasInstance = getCurrentInstance()
+    const currentInstance = getCurrentInstance()
     // only run provide when pinia hasn't been manually passed
-    const shouldProvide = hasInstance && !pinia
+    const shouldProvide = currentInstance && !pinia
     // avoid injecting if `useStore` when not possible
-    pinia = pinia || (hasInstance && inject(piniaSymbol))
+    pinia = pinia || (currentInstance && inject(piniaSymbol))
     if (pinia) setActivePinia(pinia)
     // TODO: worth warning on server if no piniaKey as it can leak data
     pinia = getActivePinia()
@@ -398,13 +398,16 @@ export function defineStore<
           InjectionKey<Store<Id, S, G, A>>
         ]
       | undefined
+
+    let store: Store<Id, S, G, A>
+
     if (!storeAndDescriptor) {
       storeAndDescriptor = initStore(id, state, pinia.state.value[id])
 
       // annoying to type
       stores.set(id, storeAndDescriptor as any)
 
-      const store = buildStoreToUse<
+      store = buildStoreToUse<
         Id,
         S,
         G,
@@ -424,28 +427,41 @@ export function defineStore<
       if (shouldProvide) {
         provide(storeAndDescriptor[2], store)
       }
+    } else {
+      store =
+        // null avoids the warning for not found injection key
+        (currentInstance && inject(storeAndDescriptor[2], null)) ||
+        buildStoreToUse<
+          Id,
+          S,
+          G,
+          // @ts-expect-error: A without extends
+          A
+        >(
+          storeAndDescriptor[0],
+          storeAndDescriptor[1],
+          id,
+          getters as GettersTree<S> | undefined,
+          actions as A | undefined,
+          options
+        )
+    }
 
-      return store
+    // save stores in instances to access them devtools
+    if (
+      __DEV__ &&
+      __BROWSER__ &&
+      IS_CLIENT &&
+      currentInstance &&
+      currentInstance.proxy
+    ) {
+      const vm = currentInstance.proxy
+      const cache = '_pStores' in vm ? vm._pStores! : (vm._pStores = {})
+      // @ts-expect-error: still can't cast Store with generics to Store
+      cache[store.$id] = store
     }
 
-    return (
-      // null avoids the warning for not found injection key
-      (hasInstance && inject(storeAndDescriptor[2], null)) ||
-      buildStoreToUse<
-        Id,
-        S,
-        G,
-        // @ts-expect-error: A without extends
-        A
-      >(
-        storeAndDescriptor[0],
-        storeAndDescriptor[1],
-        id,
-        getters as GettersTree<S> | undefined,
-        actions as A | undefined,
-        options
-      )
-    )
+    return store
   }
 
   // needed by map helpers