vue-electron / vuex-electron

Integration of Vuex and Electron
MIT License
305 stars 96 forks source link

Prototype and functions not maintained in the process it was created #42

Open TheSimpleZ opened 5 years ago

TheSimpleZ commented 5 years ago

The problem

I use this library in a project where i store a class in my state, kind of like this:

class MyCount {
  var count = 0

  getCurrentCount() {
     return count
  }
}

export default new Vuex.Store({
  state: {
    myCount: new MyCount()
  },

  actions: {
    newCounter(store, payload) {
      store.commit("newCounter", payload)
    }
  },

  mutations: {
    newCounter(state, payload) {
      state.myCount = payload
    }
  },

  plugins: [createPersistedState(), createSharedMutations()],
  strict: process.env.NODE_ENV !== "production"
})

Now this is an oversimplified example. In my case it's not really a class, but an object that has functions added to it by a 3rd party library.

The problem is that when i dispatch the newCounter action from a renderer process the action is being intercepted and processed on the main process instead. For this to happen, you currently send the dispatch type and payload using ipcRenderer.send(), which results in the payload losing the prototype chain and all functions as stated in the docs.

Proposed solution

I tried modifying the code of sharedMutations.js locally to simply sync mutations both ways instead of broadcasting them from main. The result is that the prototypes and functions will be available within the process they were created, which i feel makes more sense than having all prototypes in the main process. It seems to work well for my application, but I'm curious to whether or not you see an issue with this implementation.

I also removed the restriction of having to use actions in the renderer process, any mutations are now synced both ways.

rendererProcessLogic() {
    // Connect renderer to main process
    this.connect()

    var mainMutating = false

    // Subscribe on changes from main process and apply them
    this.onNotifyRenderers((event, { type, payload }) => {
      mainMutating = true
      this.store.commit(type, payload)
      mainMutating = false
    })

    // Subscribe on changes from Vuex store
    this.store.subscribe(mutation => {
      if (!mainMutating) {
        const { type, payload } = mutation

        // Forward changes to renderer processes
        this.notifyMain({ type, payload })
      }
    })
  }

  mainProcessLogic() {
    const connections = {}

    // Save new connection
    this.onConnect(event => {
      const win = event.sender
      const winId = win.id

      connections[winId] = win

      // Remove connection when window is closed
      win.on('destroyed', () => {
        delete connections[winId]
      })
    })

    // Subscribe on changes from renderer processes
    this.onNotifyMain((event, { type, payload }) => {
      const win = event.sender
      const winId = win.id
      delete connections[winId]
      this.store.commit(type, payload)
      connections[winId] = win
    })

    // Subscribe on changes from Vuex store
    this.store.subscribe(mutation => {
      if (connections) {
        const { type, payload } = mutation

        // Forward changes to renderer processes

        this.notifyRenderers(connections, { type, payload })
      }
    })
  }

I am willing to set up a PR if this is something you would like to use.

akodkod commented 5 years ago

https://github.com/vue-electron/vuex-electron/issues/44