UNPKG

curl-amd

Version:

curl.js is small, fast, extensible module loader that handles AMD, CommonJS Modules/1.1, CSS, HTML/text, and legacy scripts.

205 lines (184 loc) 6.22 kB
/** MIT License (c) copyright 2010-2013 B Cavalier & J Hann */ /** * curl legacy loader * * Loads legacy javascript scripts as if they were modules. Since legacy * scripts don't specify any dependencies and typically hoard many * things into one file, this isn't always straightforward. This loader * can be configured to adapt to almost any situation. * * Config options: * * exports {string} * Typically, specifies the name of a * global variable exposed by the legacy script, but can be any code that * can be executed by `eval()` at the global scope. The result of the * `eval()` is verified not to throw an exception and is used as the value * exported to other modules that depend on this script. * * factory {function} * The factory is executed when the script * is loaded and should return something to export to other modules. The * factory should thow an exception if it can't find the thing to export. * Even though the `exports` config option can evaluate arbitrary code, the * `factory` option should be used since it can be tested and/or linted. * Furthermore, the factory function takes a string argument that identifies * the module being requested. This allows the function to be reused for * multiple modules. * * NOTE: One of the `exports` or `factory` config options must be provided * because, without them, there is no way for a loader to determine if a * script has loaded in IE6-10. * * requires {array} * An array of module ids that are required for the script * to execute correctly. These module ids may refer to other legacy scripts * that have been configured via the legacy loader. * * dontWrapLegacy {boolean} * A build-time only option to tell cram to * add a define() at the end of the script rather than *around* the script. * Typically, this would never be needed. * * @example Backbone * * This backbone example uses a function call to return the exports. If * the code to return the exports is any more sophisticated than this, you * should consider using a `factory` option instead of `exports` since * factory functions can be tested and/or linted. * * curl.config({ * paths: { * backbone: { * location: 'modules/backbone-1.3.1/backbone.js', * config: { * loader: 'curl/loader/legacy', * exports: 'Backbone.noConflict()', * requires: ['jquery', 'lodash'] * } * } * } * }); * * @example jQuery UI * * This jQuery UI example uses the `factory` option to return the correct * jQuery UI widget from a concatenated collection of widgets in a * jqueryui.js file. * * curl.config({ * packages: { * jqueryui: { * location: 'modules/jquery-1.6.3/jqueryui.js#', * config: { * loader: 'curl/loader/legacy', * factory: function (fullId) { * var id = fullId.replace('jqueryui/', ''); * return $.fn[id]; * } * requires: ['jquery', 'css!jqueryui.css'] * } * } * } * }); */ (function (global, doc, testGlobalVar) { define(/*=='curl/loader/legacy',==*/ ['curl/_privileged'], function (priv) { "use strict"; var hasAsyncFalse, loadScript, dontAddExtRx; hasAsyncFalse = doc && doc.createElement('script').async == true; loadScript = priv['core'].loadScript; dontAddExtRx = /\?|\.js\b/; return { 'load': function (resId, require, callback, cfg) { var exports, factory, deps, dontAddFileExt, url, options, countdown; exports = cfg['exports'] || cfg.exports; factory = cfg['factory'] || cfg.factory; if (!exports && !factory) { throw new Error('`exports` or `factory` required for legacy: ' + resId); } deps = [].concat(cfg['requires'] || cfg.requires || []); dontAddFileExt = cfg['dontAddFileExt'] || cfg.dontAddFileExt; dontAddFileExt = dontAddFileExt ? new RegExp(dontAddFileExt) : dontAddExtRx; url = require['toUrl'](resId); if (!dontAddFileExt.test(url)) { url = nameWithExt(url, 'js'); } options = { url: url, order: true, // set a fake mimetype if we need to wait and don't support // script.async=false. mimetype: hasAsyncFalse || !deps.length ? '' : 'text/cache' }; // hasAsyncFalse, nodeps: load | _export // hasAsyncFalse, deps: getDeps+load | _export // !hasAsyncFalse, nodeps: load | _export // !hasAsyncFalse, deps: getDeps+load | reload | _export if (deps.length) { countdown = 2; getDeps(); load(); } else { countdown = 1; load(); } function getDeps () { // start process of getting deps, then either export or reload require(deps, hasAsyncFalse ? _export : reload, reject); } function load () { // load script, possibly with a fake mimetype loadScript(options, _export, reject); } function reload () { // if we faked the mimetype, we need to refetch. // (hopefully, from cache, if cache headers allow.) options.mimetype = ''; loadScript(options, _export, reject); } function _export () { var exported; if (--countdown > 0) return; if (factory) { try { exported = factory.call(global, resId); } catch (ex) { reject(new Error('Factory for legacy ' + resId + ' failed: ' + ex.message)); } } else { try { exported = testGlobalVar(exports); } catch (ex) { reject(new Error ('Failed to find exports ' + exports + ' for legacy ' + resId)); } } // define the module as if it were a regular module. // Note: the parens hide the "define signature" from cram.js (define)(resId, exported); // also return the plugin-syntax module ("legacy!foo"). callback(exported); } function reject (ex) { (callback['error'] || function (ex) { throw ex; })(ex); } }, 'cramPlugin': '../cram/legacy' }; function nameWithExt (name, defaultExt) { return name.substr(name.length - 3) !== '.' + defaultExt ? name + '.' + defaultExt : name; } }); }( this, this.document, function () { return (1, eval)(arguments[0]); } ));