Permalink
Browse files

init

  • Loading branch information...
0 parents commit 179509e47962a7f1be31032f75ea5d09f565d475 @defunctzombie committed Apr 11, 2012
@@ -0,0 +1,2 @@
+node_modules
+
@@ -0,0 +1,3 @@
+language: node_js
+node_js:
+ - 0.6
@@ -0,0 +1,3 @@
+jsbundler is an automatic javascript file bundler for files written using the node.js require style for dependencies.
+
+Although a few other similar projects exist in this space(browserify, brequest, jsbundle), the jsbundler codebase and client side code is very minimal. It leverages the builtin node module loader to track down your dependencies and generate the output.
@@ -0,0 +1,40 @@
+
+function require(name) {
+ // is the name aliased?
+ name = require.aliases[name] || name;
+
+ var cached = require.cached[name];
+ if (cached) {
+ return cached.exports;
+ }
+
+ var func = require.wrappers[name];
+ if (!func) {
+ throw new Error('unable to resolve module: ' + name);
+ }
+
+ var module = {
+ exports: {}
+ };
+
+ if (!require.main) {
+ require.main = module;
+ }
+
+ func(module, module.exports, require);
+ require.cached[name] = module;
+ return module.exports;
+}
+
+require.register = function(path, fn) {
+ require.wrappers[path] = fn;
+};
+
+require.alias = function(path, alias) {
+ require.aliases[path] = alias;
+}
+
+require.aliases = {};
+require.wrappers = {};
+require.cached = {};
+
@@ -0,0 +1,2 @@
+
+module.exports.bundle = require('./lib/bundler');
@@ -0,0 +1,23 @@
+
+var vm = require('vm');
+var fs = require('fs');
+
+var loader = fs.readFileSync(__dirname + '/module.js');
+var script = vm.createScript(loader)
+
+module.exports = function(filename) {
+
+ var sandbox = {
+ out: '',
+ filename: filename,
+ require: require,
+ console: console,
+ module: {
+ exports: {}
+ }
+ };
+ script.runInNewContext(sandbox);
+
+ return sandbox.out;
+}
+
@@ -0,0 +1,87 @@
+
+/// INPUTS
+/// filename: the fully qualified filename of the entry point
+/// out: the output stream where to write the result js
+
+// builtin
+var module = require('module');
+
+// 3rd party
+var detective = require('detective');
+
+// map of short request name to full filename
+var req_name;
+
+// list of all the filenames that we loaded
+// we need to uncache them after loading
+var required = [];
+
+// the first short name for a module is the canonical name
+var aliases = {};
+
+var orig_compile = module.Module.prototype._compile
+module.Module.prototype._compile = function(content, filename) {
+ var self = this;
+
+ // track loaded files to uncache them
+ required.push(filename);
+
+ // entry point
+ if (!req_name) {
+ req_name = '__entry__';
+ }
+
+ // get the requires from the source
+ var requires = detective(content);
+
+ out += 'require.register(\'' + req_name + '\', ';
+ out += 'function(module, exports, require, __filename, __dirname) {\n';
+ out += content;
+ out += '});\n\n';
+
+ // create a new source file with just the list of requires
+ var new_content = '';
+ requires.forEach(function(req) {
+ new_content += 'require(\'' + req + '\');'
+ });
+
+ return orig_compile.call(self, new_content, filename);
+}
+
+var orig_require = module.Module.prototype.require;
+module.Module.prototype.require = function(path) {
+ var self = this;
+
+ // get the real full path of the file
+ var full_path = module._resolveFilename(path, self);
+
+ // the first alias for a path is the canonical alias
+ var alias = aliases[full_path];
+ if (!alias) {
+ aliases[full_path] = path;
+ }
+ else if (path !== alias) {
+ // map the new short name to an already loaded name
+ out += 'require.alias(\'' + path + '\', \'' + alias + '\');\n';
+ }
+
+ // capture the short require name
+ // this is used in the _compile method above to register the module
+ req_name = path;
+ return orig_require.call(self, path);
+}
+
+new module.Module(filename, null).load(filename);
+
+// put back the prototypes
+module.Module.prototype.require = orig_require;
+module.Module.prototype._compile = orig_compile;
+
+// uncache anything we loaded otherwise this seems to persist
+required.forEach(function(name) {
+ delete require.cache[name];
+});
+
+// trigger the entry point module
+out += 'require(\'__entry__\');';
+
@@ -0,0 +1,21 @@
+{
+ "author": "Roman Shtylman <shtylman@gmail.com>",
+ "name": "jsbundler",
+ "description": "automatic bundling of nodejs modules for the browser",
+ "version": "0.0.1",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/shtylman/node-jsbundler.git"
+ },
+ "main": "index.js",
+ "scripts": {
+ "test": "node test"
+ },
+ "dependencies": {
+ "detective": "0.1.0"
+ },
+ "devDependencies": {
+ "mocha": ">1.0.0"
+ },
+ "optionalDependencies": {}
+}
@@ -0,0 +1,36 @@
+
+// builtin
+var assert = require('assert');
+var fs = require('fs');
+
+// local
+var bundler = require('../');
+
+var gen_gold = process.env.BUNDLER_GEN_GOLD;
+
+function add_test(filename) {
+ test(filename, function() {
+ var actual = bundler.bundle(__dirname + '/fixtures/' + filename);
+
+ var gold_filename = __dirname + '/golden/' + filename;
+ if (gen_gold) {
+ fs.writeFileSync(gold_filename, actual);
+ }
+
+ var expected = fs.readFileSync(gold_filename, 'utf8');
+ assert.equal(actual, expected);
+ });
+}
+
+fs.readdirSync(__dirname + '/fixtures').forEach(function(fixture) {
+ // skip directories and vim swap files
+ if (fixture.indexOf('.js') < 0 || fixture.indexOf('.swp') >= 0) {
+ return;
+ }
+
+ add_test(fixture);
+});
+
+// checks for loading one level up
+add_test('modules/up.js');
+
@@ -0,0 +1,7 @@
+/// check that noop only gets loaded once
+/// single will require noop again
+
+var noop = require('./noop');
+var single = require('./single');
+
+module.exports = function() { };
@@ -0,0 +1,6 @@
+/// even requires in if statements should be found
+
+if (hi) {
+ require('./noop');
+}
+
@@ -0,0 +1,3 @@
+/// make sure loading from inside a directory works
+
+var sample = require('./modules/sample');
@@ -0,0 +1,9 @@
+/// make sure that require.main protects undefined things
+
+if (require.main === module) {
+ // this is invalid on purpose
+ // it will not be run for initial interpretation
+ // syntax checking will still occur
+ undefined_symbol();
+}
+
@@ -0,0 +1,4 @@
+
+module.exports = function() {
+}
+
@@ -0,0 +1,5 @@
+/// check loading one level up
+
+/// noop is loaded by single and should appear only once in output
+var noop = require('../noop');
+var single = require('../single');
@@ -0,0 +1 @@
+/// no content
@@ -0,0 +1,3 @@
+/// single require
+
+var noop = require('./noop');
@@ -0,0 +1,21 @@
+require.register('__entry__', function(module, exports, require, __filename, __dirname) {
+/// check that noop only gets loaded once
+/// single will require noop again
+
+var noop = require('./noop');
+var single = require('./single');
+
+module.exports = function() { };
+});
+
+require.register('./noop', function(module, exports, require, __filename, __dirname) {
+/// no content
+});
+
+require.register('./single', function(module, exports, require, __filename, __dirname) {
+/// single require
+
+var noop = require('./noop');
+});
+
+require('__entry__');
@@ -0,0 +1,14 @@
+require.register('__entry__', function(module, exports, require, __filename, __dirname) {
+/// even requires in if statements should be found
+
+if (hi) {
+ require('./noop');
+}
+
+});
+
+require.register('./noop', function(module, exports, require, __filename, __dirname) {
+/// no content
+});
+
+require('__entry__');
@@ -0,0 +1,14 @@
+require.register('__entry__', function(module, exports, require, __filename, __dirname) {
+/// make sure loading from inside a directory works
+
+var sample = require('./modules/sample');
+});
+
+require.register('./modules/sample', function(module, exports, require, __filename, __dirname) {
+
+module.exports = function() {
+}
+
+});
+
+require('__entry__');
@@ -0,0 +1,13 @@
+require.register('__entry__', function(module, exports, require, __filename, __dirname) {
+/// make sure that require.main protects undefined things
+
+if (require.main === module) {
+ // this is invalid on purpose
+ // it will not be run for initial interpretation
+ // syntax checking will still occur
+ undefined_symbol();
+}
+
+});
+
+require('__entry__');
@@ -0,0 +1,20 @@
+require.register('__entry__', function(module, exports, require, __filename, __dirname) {
+/// check loading one level up
+
+/// noop is loaded by single and should appear only once in output
+var noop = require('../noop');
+var single = require('../single');
+});
+
+require.register('../noop', function(module, exports, require, __filename, __dirname) {
+/// no content
+});
+
+require.register('../single', function(module, exports, require, __filename, __dirname) {
+/// single require
+
+var noop = require('./noop');
+});
+
+require.alias('./noop', '../noop');
+require('__entry__');
@@ -0,0 +1,5 @@
+require.register('__entry__', function(module, exports, require, __filename, __dirname) {
+/// no content
+});
+
+require('__entry__');
@@ -0,0 +1,11 @@
+require.register('__entry__', function(module, exports, require, __filename, __dirname) {
+/// single require
+
+var noop = require('./noop');
+});
+
+require.register('./noop', function(module, exports, require, __filename, __dirname) {
+/// no content
+});
+
+require('__entry__');
@@ -0,0 +1,9 @@
+var Mocha = require('mocha');
+
+var mocha = new Mocha;
+mocha.reporter('list').ui('qunit');
+
+mocha.addFile('test/basic.js');
+
+mocha.run();
+

0 comments on commit 179509e

Please sign in to comment.