brace_umd

Provides a unified module definition wrapper for RequireJS and AMDefine definitions while staying seamlessly compliant with the RequireJS optimizer and factory based objects.

Usage no npm install needed!

<script type="module">
  import braceUmd from 'https://cdn.skypack.dev/brace_umd';
</script>

README

Synopsis

Build status Downloads

The Brace Suite Ubuntu on Windows
Brace logo Ubuntu on Windows logo

Brace Umd help pages


More than a unified module definition

Brace Umd is a source-building platform to support AMD (asynchronous module definition) modules built by the RequireJs optimizer. There will be no further need to handle individual license insertions in build files or if individual modules will be working after project obfuscations. Brace Umd ensures optimal, finished and deterministic deployments of large multi-library javscript bundles.

How it works

Individual amd modules sit above Brace Umd as a dependency descendant which holds the optimization build information. The module is then built, tested and distributed with this known optimization build output. Other projects can then be compiled using their own optimizations provied by Brace Umd while not altering the external dependecy build. Then the umd wrapper is applies to the project build for deployment. This makes for consistent package builds which consist of multiple packages and modules without need of dependency optimizing.

The Brace Umd wrapper is better than other unified module definition wrappers by providing localized uglify-js functionality and option passing. This allows the umd wrap to only ever be inserted once while using projects which also are umd wraped.

Licensed under: MIT WITH BSD-2-Clause This project relies heavily on (and includes) the Uglify-js source code. Kodos, to the Uglify-js team!

Bonuses:

  • Enables cross-platform module bundling when used with the r.js optimizer and the built in factory loader
  • Provides an anonymous module option for amdefine to avoid its dependency conundrum.
  • The wrapper only adds only one new namespace (umd), by using a self-destructing proxy method
  • Provides a way to switch between definition types without altering source code
  • Allows for minification of wrapped source code using almost all of the uglify-js options
  • Well commented, professionally engineered and thoroughly documented code
  • Vast and deep unit tests on Windows 10 and Ubuntu 18

Note: it is acceptable to use mangle and mangle properties with the Umd source and in the requirejs optimizing process. This is done by storing the build config options used and then passing them back into uglify-js via the r.js build config file (see using with requirejs, for more information.

The build process involves two RequireJs configuration files to operate. The code below is for quick access and convenience. See help document pertaining to Requirejs configurations for more information.

// Project optimization r_js file:
{
    "_init": module.paths.unshift(nodeRequire("path").join(config.baseUrl, "node_modules")),
    "name": nodeRequire("path").basename(config.baseUrl),
    "out": nodeRequire("path").join("build", nodeRequire("path").basename(config.baseUrl))+".js",
    "baseUrl": "lib",
    "onBuildRead": function (module_name, module_path, content) {
        // This is how a module is built which has dependency modules which use brace_umd. The non-brace_umd module version is used instead when a module is
        // loaded which was a brace_umd built module (it will contain a _umd.js suffix). It is assumed that any module which contains a _umd.js suffix is
        // a brace_umd wrapped module. Note: this should only apply when using a require.resolve as a requirejs paths value.
        return /.+_umd\.js$/.test(module_path) && nodeRequire("fs").existsSync(module_path.replace(/_umd\.js$/, ".js")) &&
                nodeRequire("fs").readFileSync(module_path.replace(/_umd\.js$/, ".js")).toString() || content
    },
    "paths": {
    // Add any external packages use in this project here with an :empty value
    //	"": "empty:"
    },
    "optimize": "uglify",
    "uglify2": nodeRequire("brace_umd").build_option,
    "keepAmdefine": false,
    "keepBuildDir": true,
    "writeBuildTxt": false,
}
// Final project assembly r_js file:
{
    "_init": module.paths.unshift(nodeRequire("path").join(config.baseUrl, "node_modules")),
    "name": nodeRequire("path").basename(config.baseUrl),
    "out": nodeRequire("path").join("build", nodeRequire("path").basename(config.baseUrl))+(config.suffix||"")+".js",
    "baseUrl": "build",
    "onBuildRead": function (module_name, module_path, content) {
        // This is how a module is built which has dependency modules which use brace_umd. The non-brace_umd module version is used instead when a module is
        // loaded which was a brace_umd built module (it will contain a _umd.js suffix). It is assumed that any module which contains a _umd.js suffix is
        // a brace_umd wrapped module. Note: this should only apply when using a require.resolve as a requirejs paths value.
        return /.+_umd\.js$/.test(module_path) && nodeRequire("fs").existsSync(module_path.replace(/_umd\.js$/, ".js")) &&
                nodeRequire("fs").readFileSync(module_path.replace(/_umd\.js$/, ".js")).toString() || content
    },
    "paths": {
        //"": nodeRequire.resolve("").replace(/\.js\s*$/, "")
    },
    "wrap": {
        "start": config.suffix === "_umd" && nodeRequire("brace_umd").wrap_start || "",
        // Add an anonymous definition.
        "end": config.suffix === "_umd" && nodeRequire("brace_umd").wrap_end_option({"auto_anonymous": true}) || ""
    },
    "optimize": "none",
    "keepAmdefine": config.suffix !== "_umd",
    "keepBuildDir": true,
    "writeBuildTxt": false,
}

Below is the complete umd script. The following code will work in nodejs or the browser and can use any of the supported definitions (even copy/pasted into the console to enable quick project experiments):

/* Generated by Brace_Umd 0.8.2 */
!function(e, i, r, t) {
    var define, requirejs, require, umd = {
        e: 'object' == typeof module && 'filename' in module && 'exports' in module,
        requirejs: r,
        define: i,
        i: 'object' == typeof t && t || {},
        r: function() {
            var e = {
                define: !this.i.auto_anonymous && this.define || this.t,
                requirejs: this.requirejs || this.o,
                require: this.requirejs || this.e && module.require || this.factory,
                factory: this.factory
            };
            this.i.force_type in e && (e.requirejs = e.require = e.define = e.factory = e[this.i.force_type]),
            define = e.define, requirejs = e.requirejs, require = e.require;
        },
        n: !1,
        factory: function(i, r, t, o) {
            i && i.constructor === Array ? (o = t, t = r, r = i, i = '') : 'string' != typeof i && (o = r,
            t = i, r = [ 'require' ], i = '');
            var n = [], f = umd.e && module.require || e.require, u = '';
            if (r.every(function(i) {
                return i = i.replace(/^\.[\/,\\]/, ''), n.push('require' === i && f || e[i]), 'require' === i || i in e || (u = i),
                !u;
            }), !0 !== umd.n) {
                if (!i) return umd.n = !0, void (u ? console.log('The amd factory attempted to load the', i || 'anonymous', 'module that specified a dependency which was not defined:', u) : umd.e ? module.exports = t.apply(t.prototype, n) : t.apply(t.prototype, n));
                umd.n = i;
            }
            umd.e ? module.exports[i] = t.apply(t.prototype, n) : e[i] = t.apply(t.prototype, n);
        },
        f: [ 'config', 'nextTick', 'version', 'jsExtRegExp', 'isBrowser', 's', 'toUrl', 'undef', 'defined', 'specified', 'onError', 'createNode', 'load', 'exec' ],
        u: [ 'amd', 'require' ],
        t: function() {
            if (umd.e && !umd.define) try {
                umd.define = module.require('amdefine')(module);
                for (var e in umd.define) umd.t[e] = umd.define[e];
            } catch (e) {}
            var i = umd.define || umd.factory;
            i == umd.define && umd.i.auto_anonymous ? !0 !== umd.n && 'string' == typeof arguments[0] ? umd.n = arguments[0] : 'string' != typeof arguments[0] && (umd.n = !0) : (umd.t = i,
            umd.r()), i.apply(i.prototype, arguments);
        },
        o: function() {
            if (umd.e) try {
                umd.requirejs = module.require('requirejs');
            } catch (e) {}
            umd.o = umd.requirejs || umd.factory, umd.r(), umd.o.apply(umd.o.prototype, arguments);
        }
    };
    for (var o in umd.u) umd.t.__defineGetter__(umd.u[o], function(e) {
        if (umd.e && !umd.define) try {
            umd.define = module.require('amdefine')(module);
            for (var i in umd.define) delete this[i], this[i] = umd.define[i];
            return umd.define[e];
        } catch (e) {}
    }.bind(null, umd.u[o]));
    if (!requirejs) for (var o in umd.f) umd.o.__defineGetter__(umd.f[o], function(e) {
        if (umd.e) try {
            return umd.requirejs = module.require('requirejs'), umd.o = umd.requirejs, umd.r(),
            umd.requirejs[e];
        } catch (e) {
            return;
        }
    }.bind(null, umd.f[o]));
    umd.r()
// -- Add your module definitions here ----------------



// ----------------------------------------------------
umd.n.length && define([ umd.n ], function(e) {
        return e;
   });
}(this, 'function' == typeof define && define || void 0, 'function' == typeof requirejs && requirejs || void 0, {});