Search code examples
javascriptrequirejspublish-subscribemediator

How can requirejs provide a new "class" instance for each define with properties based on the filename?


Use case is implementing a mediator pattern where each instance is a postal.js channel.

Explaining it with the actual code would require some postal.js knowledge, so my example below is conceptually similar, but only uses requirejs.

// animalSounds.js
define([],function(){
  return {
    cat:'meow',
    dog:'woof'
  };
});

// animalFactory.js ... the requirejs plugin
define(['animalSounds'],function(animalSounds){
  function animalClass(name){
    this.sound = animalSounds[name];
  }
  return {
    load:function(name, req, onload, config){
      onload(new animalClass(name)); 
    }
  }
});

// cat.js
define(['animalFactory'],function(animalInstance){
  animalInstance.sound === 'meow'; // should be true
});

// dog.js
define(['animalFactory'],function(animalInstance){
  animalInstance.sound === 'woof'; // should be true
});

Basically it's a factory that returns a new instance whenever it's required. That part I can create fine. What I'm struggling with is getting dynamic properties from other sources based on what module is requiring it. While I could define the key as a string in each file, I'm hoping to use the filename as a key to stay DRY.


Solution

  • I would just minimally break the DRY principle and have cat, for instance, like this:

    define(['animalFactory!cat'],function(animalInstance){
      animalInstance.sound === 'meow'; // should be true
    });
    

    The fact of the matter is while it would be possible to do what you want using a loader, the resulting code would be complicated, and would obscure the logic of your application. For instance, requiring animalFactory multiple times and expecting different results (which is what you have in your question) goes against one of the fundamental principles of RequireJS: requiring the same module name over and over again should return the same value over and over again.

    Note that it is possible to require the module module (it is a special module) and then use module.id to know the name of the module you are in but unfortunately, this is not available for building the dependency list on your define.