infinnie / infinnie.github.io

https://infinnie.github.io/
Apache License 2.0
0 stars 1 forks source link

A simple AMD loader using jQuery #1

Closed infinnie closed 6 years ago

infinnie commented 8 years ago

WARNING: ES5 features are used here in the code below. Rewrite with jQuery methods or use ES5-shim to make the code work in ES3 environments.

//! (c) All rights reserved

var define = (function ($) {
    var storage = {},
        pendingList = {},
        rootPath = "/",
        nameMap = {},
        resolveDep = function (key) {
            var url;
            if (typeof key === "function") {
                return key;
            }
            if (key in storage) {
                return storage[key];
            }
            if (key in nameMap) {
                url = nameMap[key];
            }
            if (!(key in pendingList)) {
                pendingList[key] = (function () {
                    var d = $.Deferred(), s = document.createElement("script");
                    s.src = (key in nameMap) ? url : (rootPath + key + ".js");
                    s.onload = function () {
                        d.resolve(storage[key]);
                    };
                    $(function () {
                        $("head")[0].appendChild(s);
                    });
                    return d.promise();
                })();
            }
            return pendingList[key];
        };

    /**
     * AMD shim
     * @param {String}name
     * @param {[String]}deps
     * @param {Function}cb
     */
    var define = function (name, deps, cb) {
        if ($.isFunction(deps) && typeof name === "string") {
            return define(name, [], deps);
        }
        if ($.isArray(name) || $.isFunction(name)) {
            throw new Error("Not implemented.");
        }
        var arr = /((.*?\/)(?:[^/]+\/)?)?[^/]+$/.exec(name),
            path = arr[1], parentPath = arr[2];

        if ((typeof path === "string") && path) {
            deps = deps.map(function (dep) {
                return dep.replace(/^\.\//, path);
            });
        }
        if ((typeof parentPath === "string") && parentPath) {
            deps = deps.map(function (dep) {
                return dep.replace(/^\.\.\//, parentPath);
            });
        }
        // do something
        if (name in storage) {
            return;
        }
        $.when.apply($, deps.map(function (dep) {
            if ("require" !== dep) {
                return dep;
            }
            return function (x) {
                if (/Array/.test(Object.prototype.toString.call(x))) {
                    return define.require.apply(define, arguments);
                }
                if ((typeof path === "string") && path) {
                    x = x.replace(/^\.\//, path);
                }
                if ((typeof parentPath === "string") && parentPath) {
                    x = x.replace(/^\.\.\//, parentPath);
                }
                if (x in storage) {
                    return storage[x];
                }
                throw new Error("Module not found :(");
            }
        }).map(resolveDep)).then(function () {
            storage[name] = cb.apply(null, arguments);
        });
    };

    define.amd = true;
    /**
     * @param {[String]}deps
     * @param {Function}cb
     */
    define.require = function (deps, cb) {
        $.when.apply($, deps.map(resolveDep)).then(function () {
            cb.apply(null, arguments);
        });
    };
    define.requirePromise = function (deps) {
        var d = $.Deferred();
        define.require(deps, function () {
            d.resolve([].slice.call(arguments));
        });
        return d.promise();
    }

    /**
     * @param {Object}obj
     */
    define.config = function (obj) {
        if ("root" in obj) {
            rootPath = obj.root;
        }
    };

    /**
     * @param {String}name
     * @param {String}url
     */
    define.mapModule = function (name, url) {
        var i;
        if (!name) { return nameMap; }
        if (name === "require") { return false; }
        if (typeof name === "object") {
            for (i in name) {
                nameMap[i] = name[i];
            }
            return true;
        }
        nameMap[name] = url;
        return true;
    };
    return define;
})(jQuery);

define("jquery", [], function () {
    return jQuery;
});