Plugins

Os stores do Vuex aceitam a opção plugins que expõe 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 = new Vuex.Store({
  // ...
  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 componentes, eles podem apenas acionar mudanças fazendo o commit de mutações.

Por 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 = new Vuex.Store({
  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 build que lidam com isso para nós:

const store = new Vuex.Store({
  // ...
  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 no build final.

Plugin de Log Integrado

Se você está usando vue-devtools provavelmente não precisará disso.

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

import createLogger from 'vuex/dist/logger'

const store = new Vuex.Store({
  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 !== "aBlacklistedMutation"
  },
  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
  },
  logger: console, // implementação da API `console`, default `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 esses plugins capturam momentos do estado, então use-os apenas durante o desenvolvimento.