Rogerwang's node-webkit (https://github.com/rogerwang/node-webkit) lets you create native desktop apps using HTML, CSS and JavaScript, but also gives you access to all node.js modules, directly from the DOM. When using require.js, this often leads to problems, due to the fact that both require.js and node.js have a global require function. This can be solved though by renaming node's require function to for instance nodereq before including require.js. However, if you want to get access to a node.js module from within an AMD module, you still have to use:
define(function(require) {
var fs = global.require('fs'),
$ = require('jquery'),
Backbone = require('backbone');
});
Therefore I modified require.js to allow for
define(function(require) {
var fs = require('fs'),
$ = require('jquery'),
Backbone = require('backbone');
});
etc.
Even
define(function(require) {
var gui = require('nw.gui');
});
is possible. The magic is done by adding a check for whether the environment is node-webkit. If so, for every module it is checked whether it exists as node.js module. If so, the module is loaded. If not, require.js will try to load the module as a simple <script> tag. Allmost all of the changes are done within the function req.load.
// The function in the if statement checks whether the requested
// module is a native node.js module (i.e. in a folder node_modules)
// This is done by trying to resolve the module using node-webkit's
// require function. If the module is not a native node.js module, then
// an error is thrown which is caught to return false.
if ((function() {
try {
nodereq.resolve(moduleName);
return true;
}
catch (e) {
return false;
}
})()) {
// Push in the defQueue with no dependencies, and as callback
// function an anonymous function is specified, which simply
// returns the module, required by nodejs's require function.
// Then, call completeLoad to complete the load
context.defQueue.push([moduleName, [], function() {
return nwreq(moduleName);
}]);
context.completeLoad(moduleName);
}
else {
// Do the usual requirejs stuff
}
Note that using require's optimizer will fail since it won't find a dependency called 'fs' for instance. This can be solved by specifying the native node.js modules as modules the optimizer should exclude. Fore more info, see: https://github.com/jrburke/r.js/blob/master/build/example.build.js
On plain nodewebkit, it is possible to call
var util = require('./lib/util');
if you have a local folder called "lib" with some internal modules in it. Using
define(function(require) {
var util = require('./lib/util');
});
will not work however, only native node modules or modules from the node_modules folder can be loaded, due to the fact that requirejs normalizes the path first before passing it to the req.load() function. As a consequence the base url etc. will be added. To be able to require internal modules, a plugin called "lcl" was built in. This allows for
define(function(require) {
var util = require('lcl!lib/util');
});
You may specify a root directory in the requirejs config object, such as
requirejs.config({
"config": {
"lcl": {
"root": "./lib"
}
}
});
which allows for
define(function(require) {
var util = require('lcl!util');
});
Just download nw-require.js
or install via bower using
bower install nw-require
Some plugins (for instance the require-handlebars-plugin) use the global require()
function instead of requirejs()
which results in unexpected behavior, such as AssertionErrors being thrown because node.js complains that the path must be a string (and not an array, as in the requirejs syntax). Therefore, the lines
// Some plugins, such as the require-handlebars-plugin use require()
// insteadof requirejs, which will result in name conflicts and also
// unexpected behavior, such as AssertionErrors and so on. Therefore,
// simulate the requirejs behavior of the require function when the
// requirejs syntax is used (i.e. require(['module'], function() {}))
// IMPORTANT NOTE: Below global.require() is used, but this is in fact
// window.require, because requirejs passes "this" into the closure, which
// is then renamed to global, overriding node.js's "global" object!
global.require = (function(nodewebkit, requirejs) {
return function() {
if (isArray(arguments[0])) {
return requirejs.apply(null, arguments);
}
else {
return nodewebkit.apply(null, arguments);
}
};
})(nwreq, req);
for (var i in req) {
if (!global.require[i]) {
global.require[i] = req[i];
}
}
were added. This is - again - an override of the require()
function, which detects what syntax is used, and calls the appropriate require function.
The version of requirejs that was used, is version 2.1.14. If you specifically need other versions of requirejs, I suggest you try to modify it yourself. The only major changes are applied in the req.load function. Minor changes are
(function (global, nodereq, nwreq) {
/*
* ALL
* OTHER
* CODE
*/
// Some plugins, such as the require-handlebars-plugin use require()
// instead of requirejs, which will result in name conflicts and also
// unexpected behavior, such as AssertionErrors and so on. Therefore,
// simulate the requirejs behavior of the require function when the
// requirejs syntax is used (i.e. require(['module'], function() {}))
// IMPORTANT NOTE: Below global.require() is used, but this is in fact
// window.require, because requirejs passes "this" into the closure, which
// is then renamed to global, overriding node.js's "global" object!
global.require = (function(nodewebkit, requirejs) {
return function() {
if (isArray(arguments[0])) {
return requirejs.apply(null, arguments);
}
else {
return nodewebkit.apply(null, arguments);
}
};
})(nwreq, req);
for (var i in req) {
if (!global.require[i]) {
global.require[i] = req[i];
}
}
// If you have a "./lib" folder and thus not in the node_modules folder,
// which need not to be run in the browser environment of node-webkit, you
// can't simply use
//
// define(function(require) {
// var util = require('./lib').util;
// });
//
// This is because require.js normalizes './lib' firstly to 'lib' before
// trying to resolve it, resulting in a module which was not found, since
// "lib" is neither a native node module, neither in the node_modules
// folder. Therefore, a special plugin is added to require.js. If you need // to load files from a local folder, use
// define(function(require) {
// var util = require('lcl!lib').util;
// });
// It is even possible to specify some configuration options to the lcl!
// plugin so that a root folder can be specified.
define("lcl", ["module"], function(module) {
var config = (module.config && module.config()) || {};
config.root = config.root || './';
var lcl = {
load: function(name, req, done) {
// If we're optimizing, do nothing
if (config && config.isBuild) {
done();
}
// Try to load, but throw errors if not found
try {
var path = config.root + name,
module = nwreq(path);
done(module);
}
catch (e) {
done.error(e);
}
}
};
return lcl;
});
}(this, typeof global === 'undefined' ? void 0 : global.require, require));
So you should be able to do this yourself.