I've been experimenting with using a shared vue.js state within a web extension.
The state is actually stored in the background script's DOM and then rendered in a popup page.
Initial Strategy
Initially, I tried using a simple store without vuex:
background.js
var store = {
count: 0
};
popup.js
browser.runtime.getBackgroundPage().then(bg => {
var store = bg.store;
var vue = new Vue({
el: '#app',
data: {
state: store
},
})
})
popup.html
<div id="app">
<p>{{ state.count }}</p>
<p>
<button @click="state.count++">+</button>
</p>
</div>
<script src="vue.js"></script>
<script src="popup.js"></script>
This method worked successfully upon first opening the popup. The counter could be incremented and the value would update accordingly. However, on subsequent openings of the popup, rendering failed with an error message stating
[Vue warn]: Error in render: "TypeError: can't access dead object"
. This appeared to be due to the fact that the initial popup instance of vue.js had modified the `store` by adding its own getter/setters, which were no longer available when the popup was reopened, rendering the shared state useless. Since this issue seemed inevitable, I decided it was time to try using vuex.
Second Attempt
background.js
var store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment: state => state.count++,
}
})
popup.js
browser.runtime.getBackgroundPage().then(bg => {
var store = bg.store;
var vue = new Vue({
el: '#app',
computed: {
count () {
return store.state.count
}
},
methods: {
increment () {
store.commit('increment')
},
}
});
})
popup.html
<div id="app">
<p>{{ count }}</p>
<p>
<button @click="increment">+</button>
</p>
</div>
<script src="vue.js"></script>
<script src="popup.js"></script>
Unfortunately, this approach also encountered issues. While you could see the current counter value upon opening the popup, incrementing it didn't automatically update the view (you needed to reopen the popup to see the updated value).
When moving the same code but declaring the store directly in popup.js, everything functioned as expected. It should have worked with the shared store, but for some reason it did not.
My questions:
- Is vue.js simply unable to handle this specific use case?
- If so, would other frameworks such as Angular or React be better suited for this scenario?