Electron-vue: sharing `vuex` store in both `main` and `renderer` processes

Created on 8 Jun 2017  Â·  9Comments  Â·  Source: SimulatedGREG/electron-vue

Hey again.

How do you access the store from the main process? I wan't to read/write values to/from it.

It works fine from the render process.

Thank you.

discussion

Most helpful comment

@Zyles

There really isn't a simple or nice way to accomplish this. What you can do is share the vuex state with the main process with a vuex plugin.

Here's what I was able to accomplish with the default electron-vue setup. Please note this only gives you access to state, and is only updated on mutations. This will not provide access to vuex mutations, getters, actions, etc. Changing state in the main process will not persist changes to the renderer process.

inside src/main/index.js

global.vuexState = null

ipcMain.on('vuex-state', (e, state) => {
  global.vuexState = state
  console.log(global.vuexState)
  // => { Counter: { main: 0 } }
})

src/renderer/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

import modules from './modules'
import broadcaster from './broadcaster'

Vue.use(Vuex)

export default new Vuex.Store({
  modules,
  plugins: [broadcaster],
  strict: process.env.NODE_ENV !== 'production'
})

src/renderer/store/broadcaster.js

import { ipcRenderer } from 'electron'

export default store => {
  ipcRenderer.send('vuex-state', store.state)

  store.subscribe((mutation, state) => {
    console.log('plugin hit')
    ipcRenderer.send('vuex-state', state)
  })
}

Sending store over ipcRenderer will not yield an expected result. The IPC communication will internally serialize the data, therefore all prototype methods attached to vuex will never make it to the main process, hence why you can't use mutations, getters, actions, etc.

Update: The reverse of this setup might be more plausible; by moving the vuex store to live in the main process. That would require much more experimenting though.

All 9 comments

@Zyles

There really isn't a simple or nice way to accomplish this. What you can do is share the vuex state with the main process with a vuex plugin.

Here's what I was able to accomplish with the default electron-vue setup. Please note this only gives you access to state, and is only updated on mutations. This will not provide access to vuex mutations, getters, actions, etc. Changing state in the main process will not persist changes to the renderer process.

inside src/main/index.js

global.vuexState = null

ipcMain.on('vuex-state', (e, state) => {
  global.vuexState = state
  console.log(global.vuexState)
  // => { Counter: { main: 0 } }
})

src/renderer/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

import modules from './modules'
import broadcaster from './broadcaster'

Vue.use(Vuex)

export default new Vuex.Store({
  modules,
  plugins: [broadcaster],
  strict: process.env.NODE_ENV !== 'production'
})

src/renderer/store/broadcaster.js

import { ipcRenderer } from 'electron'

export default store => {
  ipcRenderer.send('vuex-state', store.state)

  store.subscribe((mutation, state) => {
    console.log('plugin hit')
    ipcRenderer.send('vuex-state', state)
  })
}

Sending store over ipcRenderer will not yield an expected result. The IPC communication will internally serialize the data, therefore all prototype methods attached to vuex will never make it to the main process, hence why you can't use mutations, getters, actions, etc.

Update: The reverse of this setup might be more plausible; by moving the vuex store to live in the main process. That would require much more experimenting though.

Update 2: Placing the vuex store in the main process isn't possible unfortunately, vuex requires vueto function. Yes it is possible to setup a store and then expose as a global to the renderer process, but the problem you hit here is that since the store was created from a vue instance that lives in the main process, your renderer process vue instance will not recieve reactive updates. The state will surely change, but any computed properties that access the store will not be reactive.

I then went a step further and also exposed the main process vue instance to the renderer process, but since document isn't avilable in the main process, this just won't work. I feel that if Vue.js had a core setup of vue and something like vue-dom, similar to how react works, this might be possible. Still looking to experiment a bit more, but these are my findings.

I'm currently developing a module to address this, called ipc-flux. It's loosely based on vuex, and dispatching is entirely asynchronous.

ipc-flux

Think of it a bit like two separate instances of a vuex store. One in the main process, the other in the renderer process. Main actions are defined in the main process, renderer actions are defined in the renderer process. Using dispatch refers to actions in the current process, dispatchExternal refers to actions in the other process.

Note: This is not a drop in replacement for vuex, nor is it a plugin for vuex, it is a standalone module.

Note: Only actions have been added thus far.

The docs are included in the README.md in the github repo, if you do choose to use it and are confused at all, let me know, I'd be happy to help you.

you also can use store through proxy by electron-remote

I roughly followed this method and it seems to work pretty well. I made a fork you can try out with this:

vue init jmschneider/electron-vue my-project

There are definitely a few improvements to be made but it is a decent proof of concept. Essentially all actions are run on the main process and any mutations are then sent to all of renderer processes. It does mean you need to keep your mutations very static. If you try accessing something like Date.now() or uuid() inside a mutation you will end up with a different value in every store. You just have to move those methods to actions and send the results in the mutations.

It is also helpful that all mutations, actions, getters, modules, etc code is essentially shared between both processes. You can add node-persist and robinvdvleuten/vuex-persistedstate to the mainStore.js for really easy persisted state when the application is closed and re-opened.

Hi guys,

I've created the special package for Vuex and Electron integration:
– https://github.com/vuex-electron/vuex-electron

Plugin support added to template.

Is there any way, To listen to messages sent from Main to renderer in Vuex

Is there any way, To listen to messages sent from Main to renderer in Vuex

Isn't that what IPC does?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alexiej picture alexiej  Â·  3Comments

blackw212 picture blackw212  Â·  3Comments

pansila picture pansila  Â·  3Comments

mvalim picture mvalim  Â·  4Comments

webrtcn picture webrtcn  Â·  3Comments