I have a chrome extension with the following webpack.config.js:
module.exports = {
mode,
entry: {
"content/content": [
"./src/js/content/content.js",
"./src/js/store.js",
"./src/js/content/overlay/style.scss",
],
"background/background": [
"./src/js/background/utils.js",
"./src/js/background/background.js",
],
"overlay/overlay": "./src/js/content/overlay/index.js",
"popup/popup": "./src/js/content/popup/index.js",
},
looking at
Shared vuex state in a web-extension (dead object issues)
https://github.com/xanf/vuex-shared-mutations
Adding a wrapper around browser local storage:
browserStore.js
import browser from "@/js/browser";
export function getStorageValue(payload) {
return new Promise((resolve) => {
browser.storage.local.get(payload, (items) => {
if (items) {
resolve(items);
}
});
});
}
export function setStorageValue(payload) {
return new Promise((resolve) => {
browser.storage.local.set(payload, (value) => {
resolve(value);
});
});
}
In "./src/js/content/popup/firstpage/store/index.js"
vuex store is defined as:
import Vue from "vue";
import Vuex from "vuex";
import "es6-promise/auto";
import createMutationsSharer from "vuex-shared-mutations";
import dummyData from "./dummyData";
import { getStorageValue, setStorageValue } from "@/js/store";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
chromePagesState: {
allSections: [],
},
},
getters: {
...
},
mutations: {
setChromePagesState(state, value) {
...
},
// this function is to be called from a content script
addWhiteListedItem(state, item) {
// state not initialized here
state.chromePagesState.allSections[0].itemSectionCategory[0].tasks.splice(
0,
0,
item
);
},
...
}
actions: {
async saveChromePagesState({ state }) {
// Save only needed fields
let data = {
...
};
await setStorageValue({ inventoryData: JSON.stringify(data) });
},
async loadChromePagesState({ commit }) {
const json = await getStorageValue("inventoryData");
// json always an empty object
commit(
"setChromePagesState",
Object.keys(json).length === 0 && json.constructor === Object
? json
: dummyData
);
},
async loadChromePagesStateBrowser({ commit }) {
browser.runtime
.sendMessage({ type: "storeinit", key: "chromePagesState" })
.then(async (chromePagesState) => {
const json = await getStorageValue("inventoryData");
commit(
"setChromePagesState",
Object.keys(json).length === 0 && json.constructor === Object
? json
: dummyData
);
});
},
plugins: [
createMutationsSharer({
predicate: [
"addWhiteListedItem",
"loadChromePagesState",
"loadChromePagesStateBrowser",
],
}),
],
},
the background script has a listener; src/background/background.js
:
browser.runtime.onMessage.addListener((message, sender) => {
if (message.type === "storeinit") {
return Promise.resolve(store.state[message.key]);
}
});
The content script that needs to make use of the shared store has an entry point in content.js
:
import { initOverlay } from '@/js/content/overlay';
import browser from '@/js/browser';
browser.runtime.onMessage.addListener(function (request, _sender, _callback) {
// vue component gets created here:
if (request && request.action === 'show_overlay') {
initOverlay();
}
return true; // async response
});
initOverlay()
creates a vue component in ./src/js/content/overlay/index.js
:
import Vue from "vue";
import Overlay from "@/js/content/overlay/Overlay.vue";
import browser from "@/js/browser";
import { getStorageValue } from "@/js/store";
import store from "../popup/firstpage/store";
Vue.prototype.$browser = browser;
export async function initOverlay(lockScreen = defaultScreen, isPopUp = false) {
...
setVueOverlay(overlayContainer, cover);
...
}
function setVueOverlay(overlayContainer, elem) {
if (!elem.querySelector("button")) {
elem.appendChild(overlayContainer);
elem.classList.add("locked");
new Vue({
el: overlayContainer,
store,
render: (h) => h(Overlay, { props: { isPopUp: isPopUp } }),
});
}
}
Overlay.vue
only needs to call a mutation (addWhiteListedItem
) from store:
<template>
<button
@click="addToWhiteList()"
>White list!</button
>
</template>
<script>
import { mapState, mapMutations } from "vuex";
export default {
data() {
return {
};
},
computed: mapState(["chromePagesState"]),
methods: {
...mapMutations(["addWhiteListedItem"]),
addToWhiteList() {
console.log("addToWhiteList()");
let newItem = {
...
};
// store not defined fails with:
Uncaught TypeError: Cannot read property 'itemSectionCategory' of undefined
at Store.addWhiteListedItem (index.js:79)
at wrappedMutationHandler (vuex.esm.js:853)
at commitIterator (vuex.esm.js:475)
at Array.forEach (<anonymous>)
at eval (vuex.esm.js:474)
at Store._withCommit (vuex.esm.js:633)
at Store.commit (vuex.esm.js:473)
at Store.boundCommit [as commit] (vuex.esm.js:418)
at VueComponent.mappedMutation (vuex.esm.js:1004)
at eval (Overlay.vue?./node_modules/vue-loader/lib??vue-loader-options:95)
this.addWhiteListedItem(newItem);
}, 1500);
},
},
};
</script>
Why doesn't Overlay.vue
"see" the state of store?
from vuex shared state in chrome extension
No comments:
Post a Comment