Plugin bukan hanya untuk persistence. Episode ini membahas $onAction untuk tracking pemanggilan action, $subscribe yang menulis state ke JSON, dan plugin global untuk analytics serta error handler. Kalian juga belajar memperluas store dengan helper global dan integrasi library eksternal.

Episode 8 memperkenalkan dasar plugin. Sekarang kita naik level: plugin untuk analytics, error handling, dan logging — hal-hal yang tidak ingin kalian tulis ulang di setiap store. Plugin lanjutan inilah yang membuat observability aplikasi berjalan tanpa mengotori kode store.
Episode 18 membahas $onAction untuk tracking, $subscribe yang menulis state ke JSON, plugin global untuk analytics dan error handler, serta cara memperluas store dengan helper global.
$onAction mendengarkan semua pemanggilan action di sebuah store — termasuk argumen, hasil, dan error:
export function actionTrackerPlugin({ store }) {
store.$onAction(({ name, args, after, onError }) => {
console.time(`action:${name}`)
after((result) => {
console.timeEnd(`action:${name}`)
console.log('Hasil', name, result)
})
onError((error) => {
console.error('Action gagal', name, error)
})
})
}store.$onAction(({ name, args, after, onError }) => ...) memberi hook lengkap siklus action. after dipanggil saat action sukses, onError saat gagal. Inilah dasar pembuatan logger atau metrik performa action.
$subscribe bisa dimanfaatkan untuk menyimpan snapshot state secara berkala, misalnya untuk debugging session:
let terakhir = 0
store.$subscribe((_mutation, state) => {
const sekarang = Date.now()
if (sekarang - terakhir > 5000) {
terakhir = sekarang
localStorage.setItem(
`snapshot-${store.$id}`,
JSON.stringify(state),
)
}
})JSON.stringify(state) di dalam subscriber membuat snapshot state yang bisa dianalisis untuk reproduksi bug. Batas waktu mencegah snapshot membanjiri storage.
Satu plugin bisa menangani analytics untuk seluruh store:
export function analyticsPlugin({ store }) {
store.$onAction(({ name, after }) => {
after(() => {
trackEvent('store_action', { store: store.$id, action: name })
})
})
}trackEvent('store_action', ...) mengirimkan nama store dan action setiap kali aksi berhasil. Tim marketing atau monitoring cukup membaca event ini tanpa perubahan di komponen mana pun.
Error yang terjadi di action bisa dipusatkan di satu tempat:
export function errorHandlerPlugin({ store }) {
store.$onAction(({ onError }) => {
onError((error) => {
reportError(error, { storeId: store.$id })
})
})
}
function reportError(error: unknown, info: object) {
console.error('Error dari store', info, error)
}store.$onAction(({ onError }) => ...) menangkap error dari semua action store. Dengan plugin ini, error handling cukup ditulis sekali dan terpusat — tidak tersebar di setiap action.
Plugin juga bisa menempelkan helper yang dipakai semua store:
pinia.use(({ store }) => {
store.$error = (message: string) => {
console.error(`[${store.$id}]`, message)
}
})store.$error = (message) => ... menambah method helper ke setiap store. Untuk membuat TypeScript mengenalinya, gunakan PiniaCustomProperties seperti yang dibahas di episode 16.
Warning
Pilih antara plugin atau action manual dengan bijak. Gunakan plugin untuk hal lintas store yang seragam; gunakan action untuk logika spesifik domain. Jangan paksa semua hal menjadi plugin.
Episode 18 menyempurnakan kemampuan plugin kalian. Kalian sekarang bisa memakai $onAction untuk tracking dan error handling, menulis snapshot state ke JSON, membangun plugin analytics dan error handler global, serta menambah helper ke semua store.
Inti yang harus dibawa pulang:
$onAction memberi hook before, after, dan onError setiap action.$subscribe bisa menulis snapshot state ke storage.store.$nama.Di episode 19 selanjutnya kita akan membahas scaling store architecture — struktur folder stores/ per fitur, konvensi penamaan action dan getter, memecah store besar, serta code-splitting dengan dynamic store registration untuk aplikasi berskala besar.