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 }
})
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] } })
--- /dev/null
+# 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: '' }))
+```
StateTree,
StoreWithState,
StateDescriptor,
+ GenericStore,
PiniaCustomProperties,
GenericStore,
} from './types'
* Plugin to extend every store
*/
export interface PiniaStorePlugin {
- (app: App): Partial<PiniaCustomProperties>
+ (context: { app: App; store: GenericStore }): Partial<PiniaCustomProperties>
}
/**
*
* @internal
*/
- _p: Array<() => Partial<PiniaCustomProperties>>
+ _p: Array<PiniaStorePlugin>
+
+ /**
+ * App linked to this Pinia instance
+ *
+ * @internal
+ */
+ _a: App
}
declare module '@vue/runtime-core' {
const pinia: Pinia = {
install(app: App) {
- localApp = app
+ pinia._a = localApp = app
// pinia._a = app
app.provide(piniaSymbol, pinia)
app.config.globalProperties.$pinia = pinia
// installing pinia's plugin
setActivePinia(pinia)
}
- toBeInstalled.forEach((plugin) => _p.push(plugin.bind(null, localApp!)))
+ toBeInstalled.forEach((plugin) => _p.push(plugin))
},
use(plugin) {
if (!localApp) {
toBeInstalled.push(plugin)
} else {
- _p.push(plugin.bind(null, localApp))
+ _p.push(plugin)
}
},
_p,
+ // it's actually undefined here
+ _a: localApp!,
state,
}
} 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
}