]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
feat: add plugin api wip
authorEduardo San Martin Morote <posva13@gmail.com>
Wed, 24 Mar 2021 16:00:08 +0000 (17:00 +0100)
committerEduardo San Martin Morote <posva13@gmail.com>
Thu, 15 Apr 2021 14:42:37 +0000 (16:42 +0200)
__tests__/storePlugins.spec.ts
docs/core-concepts/plugins.md [new file with mode: 0644]
src/rootStore.ts
src/store.ts

index 0f7a1b45921295db2716bf99c79f8723c8c314ac..13e5d248ae31df2464ae8e270858f9ef70d942cd 100644 (file)
@@ -33,7 +33,7 @@ describe('store plugins', () => {
     mount({ template: 'none' }, { global: { plugins: [pinia] } })
 
     // must call use after installing the plugin
-    pinia.use((app) => {
+    pinia.use(({ app }) => {
       return { n: 20, uid: app._uid }
     })
 
@@ -51,7 +51,7 @@ describe('store plugins', () => {
     const pinia = createPinia()
 
     pinia.use(() => ({ n: 1 }))
-    pinia.use((app) => ({ uid: app._uid }))
+    pinia.use(({ app }) => ({ uid: app._uid }))
 
     mount({ template: 'none' }, { global: { plugins: [pinia] } })
 
diff --git a/docs/core-concepts/plugins.md b/docs/core-concepts/plugins.md
new file mode 100644 (file)
index 0000000..fb1a413
--- /dev/null
@@ -0,0 +1,17 @@
+# Plugins
+
+Pinia stores can be fully extended thanks to a low level API. Here is a list of things you can do:
+
+- Add new properties to stores
+- Add new methods to stores
+- Wrap existing methods
+- Change or even cancel actions
+- Implement side effects like local storage
+- Apply **only** to specific stores
+
+Plugins are added to pinia with `pinia.use()`:
+
+```js
+// add a property named `secret` to every store that is created after this plugin is installed
+pinia.use(() => ({ secret: '' }))
+```
index 9cfad32d2f892180b1b91a615c82c45086bfda12..d7e5f6295598ae481383e07b4dd78ba2841bf1cf 100644 (file)
@@ -4,6 +4,7 @@ import {
   StateTree,
   StoreWithState,
   StateDescriptor,
+  GenericStore,
   PiniaCustomProperties,
   GenericStore,
 } from './types'
@@ -60,7 +61,7 @@ export const getClientApp = () => clientApp
  * Plugin to extend every store
  */
 export interface PiniaStorePlugin {
-  (app: App): Partial<PiniaCustomProperties>
+  (context: { app: App; store: GenericStore }): Partial<PiniaCustomProperties>
 }
 
 /**
@@ -86,7 +87,14 @@ export interface Pinia {
    *
    * @internal
    */
-  _p: Array<() => Partial<PiniaCustomProperties>>
+  _p: Array<PiniaStorePlugin>
+
+  /**
+   * App linked to this Pinia instance
+   *
+   * @internal
+   */
+  _a: App
 }
 
 declare module '@vue/runtime-core' {
@@ -125,7 +133,7 @@ export function createPinia(): Pinia {
 
   const pinia: Pinia = {
     install(app: App) {
-      localApp = app
+      pinia._a = localApp = app
       // pinia._a = app
       app.provide(piniaSymbol, pinia)
       app.config.globalProperties.$pinia = pinia
@@ -137,7 +145,7 @@ export function createPinia(): Pinia {
         // installing pinia's plugin
         setActivePinia(pinia)
       }
-      toBeInstalled.forEach((plugin) => _p.push(plugin.bind(null, localApp!)))
+      toBeInstalled.forEach((plugin) => _p.push(plugin))
     },
 
     use(plugin) {
@@ -150,11 +158,13 @@ export function createPinia(): Pinia {
       if (!localApp) {
         toBeInstalled.push(plugin)
       } else {
-        _p.push(plugin.bind(null, localApp))
+        _p.push(plugin)
       }
     },
 
     _p,
+    // it's actually undefined here
+    _a: localApp!,
 
     state,
   }
index 6daaab6d4946e2274416a7c148577ce7db73954c..329f4672df24f82bf92583ebd642b16f787403a0 100644 (file)
@@ -230,28 +230,24 @@ function buildStoreToUse<
     } as StoreWithActions<A>[typeof actionName]
   }
 
-  const extensions = pinia._p.reduce(
-    (extended, extender) => assign({}, extended, extender()),
-    {} as PiniaCustomProperties
-  )
-
-  const store: Store<Id, S, G, A> = reactive(
-    assign(
-      {},
-      extensions,
-      partialStore,
-      // using this means no new properties can be added as state
-      computedFromState(pinia.state, $id),
-      computedGetters,
-      wrappedActions
-    )
-  ) as Store<Id, S, G, A>
+  const store: Store<Id, S, G, A> = reactive({
+    ...partialStore,
+    // using this means no new properties can be added as state
+    ...computedFromState(pinia.state, $id),
+    ...computedGetters,
+    ...wrappedActions,
+  }) as Store<Id, S, G, A>
 
   // use this instead of a computed with setter to be able to create it anywhere
   // without linking the computed lifespan to wherever the store is first
   // created.
   Object.defineProperty(store, '$state', descriptor)
 
+  // apply all plugins
+  pinia._p.forEach((extender) => {
+    Object.assign(store, extender({ store, app: pinia._a }))
+  })
+
   return store
 }