Write Requirejs modules that work without requirej

2019-05-23 23:10发布

问题:

I would like to create my modules in a way, that they can be used with and without requirejs (without require js they should just work normally, so I have to make sure they load correctly, like putting script tags in the right order).

So jQuery does it kindof like this:

// export module
if ( typeof define === "function" && define.amd ) {     
    define(["dep"], function(dep){
        dep.fn.test = test;
        return dep;
    });
}
else{ 
    dep.fn.test = test;
}

The actual module is defined as like so

var dep = function(...){...}

This definition and the export part is within an IIFE to keep everything in out of the global scope.

Generally it works well with one exception, the dependency is not available. This problem can be solved by defining the function within the define part, but this would mean defining it twice, in the define part and below in the else part.

How can I get this to work but only define the module once?

I have "plugin-like" extensions to a core dep which should all be in separate files so the main dep must be passed as a depenency

This works fine btw. but it would mean I write the code for test twice.

(function(){
    // export module
    if ( typeof define === "function" && define.amd ) {     
        define(["dep"], function(dep){
            dep.fn.test = function(){...ssomething using dep...};
            return dep;
        });
    }
    else{ 
        dep.fn.test = unction(){...ssomething using dep...};
    }

})

Okay, I try another example

animate/animate.js (this is my main file)

define(function(){
  ...
  return animate;
});

animate/modules/easing.js (this is a module file) (function(){ var ease = function(){ // using animate main function from animate.js // animate is not available here ... };

if ( typeof define === "function" && define.amd ) {
    define(["animate/animate"], function(animate){
      // animate is available here
      ...
     animate.fn.ease = ease;
     return animate;
    });
}
else
{
    // if no requirejs, animate is global
    animate.fn.ease = ease;
}
});

回答1:

I think you're just writing the define incorrectly and so it's not getting registered. This is what I use.

if (typeof define === "function" && define.amd) {
    define("telegraph", [], function () { return telegraph; });
}

Put in context

(function(window) {
    var telegraph = function() { };

    telegraph.prototype.test = function() {
       // do something
    };

    if (typeof define === "function" && define.amd) {
        define("telegraph", [], function () { return telegraph; });
    }

    window.telegraph = telegraph;

})(window);

EDIT

Do the question is really how do you define test and make use of dep internally so that you don't have to supply it as a dependency and can define a named dep module. One solution is to register the second-level functions in the constructor and capture this as self (or another variable) to use within the function. The key thing here is that you use define to define the named module and by using the captured context in the constructor, you don't need to supply the parent object as a dependency. Example (with working fiddle at http://jsfiddle.net/YS8v6/):

(function(){
    var dep = function() {
        var self = this;
        self.fn.test = function() {
            self.foo();
        };
    };

    dep.prototype.foo = function() {
       alert('foo');
    };

    dep.prototype.fn = function() {

    };

    if ( typeof define === "function" && define.amd ) {     
        define('dep', [], function() { return dep; });
    }

})();


回答2:

The actual problem seems to be that define is not available within the IIFE but window.define is. So passing define as an argument to the IIFE solves the problem.

(function(define){
    // export module
    if ( typeof define === "function" && define.amd ) {     
        define(["dep"], function(dep){
            dep.fn.test = function(){...ssomething using dep...};
            return dep;
        });
    }
    else{ 
        dep.fn.test = unction(){...ssomething using dep...};
    }

}(window.define))

Before it would check for define, not find it and immediately try to attache it to dep.fn.test without the requirejs define part.