skip to Main Content

I have a JS plugin in Shopware 6, that subscribes to two events of another JS plugin:

One that fires after the user interacts with the page and one that fires at the end of init().

The latter does nothing. I am confused because the other event works just fine.

Both $emitter.publish have the same argument. In my plugin, they use the same method:

// main.js
import MyPlugin from "./my-plugin/my-plugin.plugin";

const PluginManager = window.PluginManager;
PluginManager.register("MyPlugin", MyPlugin);
// ./my-plugin/my-plugin.plugin.js
import Iterator from "src/helper/iterator.helper";

export default class MyPlugin extends window.PluginBaseClass {
  init() {
    const configuratorPlugins =
      window.PluginManager.getPluginInstances("TargetPlugin");
    Iterator.iterate(configuratorPlugins, (instance) => {
      // nope ...
      instance.$emitter.subscribe("init", this.onEvent.bind(this));
      // working ...
      instance.$emitter.subscribe(
        "otherEvent",
        this.onEvent.bind(this)
      );
    });
  }

  onEvent(event) {
    // do it ...
  }
}
// target-plugin.plugin.js
    init() {
        // ...
        this.$emitter.publish('init', this.createCurrentState());
    }

The init event is not inside an if statement. I tested this.createCurrentState() with a console.log() right before the event and that works.

Also, I looked into PluginManager.getPluginList(). The other plugin is in the list before my plugin gets registered – if that helps.

Don’t know what I am doing wrong. That plugin is the only one which publishes an event inside init().

2

Answers


  1. Looking at the code snippets provided and the behavior you are seeing, some possible issues and steps to troubleshoot are:

    1. Event Subscription Timing
      From the fact that "otherEvent" subscription works, it means that your MyPlugin initialization is correct and it can subscribe to events from TargetPlugin instances. However, the subscription to the "init" event doesn’t work reliably.

    2. Plugin Registration Order
      You said you checked PluginManager.getPluginList() and confirmed that TargetPlugin is already in the list prior to the registration of MyPlugin. Good, because that way, when MyPlugin initializes and it subscribes to events from TargetPlugin instances, the instances of TargetPlugin should have been already created.

    3. Ensure event publishing in TargetPlugin
      You mentioned that TargetPlugin publishes an "init" event in its init() method. This new publishing of the event shall occur only after the plugin has been completely initialized and its internal state, for example this.createCurrentState(), is available for subscribers.

    4. Check for Asynchronous Initialization
      Sometimes, plugins or components just initialize themselves asynchronously. In this case, the "init" event might well be triggered before TargetPlugin or its components have finished initialization and event subscription if initialization of TargetPlugin or its components occurs asynchronously.

    In such scenarios, proper synchronization could be attained by potentially using promises or async/await patterns if your plugin system allows for these to make sure that subscriptions are attempted only after all plugins have been initialized.

    Notice the possible change of the initialization in your MyPlugin class to avoid asynchrony and make event-handling more robust:

    import Iterator from "src/helper/iterator.helper";
    
    export default class MyPlugin extends window.PluginBaseClass {
      async init() {
        const configuratorPlugins =
          window.PluginManager.getPluginInstances("TargetPlugin");
    
        // Ensure all plugins are fully initialized before subscribing
        await Promise.all(configuratorPlugins.map(async (instance) => {
          // Assuming instance.init() returns a promise if async
          await instance.init();
    
          instance.$emitter.subscribe("init", this.onEvent.bind(this));
          instance.$emitter.subscribe("otherEvent", this.onEvent.bind(this));
        }));
      }
    
      onEvent(event) {
        // Handle events here
      }
    }
    Login or Signup to reply.
  2. In my opinion, the problem is exactly this:

    Also, I looked into PluginManager.getPluginList(). The other plugin is in the list before my plugin gets registered – if that helps.

    A race condition with the initialization of the plugin. You are setting the listener for event "init" inside MyPlugin init() method which is called after TargetPlugin init(). So at the moment of
    this.$emitter.publish('init', this.createCurrentState());
    MyPlugin hasn’t subscribed yet.

    Possible solutions:

    1. Rely on the PluginManager.register() order
    2. Declare that MyPlugin depends from TargetPlugin

    Both solutions imply an edit to the register plugin logic.
    The first i think it’s not much consistent, very prone to error and not clear to other devs.
    With the latter, when you register the plugin, you can pass an options object

    // where you register all the plugins
    
    const options = {
        dependencies: [...window.PluginManager.getPluginInstances("TargetPlugin")]
    };
    PluginManager.register("MyPlugin", import('src/../myplugin'), 'your-plugin-selector', options)
    

    Then in MyPlugin class you override the constructor, which is called for each plugin always before the initialization of all the others.

    import Iterator from "src/helper/iterator.helper";
    
    export default class MyPlugin extends window.PluginBaseClass {
      constructor(el, options = {}, pluginName = false) {
        super(el, options, pluginName); // important
        // iterate over options.dependecies and subscribe
      }
    }
    

    I haven’t tested the code, let me know if this idea helped.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search