Plugins

Os stores do Vuex aceitam a opção plugins que expõe gatilhos (ou hooks) para cada mutação. Um plugin Vuex é simplesmente uma função que recebe um store como seu único argumento:

const myPlugin = (store) => {
  // chamado quando o store é inicializado
  store.subscribe((mutation, state) => {
    // chamada após cada mutação.
    // A mutação vem no formato de `{ type, payload }`.
  })
}

E pode ser usada assim:

const store = createStore({
  // ...
  plugins: [myPlugin]
})

Confirmando (ou fazendo commit de) Mutações Dentro de Plugins

Plugins não tem permissão para alterar o estado diretamente - similar aos seus componentes, eles podem apenas acionar mudanças confirmando (ou fazendo o commit de) mutações.

Por confirmar (ou fazer commit de) mutações, um plugin pode ser usado para sincronizar uma fonte de dados ao store. Por exemplo, para sincronizar uma fonte de dados websocket ao store (isso é só um exemplo inventado, na realidade a função createPlugin pode receber parâmetros adicionais para tarefas mais complexas):

export default function createWebSocketPlugin (socket) {
  return (store) => {
    socket.on('data', data => {
      store.commit('receiveData', data)
    })
    store.subscribe(mutation => {
      if (mutation.type === 'UPDATE_DATA') {
        socket.emit('update', mutation.payload)
      }
    })
  }
}
const plugin = createWebSocketPlugin(socket)

const store = createStore({
  state,
  mutations,
  plugins: [plugin]
})

Capturando os Momentos do Estado

Às vezes, um plugin pode querer receber "momentos" do estado, e também comparar o estado pós-mutação com o estado de pré-mutação. Para conseguir isso, você precisará realizar uma cópia-profunda do objeto de estado:

const myPluginWithSnapshot = (store) => {
  let prevState = _.cloneDeep(store.state)
  store.subscribe((mutation, state) => {
    let nextState = _.cloneDeep(state)

    // compara `prevState` e `nextState`...

    // salva o estado para a próxima mutação
    prevState = nextState
  })
}

Plugins que capturam momentos do estado devem ser usados apenas durante o desenvolvimento. Quando usamos webpack ou Browserify, podemos construir nossas próprias ferramentas de distribuição (ou nossos próprios builds) que lidam com isso para nós:

const store = createStore({
  // ...
  plugins: process.env.NODE_ENV !== 'production'
    ? [myPluginWithSnapshot]
    : []
})

O plugin vai ser usado por padrão. Para produção, você vai precisar do DefinePlugin para webpack ou envify para Browserify para converter o valor do process.env.NODE_ENV !== 'production' para false na distribuição (ou build) final.

Plugin de Log Integrado

Vuex vem com um plugin de log para casos comuns de depuração:

import { createLogger } from 'vuex'

const store = createStore({
  plugins: [createLogger()]
})

A função createLogger tem algumas opções:

const logger = createLogger({
  collapsed: false, // expande automaticamente mutações registradas no log
  filter (mutation, stateBefore, stateAfter) {
    // retorna `true` se uma mutação deve ser registrada no log
    // `mutation` é um `{ type, payload }`
    return mutation.type !== "aBlocklistedMutation"
  },
  actionFilter (action, state) {
    // o mesmo que `filter`, mas para ações
    // `action` é um `{ type, payload }`
    return action.type !== "aBlocklistedAction"
  },
  transformer (state) {
    // transforma o estado antes de regitrá-lo no log.
    // por exemplo, retorna apenas uma sub-árvore específica
    return state.subTree
  },
  mutationTransformer (mutation) {
    // mutações são registradas no log no formato de  `{ type, payload }`
    // mas podemos formatá-las como quisermos.
    return mutation.type
  },
  actionTransformer (action) {
    // O mesmo que mutationTransformer mas para ações
    return action.type
  },
  logActions: true, // Log de Ações
  logMutations: true, // Log de mutações
  logger: console, // implementação da API `console`, valor padrão `console`
})

O arquivo de log também pode ser incluído diretamente via tag <script>, e vai expor a função createVuexLogger globalmente.

Perceba que o plugin de log captura momentos do estado, então use-o apenas durante o desenvolvimento.