What would be the best archictecture for a Vue app that runs inside a browser rendered in Lua?

Hi everybody, I’m working in a Game made with Lua (GTA FiveM), and the game renders a browser where I run a Vue app (with typescript) on it, and the only way the user can communicate with my Vue App is throught Lua, Lua sending events to the browser and my App can react to it. I have nested components and I want to communicate with them (send them data/call their methods dynamically).

I created two simple apps using two different architectures to communicate with components (one with Vuex, and the other with another library for “event emitter” called mitt suggested in the docs) that you can check here.
App with vuex

App with event bus

I’ve seen people often saying that Vuex is the way to go for 98% of cases, but I would like to know if my particuar case is among these 2% since it’s a very special case for a Vue app. And there is a drawback when using Vuex is that I’m forced to create a state, a mutation and a action to manipulate data that is gonna be used inside only one component.

I would like to know which one is the best or if there is another way that is even better.

my App with Vuex :
In the App.vue my App listens to windows events with data and call the action HandleEvent from my store.

mounted() {
    window.addEventListener("message", ({ data }) => {
        this.$store.dispatch("handleEvent", data);

This action will check the data sent in the event, and call another action from another namespaced module.

handleEvent({commit, dispatch}, {component, action, payload}) {
            //this check is only to avoid events dispatched by Vue cli
            if (component) {
                if (action === 'changeComponent') {
                    commit('component', component);
                } else {
                    dispatch(`${component}/${action}`, payload);

And in my nested component I have to register its module

beforeCreate() {
        this.$store.registerModule(name, grandChildOneModule);

and create an action that will set its data

actions: {
        setFoo(context, payload: string[]) {
            context.commit('SET_FOO', payload);

Event emitter App
My App.vue will listen to windows events then will emit another event to a specific component name

mounted() {
        window.addEventListener('message', ({data}) => {
          const {component, action, payload} = data;
          if (action === 'changeComponent') {
            this.component = component;
            emitter.emit(component, {action, payload})

My nested component just need to have a method that set its data:

methods: {
    setFoo(payload: string[]) {
      this.foo = payload;

And it needs to listen to events with its own name and based on that it calls one of its methods dynamically:

mounted() {
    emitter.on(this.name, ({action, payload}: any) => {
      // eslint-disable-next-line @typescript-eslint/no-this-alias
      const x = this; //I have to do this since my components aren't classes
      this[action as keyof typeof x](payload);

The events my Lua will send to my Vue are listed below, (they aren’t gonna be dispatched all at once, but individually during some game triggers)

you can use the console of the website to send these events to the App and see how it react

//open child 1
window.dispatchEvent(new MessageEvent("message", {data:{component:"child-one", action:"changeComponent"}}));

//open grand child 1
window.dispatchEvent(new MessageEvent("message", {data:{component:"child-one", action:"openGrandChildOne"}}));

//send grand child 1 data
window.dispatchEvent(new MessageEvent("message", {data:{component:"grand-child-one", action:"setFoo", payload:['a','b','c']}}));

//open child 2
window.dispatchEvent(new MessageEvent("message", {data:{component:"child-two", action:"changeComponent"}}));

//open grand child 3
window.dispatchEvent(new MessageEvent("message", {data:{component:"child-two", action:"openGrandChildTwo"}}));

//send grand child 3 data
window.dispatchEvent(new MessageEvent("message", {data:{component:"grand-child-two", action:"setBar", payload:[1,2,3]}}));