uRequire@greecejs: An introduction to http://uRequire.org
1. The JavaScript Universal Module &
Resource Converter
“Write modular JavaScript code once, run everywhere” is a reality.
uRequire.org
2. • Why Modularity
• JavaScript module systems
• uRequire primer
• A modules & dependencies builder
• Build config usage
uRequire.org
3. Why modularity
• Maintainable & reusable code
– Organize code in logical parts
– Clearly stated dependencies
– Reusability, Replace-ability, Testability etc
• Employ standards and trusted tools
– Unit Testing, Versioning, Regression Testing
• Have a dynamic code loading mechanism.
• End the damnation of
– Authoring “OneHuge.js” file
– .js file concatenation
uRequire.org
4. • Why Modularity
• JavaScript module systems & woes
• uRequire primer
• A modules & dependencies builder
• Build config usage
uRequire.org
5. CommonJS (nodejs)
var dep1 = require("../some/path/dep1"),
dep2 = require("../other/path/dep2"),
localDep = require("localDep");// ‘localDep’ in node_modules
// do stuff with dep1, dep2 & localDep
// `return` module value
module.exports = {my: "module"}
// or set properties on `exports`
exports.my = "module" // `exports` is a pre-given {}
uRequire.org
7. • Many woes on Module formats & incompatibilities
• Verbose syntax, boilerplate ceremony & intricacies
(especially AMD)
• execution environment (AMD only for Web,
CommonJs only for nodejs)
• capabilities, dependency/path resolutions, plugins,
semantics etc are a mess
• UMD is a semi-standard boilerplate, far from usable.
• U need a bridge to enjoy the richness of modules.
uRequire.org
Why do JavaScript developers hate
modules ?
8. Mixing AMD & CommonJs ?
define(['main/dep1', 'main/helpers/dep2'],
function(dep1, dep2) {
var dep3 = require('moredeps/dep3');
if (dep3(dep1) === 'wow'){
require(['./dep4'], function(dep4) {
// asynchronously do things with dep4
});
}
// do stuff with dep1, dep2, dep3
return {my:'module'}
}
);
uRequire.org
Too many woes
AMD: “require” needs to be in []
dependencies 1st (& fn params)
AMD: “moredeps/dep3” not
listed as [] dependency, halts
nodejs: ‘define’
is unknown (use
amdefine ?)
nodejs: async
‘require’ not working
nodejs: bundleRelative
paths not working
9. UMD: Universal Module Definition
// https://github.com/umdjs/umd/blob/master/returnExports.js
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['b'], factory);
} else if (typeof exports === 'object') {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports, like Node.
module.exports = factory(require('b'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.b);
}
}(this, function (b) {
// use b in some fashion.
// Just return a value to define the module export.
// This example returns {}, but can return a function as the exported value.
return {};
}));
uRequire.org
Not really a “Universal” one but …
… 10s of proposed module templates, for different scenarios.
10. Dependency path resolution:
• nodejs: relative to requiring file (fileRelative) only:
• AMD: relative to bundle (bundleRelative) also:
• Both are useful (at times). Can we use both ?
uRequire.org
AMD + CommonJS = neighbors from hell
var replace = require(“../../../string/replace");
• define(["utils/string/replace"], ...);
11. • Why Modularity
• JavaScript module systems & woes
• uRequire primer
• A modules & dependencies builder
• Build config usage
uRequire.org
12. uRequire primer
• Convert from any format to any other:
– from AMD and CommonJS (.js, .coffee, .iced, .coco, .ls)
– to AMD, CommonJS, UMD, Combined for nodejs-Web/AMD-
Web/Script
– Control conversion features (runtimeInfo, globalWindow etc)
• Forget the woes or Module formats incompatibilities
– Resolve paths, fill missing deps from [], inject ‘require’ etc
• Eliminate boilerplate & write modular Javascript code
once, run everywhere : Web/Script, Web/AMD, nodejs
• A Universal Module Format with the power, goodies &
standards from all.
• Convert to a single combined.js, that runs everywhere &
is super optimized uRequire.org
13. • Why Modularity
• JavaScript module systems & woes
• uRequire primer
• A modules & dependencies builder
• Build config usage
uRequire.org
14. A Modules & Dependencies aware builder.
• Exporting modules to global (like window.$)
with no boilerplate.
• Want noConflict(), baked in? Its a simple
declaration away.
• The same in a config:
• Export to bundle:
uRequire.org
// file `uberscore.js` - export it to root (`window`) as `_B`
({ urequire: { rootExports: '_B', noConflict: true }});
module.exports = {...}
dependencies: { exports: { root: { 'uberscore': '_B' }}}
dependencies: { exports: { bundle: { ‘lodash': '_' }}}
15. Manipulate module dependencies
• Replace deps with mocks or alternative versions:
• With a ResourceConverter callback:
uRequire.org
// underscore is dead, long live _
dependencies: { replace: { lodash: 'underscore'}}
function(m){
m.replaceDeps('models/PersonModel','mock/models/PersonModelMock');
}
16. Manipulate Module Code
Inject, replace or delete code fragments or AST nodes:
• Delete matching code of code skeleton
• Traverse matching nodes, replace or delete them
• Inject code before (or after) each module's body:
uRequire.org
function(m){ m.replaceCode('if (debug){}') }
function(m){ m.replaceCode('console.log()', function(nodeAST){}) }
function(m) { m.beforeBody = 'var VERSION = ‘1.0’;' }
17. Manipulate Module Code
Inject common or merged statements:
• beforeBody can be calculated per module
• Before main body at each module:
• Like above, but merge code on 'combined' template:
uRequire.org
bundle: commonCode: 'var expect = chai.expect;'
function(m) {
m.mergedCode = '"var p1 = myModule.p1, p2 = myModule.p2;"'
}
function(m) {
m.beforeBody = "var l = new _B.Logger('" + m.dstFilename + "');";
}
18. • Why Modularity
• JavaScript module systems & woes
• uRequire primer
• A modules & dependencies builder
• Build config usage
uRequire.org
19. uRequire config
uRequire.org
uberscore:
path: 'source'
dstPath: 'build'
filez: ['**/*', (f)-> f isnt 'badfile']
copy: [/./]
runtimeInfo: ['!**/*', 'Logger']
dependencies: exports:
bundle: 'lodash': '_'
root: 'uberscore': '_B'
resources: [
['+inject:VERSION', ['uberscore.js'],
(m)-> m.beforeBody = "var VERSION ='0.0.15';"]
]
template: banner: "// uBerscore v0.0.15"
read files from ‘source’
save to ‘build’
filter some filez
copy all other files
affect template selectively
inject ‘lodash’ in each module
export ‘uberscore’ as
`window._B` with noConflict()
inject ‘VERSION = ..’ before body
banner after template/optimize
Can be gruntjs, .coffee / .js nodejs module, .json, .yml & more
20. Deriving a config
uRequire.org
min:
derive: ['uberscore']
filez: ['!', /RegExpSpecs/]
template: 'combined'
dstPath: 'build/uberscore-min.js'
optimize: true
inherit deeply & modify
filter more filez
change template
optimize through Uglify2.
Can also pass an options {}
• Deeply inherit / extend all properties
change destination
filez: ['**/*', (f)-> f isnt 'badfile', '!', /RegExpSpecs/]
• Either overwriting or appending props: