Last active
February 11, 2024 22:27
-
-
Save foo123/20e0ca043cdc50ecb004 to your computer and use it in GitHub Desktop.
UMD JavaScript Module pattern with dependencies (bundled-in or external) for Node/CommonJS, AMD/RequireJS, Web Workers and Browser (~2.2kB of extra code minified)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
!function ( root, name, deps, factory ) { | |
"use strict"; | |
// | |
// export the module umd-style (with deps bundled-in or external) | |
// Get current filename/path | |
function getPath( isNode, isWebWorker, isAMD, isBrowser, amdMod ) | |
{ | |
var f; | |
if (isNode) return {file:__filename, path:__dirname}; | |
else if (isWebWorker) return {file:(f=self.location.href), path:f.split('/').slice(0, -1).join('/')}; | |
else if (isAMD&&amdMod&&amdMod.uri) return {file:(f=amdMod.uri), path:f.split('/').slice(0, -1).join('/')}; | |
else if (isBrowser&&(f=document.getElementsByTagName('script'))&&f.length) return {file:(f=f[f.length - 1].src), path:f.split('/').slice(0, -1).join('/')}; | |
return {file:null, path:null}; | |
} | |
function getDeps( names, paths, deps, depsType, require ) | |
{ | |
var i, dl = names.length, mods = new Array( dl ); | |
for (i=0; i<dl; i++) | |
mods[ i ] = (1 === depsType) | |
? /* node */ (deps[ names[ i ] ] || require( paths[ i ] )) | |
: (2 === depsType ? /* amd args */ (require( names[ i ] )) : /* globals */ (deps[ names[ i ] ])) | |
; | |
return mods; | |
} | |
// load javascript(s) (a)sync using <script> tags if browser, or importScripts if worker | |
function loadScripts( scope, base, names, paths, callback, imported ) | |
{ | |
var dl = names.length, i, rel, t, load, next, head, link; | |
if ( imported ) | |
{ | |
for (i=0; i<dl; i++) if ( !(names[ i ] in scope) ) importScripts( base + paths[ i ] ); | |
return callback( ); | |
} | |
head = document.getElementsByTagName("head")[ 0 ]; link = document.createElement( 'a' ); | |
rel = /^\./; t = 0; i = 0; | |
load = function( url, cb ) { | |
var done = 0, script = document.createElement('script'); | |
script.type = 'text/javascript'; script.language = 'javascript'; | |
script.onload = script.onreadystatechange = function( ) { | |
if (!done && (!script.readyState || script.readyState == 'loaded' || script.readyState == 'complete')) | |
{ | |
done = 1; script.onload = script.onreadystatechange = null; | |
cb( ); | |
head.removeChild( script ); script = null; | |
} | |
} | |
if ( rel.test( url ) ) | |
{ | |
// http://stackoverflow.com/a/14781678/3591273 | |
// let the browser generate abs path | |
link.href = base + url; | |
url = link.protocol + "//" + link.host + link.pathname + link.search + link.hash; | |
} | |
// load it | |
script.src = url; head.appendChild( script ); | |
}; | |
next = function( ) { | |
if ( names[ i ] in scope ) | |
{ | |
if ( ++i >= dl ) callback( ); | |
else if ( names[ i ] in scope ) next( ); | |
else load( paths[ i ], next ); | |
} | |
else if ( ++t < 30 ) { setTimeout( next, 30 ); } | |
else { t = 0; i++; next( ); } | |
}; | |
while ( i < dl && (names[ i ] in scope) ) i++; | |
if ( i < dl ) load( paths[ i ], next ); | |
else callback( ); | |
} | |
deps = deps || [[],[]]; | |
var isNode = ("undefined" !== typeof global) && ("[object global]" === {}.toString.call(global)), | |
isBrowser = !isNode && ("undefined" !== typeof navigator), | |
isWebWorker = !isNode && ("function" === typeof importScripts) && (navigator instanceof WorkerNavigator), | |
isAMD = ("function" === typeof define) && define.amd, | |
isCommonJS = isNode && ("object" === typeof module) && module.exports, | |
currentGlobal = isWebWorker ? self : root, currentPath = getPath( isNode, isWebWorker, isAMD, isBrowser ), m, | |
names = [].concat(deps[0]), paths = [].concat(deps[1]), dl = names.length, i, requireJSPath, ext_js = /\.js$/i | |
; | |
// commonjs, node, etc.. | |
if ( isCommonJS ) | |
{ | |
module.$deps = module.$deps || {}; | |
module.exports = module.$deps[ name ] = factory.apply( root, [{NODE:module}].concat(getDeps( names, paths, module.$deps, 1, require )) ) || 1; | |
} | |
// amd, requirejs, etc.. | |
else if ( isAMD && ("function" === typeof require) && ("function" === typeof require.specified) && | |
require.specified(name) ) | |
{ | |
if ( !require.defined(name) ) | |
{ | |
requireJSPath = { }; | |
for (i=0; i<dl; i++) | |
require.specified( names[ i ] ) || (requireJSPath[ names[ i ] ] = paths[ i ].replace(ext_js, '')); | |
require.config({ paths: requireJSPath }); | |
// named modules, require the module by name given | |
define( name, ["require", "exports", "module"].concat( names ), function( require, exports, module ) { | |
return factory.apply( root, [{AMD:module}].concat(getDeps( names, paths, arguments, 2, require )) ); | |
}); | |
} | |
} | |
// browser, web worker, other loaders, etc.. + AMD optional | |
else if ( !(name in currentGlobal) ) | |
{ | |
loadScripts( currentGlobal, currentPath.path + '/', names, paths, function( ){ | |
currentGlobal[ name ] = m = factory.apply( root, [{}].concat(getDeps( names, paths, currentGlobal )) ) || 1; | |
isAMD && define( name, ["require"], function( ){ return m; } ); | |
}, isWebWorker); | |
} | |
}( /* current root */ this, | |
/* module name */ "MODULE_NAME", | |
/* module dependencies */ [['Dep1', 'Dep2'],['./dep1.js', './dep2.js']], | |
/* module factory */ function( exports, Dep1, Dep2 ) { | |
/* main code starts here */ | |
// custom exports object will export automatically to node/requirejs/worker/browser/etc.. as needed | |
exports["MODULE_NAME"] = { /* ... */}; | |
/* main code ends here */ | |
/* export the module */ | |
return exports["MODULE_NAME"]; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment