Daniel Kelly
Lead Instructor @ Vue School
Full Stack developer (10 years)
Husband and Father
762 Lessons | 63 Hours | 40 Courses
Dissecting the Pinia Source Code
Why?
Why?
- You can squeeze the most effectiveness out of it, when you understand how it works
- For inspiration in building your own open source Vue libraries
- To see an example of the flexibility and power of the Composition API in the wild
- To see how to utilize TypeScript in a Vue library
Examining the File Structure
1
Examining the File Structure
Eduardo uses
VS Code
Examining the File Structure
.vscode/settings.json
Examining the File Structure
Pinia is a monorepo
Examining the File Structure
Distributed
via NPM
Examining the File Structure
Examining the File Structure
Uses Prettier
for Formatting
Examining the File Structure
MIT
License
Examining the File Structure
versions getting security patches
Examining the File Structure
Examining the File Structure
tested with Jest
Examining the File Structure
Lerna mono-repo tooling
Examining the File Structure
https://github.com/lerna/lerna
Examining the File Structure
docs deployed
to Netlify
Examining the File Structure
manages deps with pnpm
Examining the File Structure
- faster
- disk space efficient
- more secure
Examining the File Structure
automated dependency updates
Examining the File Structure
Examining the File Structure
Uses TypeScript
Examining the File Structure
The packages
Examining the File Structure
docs built with Vitepress
Examining the File Structure
docs built with Vitepress
Examining the File Structure
includes a Nuxt module
Examining the File Structure
playground important iteration
Examining the File Structure
Examining the File Structure
automated package size report
Examining the File Structure
helpers for unit testing
Examining the File Structure
createTestingPinia
the main package
Examining the File Structure
Examining the File Structure
Built in devtools support
1076 lines
How does createPinia work?
2
How does createPinia work?
Used to install Pinia with Vue
How does createPinia work?
// main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
app.use(createPinia())
Used to install Pinia with Vue
How does createPinia work?
// createPinia.ts
import { Pinia, PiniaPlugin, setActivePinia, piniaSymbol } from './rootStore'
import { ref, App, markRaw, effectScope, isVue2, Ref } from 'vue-demi'
import { registerPiniaDevtools, devtoolsPlugin } from './devtools'
import { IS_CLIENT } from './env'
import { StateTree, StoreGeneric } from './types'
/**
* Creates a Pinia instance to be used by the application
*/
export function createPinia(): Pinia {
const scope = effectScope(true)
// NOTE: here we could check the window object for a state and directly set it
// if there is anything like it with Vue 3 SSR
const state = scope.run<Ref<Record<string, StateTree>>>(() =>
ref<Record<string, StateTree>>({})
)!
let _p: Pinia['_p'] = []
// plugins added before calling app.use(pinia)
let toBeInstalled: PiniaPlugin[] = []
const pinia: Pinia = markRaw({
install(app: App) {
// this allows calling useStore() outside of a component setup after
// installing pinia's plugin
setActivePinia(pinia)
if (!isVue2) {
pinia._a = app
app.provide(piniaSymbol, pinia)
app.config.globalProperties.$pinia = pinia
/* istanbul ignore else */
if (__DEV__ && IS_CLIENT) {
registerPiniaDevtools(app, pinia)
}
toBeInstalled.forEach((plugin) => _p.push(plugin))
toBeInstalled = []
}
},
use(plugin) {
if (!this._a && !isVue2) {
toBeInstalled.push(plugin)
} else {
_p.push(plugin)
}
return this
},
_p,
// it's actually undefined here
// @ts-expect-error
_a: null,
_e: scope,
_s: new Map<string, StoreGeneric>(),
state,
})
// pinia devtools rely on dev only features so they cannot be forced unless
// the dev build of Vue is used
// We also don't need devtools in test mode
if (__DEV__ && IS_CLIENT && !__TEST__) {
pinia.use(devtoolsPlugin)
}
return pinia
}
How does createPinia work?
// rootStore.ts
/**
* Every application must own its own pinia to be able to create stores
*/
export interface Pinia {
install: (app: App) => void
/**
* root state
*/
state: Ref<Record<string, StateTree>>
/**
* Adds a store plugin to extend every store
*
* @param plugin - store plugin to add
*/
use(plugin: PiniaPlugin): Pinia
/**
* Installed store plugins
*
* @internal
*/
_p: PiniaPlugin[]
/**
* App linked to this Pinia instance
*
* @internal
*/
_a: App
/**
* Effect scope the pinia is attached to
*
* @internal
*/
_e: EffectScope
/**
* Registry of stores used by this pinia.
*
* @internal
*/
_s: Map<string, StoreGeneric>
/**
* Added by `createTestingPinia()` to bypass `useStore(pinia)`.
*
* @internal
*/
_testing?: boolean
}
How does createPinia work?
// rootStore.ts
/**
* Every application must own its own pinia to be able to create stores
*/
export interface Pinia {
install: (app: App) => void
/**
* root state
*/
state: Ref<Record<string, StateTree>>
/**
* Adds a store plugin to extend every store
*
* @param plugin - store plugin to add
*/
use(plugin: PiniaPlugin): Pinia
/**
* Installed store plugins
*
* @internal
*/
_p: PiniaPlugin[]
/**
* App linked to this Pinia instance
*
* @internal
*/
_a: App
/**
* Effect scope the pinia is attached to
*
* @internal
*/
_e: EffectScope
/**
* Registry of stores used by this pinia.
*
* @internal
*/
_s: Map<string, StoreGeneric>
/**
* Added by `createTestingPinia()` to bypass `useStore(pinia)`.
*
* @internal
*/
_testing?: boolean
}
How does createPinia work?
// rootStore.ts
/**
* Every application must own its own pinia to be able to create stores
*/
export interface Pinia {
install: (app: App) => void
/**
* root state
*/
state: Ref<Record<string, StateTree>>
/**
* Adds a store plugin to extend every store
*
* @param plugin - store plugin to add
*/
use(plugin: PiniaPlugin): Pinia
/**
* Installed store plugins
*
* @internal
*/
_p: PiniaPlugin[]
/**
* App linked to this Pinia instance
*
* @internal
*/
_a: App
/**
* Effect scope the pinia is attached to
*
* @internal
*/
_e: EffectScope
/**
* Registry of stores used by this pinia.
*
* @internal
*/
_s: Map<string, StoreGeneric>
/**
* Added by `createTestingPinia()` to bypass `useStore(pinia)`.
*
* @internal
*/
_testing?: boolean
}
TS Record Utility Type
How does createPinia work?
// rootStore.ts
/**
* Every application must own its own pinia to be able to create stores
*/
export interface Pinia {
install: (app: App) => void
/**
* root state
*/
state: Ref<Record<string, StateTree>>
/**
* Adds a store plugin to extend every store
*
* @param plugin - store plugin to add
*/
use(plugin: PiniaPlugin): Pinia
/**
* Installed store plugins
*
* @internal
*/
_p: PiniaPlugin[]
/**
* App linked to this Pinia instance
*
* @internal
*/
_a: App
/**
* Effect scope the pinia is attached to
*
* @internal
*/
_e: EffectScope
/**
* Registry of stores used by this pinia.
*
* @internal
*/
_s: Map<string, StoreGeneric>
/**
* Added by `createTestingPinia()` to bypass `useStore(pinia)`.
*
* @internal
*/
_testing?: boolean
}
// types.ts
export type StateTree = Record<string | number | symbol, any>
TS Record Utility Type
How does createPinia work?
// rootStore.ts
/**
* Every application must own its own pinia to be able to create stores
*/
export interface Pinia {
install: (app: App) => void
/**
* root state
*/
state: Ref<Record<string, StateTree>>
/**
* Adds a store plugin to extend every store
*
* @param plugin - store plugin to add
*/
use(plugin: PiniaPlugin): Pinia
/**
* Installed store plugins
*
* @internal
*/
_p: PiniaPlugin[]
/**
* App linked to this Pinia instance
*
* @internal
*/
_a: App
/**
* Effect scope the pinia is attached to
*
* @internal
*/
_e: EffectScope
/**
* Registry of stores used by this pinia.
*
* @internal
*/
_s: Map<string, StoreGeneric>
/**
* Added by `createTestingPinia()` to bypass `useStore(pinia)`.
*
* @internal
*/
_testing?: boolean
}
export const piniaSymbol = (
__DEV__ ? Symbol('pinia') : /* istanbul ignore next */ Symbol()
) as InjectionKey<Pinia>
/**
* Context argument passed to Pinia plugins.
*/
export interface PiniaPluginContext<
Id extends string = string,
S extends StateTree = StateTree,
G /* extends _GettersTree<S> */ = _GettersTree<S>,
A /* extends _ActionsTree */ = _ActionsTree
> {
/**
* pinia instance.
*/
pinia: Pinia
/**
* Current app created with `Vue.createApp()`.
*/
app: App
/**
* Current store being extended.
*/
store: Store<Id, S, G, A>
/**
* Initial options defining the store when calling `defineStore()`.
*/
options: DefineStoreOptionsInPlugin<Id, S, G, A>
}
/**
* Plugin to extend every store.
*/
export interface PiniaPlugin {
/**
* Plugin to extend every store. Returns an object to extend the store or
* nothing.
*
* @param context - Context
*/
(context: PiniaPluginContext): Partial<
PiniaCustomProperties & PiniaCustomStateProperties
> | void
}
https://tsdoc.org
How does createPinia work?
// createPinia.ts
import { Pinia, PiniaPlugin, setActivePinia, piniaSymbol } from './rootStore'
import { ref, App, markRaw, effectScope, isVue2, Ref } from 'vue-demi'
import { registerPiniaDevtools, devtoolsPlugin } from './devtools'
import { IS_CLIENT } from './env'
import { StateTree, StoreGeneric } from './types'
/**
* Creates a Pinia instance to be used by the application
*/
export function createPinia(): Pinia {
const scope = effectScope(true)
// NOTE: here we could check the window object for a state and directly set it
// if there is anything like it with Vue 3 SSR
const state = scope.run<Ref<Record<string, StateTree>>>(() =>
ref<Record<string, StateTree>>({})
)!
let _p: Pinia['_p'] = []
// plugins added before calling app.use(pinia)
let toBeInstalled: PiniaPlugin[] = []
const pinia: Pinia = markRaw({
install(app: App) {
// this allows calling useStore() outside of a component setup after
// installing pinia's plugin
setActivePinia(pinia)
if (!isVue2) {
pinia._a = app
app.provide(piniaSymbol, pinia)
app.config.globalProperties.$pinia = pinia
/* istanbul ignore else */
if (__DEV__ && IS_CLIENT) {
registerPiniaDevtools(app, pinia)
}
toBeInstalled.forEach((plugin) => _p.push(plugin))
toBeInstalled = []
}
},
use(plugin) {
if (!this._a && !isVue2) {
toBeInstalled.push(plugin)
} else {
_p.push(plugin)
}
return this
},
_p,
// it's actually undefined here
// @ts-expect-error
_a: null,
_e: scope,
_s: new Map<string, StoreGeneric>(),
state,
})
// pinia devtools rely on dev only features so they cannot be forced unless
// the dev build of Vue is used
// We also don't need devtools in test mode
if (__DEV__ && IS_CLIENT && !__TEST__) {
pinia.use(devtoolsPlugin)
}
return pinia
}
How does createPinia work?
// createPinia.ts
import { Pinia, PiniaPlugin, setActivePinia, piniaSymbol } from './rootStore'
import { ref, App, markRaw, effectScope, isVue2, Ref } from 'vue-demi'
import { registerPiniaDevtools, devtoolsPlugin } from './devtools'
import { IS_CLIENT } from './env'
import { StateTree, StoreGeneric } from './types'
/**
* Creates a Pinia instance to be used by the application
*/
export function createPinia(): Pinia {
const scope = effectScope(true)
// NOTE: here we could check the window object for a state and directly set it
// if there is anything like it with Vue 3 SSR
const state = scope.run<Ref<Record<string, StateTree>>>(() =>
ref<Record<string, StateTree>>({})
)!
let _p: Pinia['_p'] = []
// plugins added before calling app.use(pinia)
let toBeInstalled: PiniaPlugin[] = []
const pinia: Pinia = markRaw({
install(app: App) {
// this allows calling useStore() outside of a component setup after
// installing pinia's plugin
setActivePinia(pinia)
if (!isVue2) {
pinia._a = app
app.provide(piniaSymbol, pinia)
app.config.globalProperties.$pinia = pinia
/* istanbul ignore else */
if (__DEV__ && IS_CLIENT) {
registerPiniaDevtools(app, pinia)
}
toBeInstalled.forEach((plugin) => _p.push(plugin))
toBeInstalled = []
}
},
use(plugin) {
if (!this._a && !isVue2) {
toBeInstalled.push(plugin)
} else {
_p.push(plugin)
}
return this
},
_p,
// it's actually undefined here
// @ts-expect-error
_a: null,
_e: scope,
_s: new Map<string, StoreGeneric>(),
state,
})
// pinia devtools rely on dev only features so they cannot be forced unless
// the dev build of Vue is used
// We also don't need devtools in test mode
if (__DEV__ && IS_CLIENT && !__TEST__) {
pinia.use(devtoolsPlugin)
}
return pinia
}
Handle Pinia Plugins
How does createPinia work?
// createPinia.ts
import { Pinia, PiniaPlugin, setActivePinia, piniaSymbol } from './rootStore'
import { ref, App, markRaw, effectScope, isVue2, Ref } from 'vue-demi'
import { registerPiniaDevtools, devtoolsPlugin } from './devtools'
import { IS_CLIENT } from './env'
import { StateTree, StoreGeneric } from './types'
/**
* Creates a Pinia instance to be used by the application
*/
export function createPinia(): Pinia {
const scope = effectScope(true)
// NOTE: here we could check the window object for a state and directly set it
// if there is anything like it with Vue 3 SSR
const state = scope.run<Ref<Record<string, StateTree>>>(() =>
ref<Record<string, StateTree>>({})
)!
let _p: Pinia['_p'] = []
// plugins added before calling app.use(pinia)
let toBeInstalled: PiniaPlugin[] = []
const pinia: Pinia = markRaw({
install(app: App) {
// this allows calling useStore() outside of a component setup after
// installing pinia's plugin
setActivePinia(pinia)
if (!isVue2) {
pinia._a = app
app.provide(piniaSymbol, pinia)
app.config.globalProperties.$pinia = pinia
/* istanbul ignore else */
if (__DEV__ && IS_CLIENT) {
registerPiniaDevtools(app, pinia)
}
toBeInstalled.forEach((plugin) => _p.push(plugin))
toBeInstalled = []
}
},
use(plugin) {
if (!this._a && !isVue2) {
toBeInstalled.push(plugin)
} else {
_p.push(plugin)
}
return this
},
_p,
// it's actually undefined here
// @ts-expect-error
_a: null,
_e: scope,
_s: new Map<string, StoreGeneric>(),
state,
})
// pinia devtools rely on dev only features so they cannot be forced unless
// the dev build of Vue is used
// We also don't need devtools in test mode
if (__DEV__ && IS_CLIENT && !__TEST__) {
pinia.use(devtoolsPlugin)
}
return pinia
}
// rootStore.ts
export let activePinia: Pinia | undefined
export const setActivePinia = (pinia: Pinia | undefined) =>
(activePinia = pinia)
How does createPinia work?
// createPinia.ts
import { Pinia, PiniaPlugin, setActivePinia, piniaSymbol } from './rootStore'
import { ref, App, markRaw, effectScope, isVue2, Ref } from 'vue-demi'
import { registerPiniaDevtools, devtoolsPlugin } from './devtools'
import { IS_CLIENT } from './env'
import { StateTree, StoreGeneric } from './types'
/**
* Creates a Pinia instance to be used by the application
*/
export function createPinia(): Pinia {
const scope = effectScope(true)
// NOTE: here we could check the window object for a state and directly set it
// if there is anything like it with Vue 3 SSR
const state = scope.run<Ref<Record<string, StateTree>>>(() =>
ref<Record<string, StateTree>>({})
)!
let _p: Pinia['_p'] = []
// plugins added before calling app.use(pinia)
let toBeInstalled: PiniaPlugin[] = []
const pinia: Pinia = markRaw({
install(app: App) {
// this allows calling useStore() outside of a component setup after
// installing pinia's plugin
setActivePinia(pinia)
if (!isVue2) {
pinia._a = app
app.provide(piniaSymbol, pinia)
app.config.globalProperties.$pinia = pinia
/* istanbul ignore else */
if (__DEV__ && IS_CLIENT) {
registerPiniaDevtools(app, pinia)
}
toBeInstalled.forEach((plugin) => _p.push(plugin))
toBeInstalled = []
}
},
use(plugin) {
if (!this._a && !isVue2) {
toBeInstalled.push(plugin)
} else {
_p.push(plugin)
}
return this
},
_p,
// it's actually undefined here
// @ts-expect-error
_a: null,
_e: scope,
_s: new Map<string, StoreGeneric>(),
state,
})
// pinia devtools rely on dev only features so they cannot be forced unless
// the dev build of Vue is used
// We also don't need devtools in test mode
if (__DEV__ && IS_CLIENT && !__TEST__) {
pinia.use(devtoolsPlugin)
}
return pinia
}
How does createPinia work?
// createPinia.ts
import { Pinia, PiniaPlugin, setActivePinia, piniaSymbol } from './rootStore'
import { ref, App, markRaw, effectScope, isVue2, Ref } from 'vue-demi'
import { registerPiniaDevtools, devtoolsPlugin } from './devtools'
import { IS_CLIENT } from './env'
import { StateTree, StoreGeneric } from './types'
/**
* Creates a Pinia instance to be used by the application
*/
export function createPinia(): Pinia {
const scope = effectScope(true)
// NOTE: here we could check the window object for a state and directly set it
// if there is anything like it with Vue 3 SSR
const state = scope.run<Ref<Record<string, StateTree>>>(() =>
ref<Record<string, StateTree>>({})
)!
let _p: Pinia['_p'] = []
// plugins added before calling app.use(pinia)
let toBeInstalled: PiniaPlugin[] = []
const pinia: Pinia = markRaw({
install(app: App) {
// this allows calling useStore() outside of a component setup after
// installing pinia's plugin
setActivePinia(pinia)
if (!isVue2) {
pinia._a = app
app.provide(piniaSymbol, pinia)
app.config.globalProperties.$pinia = pinia
/* istanbul ignore else */
if (__DEV__ && IS_CLIENT) {
registerPiniaDevtools(app, pinia)
}
toBeInstalled.forEach((plugin) => _p.push(plugin))
toBeInstalled = []
}
},
use(plugin) {
if (!this._a && !isVue2) {
toBeInstalled.push(plugin)
} else {
_p.push(plugin)
}
return this
},
_p,
// it's actually undefined here
// @ts-expect-error
_a: null,
_e: scope,
_s: new Map<string, StoreGeneric>(),
state,
})
// pinia devtools rely on dev only features so they cannot be forced unless
// the dev build of Vue is used
// We also don't need devtools in test mode
if (__DEV__ && IS_CLIENT && !__TEST__) {
pinia.use(devtoolsPlugin)
}
return pinia
}
How does createPinia work?
// createPinia.ts
import { Pinia, PiniaPlugin, setActivePinia, piniaSymbol } from './rootStore'
import { ref, App, markRaw, effectScope, isVue2, Ref } from 'vue-demi'
import { registerPiniaDevtools, devtoolsPlugin } from './devtools'
import { IS_CLIENT } from './env'
import { StateTree, StoreGeneric } from './types'
/**
* Creates a Pinia instance to be used by the application
*/
export function createPinia(): Pinia {
const scope = effectScope(true)
// NOTE: here we could check the window object for a state and directly set it
// if there is anything like it with Vue 3 SSR
const state = scope.run<Ref<Record<string, StateTree>>>(() =>
ref<Record<string, StateTree>>({})
)!
let _p: Pinia['_p'] = []
// plugins added before calling app.use(pinia)
let toBeInstalled: PiniaPlugin[] = []
const pinia: Pinia = markRaw({
install(app: App) {
// this allows calling useStore() outside of a component setup after
// installing pinia's plugin
setActivePinia(pinia)
if (!isVue2) {
pinia._a = app
app.provide(piniaSymbol, pinia)
app.config.globalProperties.$pinia = pinia
/* istanbul ignore else */
if (__DEV__ && IS_CLIENT) {
registerPiniaDevtools(app, pinia)
}
toBeInstalled.forEach((plugin) => _p.push(plugin))
toBeInstalled = []
}
},
use(plugin) {
if (!this._a && !isVue2) {
toBeInstalled.push(plugin)
} else {
_p.push(plugin)
}
return this
},
_p,
// it's actually undefined here
// @ts-expect-error
_a: null,
_e: scope,
_s: new Map<string, StoreGeneric>(),
state,
})
// pinia devtools rely on dev only features so they cannot be forced unless
// the dev build of Vue is used
// We also don't need devtools in test mode
if (__DEV__ && IS_CLIENT && !__TEST__) {
pinia.use(devtoolsPlugin)
}
return pinia
}
How does createPinia work?
How does createPinia work?
Don't be afraid of source code
Learn from it
Grab a FREE limited edition Vue School t-shirt
Visit our Booth 🤗
Thanks!
Dissecting the Pinia Source Code v1
By Daniel Kelly
Dissecting the Pinia Source Code v1
- 1,357