Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3.5 KiB
3.5 KiB
name, description
| name | description |
|---|---|
| plugins | Extend stores with custom properties, methods, and behavior |
Plugins
Plugins extend all stores with custom properties, methods, or behavior.
Basic Plugin
import { createPinia } from 'pinia'
function SecretPiniaPlugin() {
return { secret: 'the cake is a lie' }
}
const pinia = createPinia()
pinia.use(SecretPiniaPlugin)
// In any store
const store = useStore()
store.secret // 'the cake is a lie'
Plugin Context
Plugins receive a context object:
import { PiniaPluginContext } from 'pinia'
export function myPiniaPlugin(context: PiniaPluginContext) {
context.pinia // pinia instance
context.app // Vue app instance
context.store // store being augmented
context.options // store definition options
}
Adding Properties
Return an object to add properties (tracked in devtools):
pinia.use(() => ({ hello: 'world' }))
Or set directly on store:
pinia.use(({ store }) => {
store.hello = 'world'
// For devtools visibility in dev mode
if (process.env.NODE_ENV === 'development') {
store._customProperties.add('hello')
}
})
Adding State
Add to both store and store.$state for SSR/devtools:
import { toRef, ref } from 'vue'
pinia.use(({ store }) => {
if (!store.$state.hasOwnProperty('hasError')) {
const hasError = ref(false)
store.$state.hasError = hasError
}
store.hasError = toRef(store.$state, 'hasError')
})
Adding External Properties
Wrap non-reactive objects with markRaw():
import { markRaw } from 'vue'
import { router } from './router'
pinia.use(({ store }) => {
store.router = markRaw(router)
})
Custom Store Options
Define custom options consumed by plugins:
// Store definition
defineStore('search', {
actions: {
searchContacts() { /* ... */ },
},
debounce: {
searchContacts: 300,
},
})
// Plugin reads custom option
import debounce from 'lodash/debounce'
pinia.use(({ options, store }) => {
if (options.debounce) {
return Object.keys(options.debounce).reduce((acc, action) => {
acc[action] = debounce(store[action], options.debounce[action])
return acc
}, {})
}
})
For Setup Stores, pass options as third argument:
defineStore(
'search',
() => { /* ... */ },
{
debounce: { searchContacts: 300 },
}
)
TypeScript Augmentation
Custom Properties
import 'pinia'
import type { Router } from 'vue-router'
declare module 'pinia' {
export interface PiniaCustomProperties {
router: Router
hello: string
}
}
Custom State
declare module 'pinia' {
export interface PiniaCustomStateProperties<S> {
hasError: boolean
}
}
Custom Options
declare module 'pinia' {
export interface DefineStoreOptionsBase<S, Store> {
debounce?: Partial<Record<keyof StoreActions<Store>, number>>
}
}
Subscribe in Plugins
pinia.use(({ store }) => {
store.$subscribe(() => {
// React to state changes
})
store.$onAction(() => {
// React to actions
})
})
Nuxt Plugin
Create a Nuxt plugin to add Pinia plugins:
// plugins/myPiniaPlugin.ts
import { PiniaPluginContext } from 'pinia'
function MyPiniaPlugin({ store }: PiniaPluginContext) {
store.$subscribe((mutation) => {
console.log(`[🍍 ${mutation.storeId}]: ${mutation.type}`)
})
return { creationTime: new Date() }
}
export default defineNuxtPlugin(({ $pinia }) => {
$pinia.use(MyPiniaPlugin)
})