node_modules/browserify/index.js in sprockets-browserify-0.1.2 vs node_modules/browserify/index.js in sprockets-browserify-0.2.0
- old
+ new
@@ -1,202 +1,365 @@
+var crypto = require('crypto');
+var through = require('through');
+var duplexer = require('duplexer');
+var concatStream = require('concat-stream');
+var checkSyntax = require('syntax-error');
+
+var mdeps = require('module-deps');
+var browserPack = require('browser-pack');
+var browserResolve = require('browser-resolve');
+var insertGlobals = require('insert-module-globals');
+var umd = require('umd');
+
var path = require('path');
-var coffee = require('coffee-script');
+var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;
-var wrap = require('./lib/wrap');
-var watch = require('./lib/watch');
+module.exports = function (opts) {
+ if (opts === undefined) opts = {};
+ if (typeof opts === 'string') opts = { entries: [ opts ] };
+ if (Array.isArray(opts)) opts = { entries: opts };
+
+ var b = new Browserify(opts);
+ [].concat(opts.entries).filter(Boolean).forEach(b.add.bind(b));
+ return b;
+};
-function idFromPath (path) {
- return path.replace(/\\/g, '/');
+function hash(what) {
+ return crypto.createHash('md5').update(what).digest('base64').slice(0, 6);
}
-function isAbsolute (pathOrId) {
- return path.normalize(pathOrId) === path.normalize(path.resolve(pathOrId));
-}
+inherits(Browserify, EventEmitter);
-function needsNodeModulesPrepended (id) {
- return !/^[.\/]/.test(id) && !isAbsolute(id);
+function Browserify (opts) {
+ var self = this;
+
+ self.files = [];
+ self.exports = {};
+ self._pending = 0;
+ self._entries = [];
+ self._ignore = {};
+ self._external = {};
+ self._expose = {};
+ self._mapped = {};
+ self._transforms = [];
+ self._noParse =[];
+
+ var noParse = [].concat(opts.noParse).filter(Boolean);
+ var cwd = process.cwd();
+ var top = { id: cwd, filename: cwd + '/_fake.js', paths: [] };
+ noParse.forEach(function (file) {
+ self._noParse.push(file, path.resolve(file));
+ self._pending ++;
+ self._resolve(file, top, function (err, r) {
+ if (r) self._noParse.push(r);
+ if (--self._pending === 0) self.emit('_ready');
+ });
+ });
}
-var exports = module.exports = function (entryFile, opts) {
- if (!opts) opts = {};
+Browserify.prototype.add = function (file) {
+ this.require(file, { entry: true });
+ return this;
+};
+
+Browserify.prototype.require = function (id, opts) {
+ var self = this;
+ if (opts === undefined) opts = { expose: id };
- if (Array.isArray(entryFile)) {
- if (Array.isArray(opts.entry)) {
- opts.entry.unshift.apply(opts.entry, entryFile);
+ self._pending ++;
+
+ var basedir = opts.basedir || process.cwd();
+ var fromfile = basedir + '/_fake.js';
+
+ var params = { filename: fromfile, packageFilter: packageFilter };
+ browserResolve(id, params, function (err, file) {
+ if (err) return self.emit('error', err);
+ if (!file) return self.emit('error', new Error(
+ 'module ' + JSON.stringify(id) + ' not found in require()'
+ ));
+
+ if (opts.expose) {
+ self.exports[file] = hash(file);
+
+ if (typeof opts.expose === 'string') {
+ self._expose[file] = opts.expose;
+ self._mapped[opts.expose] = file;
+ }
}
- else if (opts.entry) {
- opts.entry = entryFile.concat(opts.entry);
+
+ if (opts.external) {
+ self._external[file] = true;
}
else {
- opts.entry = entryFile;
+ self.files.push(file);
}
+
+ if (opts.entry) self._entries.push(file);
+
+ if (--self._pending === 0) self.emit('_ready');
+ });
+
+ return self;
+};
+
+// DEPRECATED
+Browserify.prototype.expose = function (name, file) {
+ this.exports[file] = name;
+ this.files.push(file);
+};
+
+Browserify.prototype.external = function (id, opts) {
+ opts = opts || {};
+ opts.external = true;
+ return this.require(id, opts);
+};
+
+Browserify.prototype.ignore = function (file) {
+ this._ignore[file] = true;
+ return this;
+};
+
+Browserify.prototype.bundle = function (opts, cb) {
+ var self = this;
+ if (typeof opts === 'function') {
+ cb = opts;
+ opts = {};
}
- else if (typeof entryFile === 'object') {
- opts = entryFile;
- }
- else if (typeof entryFile === 'string') {
- if (Array.isArray(opts.entry)) {
- opts.entry.unshift(entryFile);
- }
- else if (opts.entry) {
- opts.entry = [ opts.entry, entryFile ];
- }
- else {
- opts.entry = entryFile;
- }
- }
+ if (!opts) opts = {};
+ if (opts.insertGlobals === undefined) opts.insertGlobals = false;
+ if (opts.detectGlobals === undefined) opts.detectGlobals = true;
+ if (opts.ignoreMissing === undefined) opts.ignoreMissing = false;
+ if (opts.standalone === undefined) opts.standalone = false;
- var opts_ = {
- cache : opts.cache,
- debug : opts.debug,
- exports : opts.exports,
- };
- var w = wrap(opts_);
- w.register('.coffee', function (body, file) {
- try {
- var res = coffee.compile(body, { filename : file });
- }
- catch (err) {
- w.emit('syntaxError', err);
- }
- return res;
- });
- w.register('.json', function (body, file) {
- return 'module.exports = ' + body + ';\n';
- });
+ opts.resolve = self._resolve.bind(self);
+ opts.transform = self._transforms;
+ opts.noParse = self._noParse;
+ opts.transformKey = [ 'browserify', 'transform' ];
- var listening = false;
- w._cache = null;
-
- var self = function (req, res, next) {
- if (!listening && req.connection && req.connection.server) {
- req.connection.server.on('close', function () {
- self.end();
- });
- }
- listening = true;
-
- if (req.url.split('?')[0] === (opts.mount || '/browserify.js')) {
- if (!w._cache) self.bundle();
- res.statusCode = 200;
- res.setHeader('last-modified', self.modified.toString());
- res.setHeader('content-type', 'text/javascript');
- res.end(w._cache);
- }
- else next()
+ var parentFilter = opts.packageFilter;
+ opts.packageFilter = function (pkg) {
+ if (parentFilter) pkg = parentFilter(pkg);
+ return packageFilter(pkg);
};
- if (opts.watch) watch(w, opts.watch);
+ if (self._pending) {
+ var tr = through();
+ self.on('_ready', function () {
+ var b = self.bundle(opts, cb);
+ if (!cb) b.on('error', tr.emit.bind(tr, 'error'));
+ b.pipe(tr);
+ });
+ return tr;
+ }
- if (opts.filter) {
- w.register('post', function (body) {
- return opts.filter(body);
+ if (opts.standalone && self._entries.length !== 1) {
+ process.nextTick(function () {
+ p.emit('error', 'standalone only works with a single entry point');
});
}
- w.ignore(opts.ignore || []);
+ var d = (opts.deps || self.deps.bind(self))(opts);
+ var g = opts.detectGlobals || opts.insertGlobals
+ ? insertGlobals(self.files, {
+ resolve: self._resolve.bind(self),
+ always: opts.insertGlobals
+ })
+ : through()
+ ;
+ var p = self.pack(opts.debug, opts.standalone);
+ if (cb) {
+ p.on('error', cb);
+ p.pipe(concatStream(cb));
+ }
- if (opts.require) {
- if (Array.isArray(opts.require)) {
- opts.require.forEach(function (r) {
- r = idFromPath(r);
-
- var params = {};
- if (needsNodeModulesPrepended(r)) {
- params.target = '/node_modules/' + r + '/index.js';
- }
- w.require(r, params);
- });
+ d.on('error', p.emit.bind(p, 'error'));
+ g.on('error', p.emit.bind(p, 'error'));
+ d.pipe(through(function (dep) {
+ if (self._noParse.indexOf(dep.id) >= 0
+ || (opts.cache && opts.cache[dep.id])) {
+ p.write(dep);
}
- else if (typeof opts.require === 'object') {
- Object.keys(opts.require).forEach(function (key) {
- opts.require[key] = idFromPath(opts.require[key]);
+ else this.queue(dep)
+ })).pipe(g).pipe(p);
+
+ return p;
+};
- var params = {};
- if (needsNodeModulesPrepended(opts.require[key])) {
- params.target = '/node_modules/'
- + opts.require[key] + '/index.js'
- ;
- }
- w.require(opts.require[key], params);
- w.alias(key, opts.require[key]);
- });
- }
- else {
- opts.require = idFromPath(opts.require);
-
- var params = {};
- if (needsNodeModulesPrepended(opts.require)) {
- params.target = '/node_modules/'
- + opts.require + '/index.js'
- ;
- }
- w.require(opts.require, params);
- }
+Browserify.prototype.transform = function (t) {
+ if (typeof t === 'string' && /^\./.test(t)) {
+ t = path.resolve(t);
}
+ this._transforms.push(t);
+ return this;
+};
- if (opts.entry) {
- if (Array.isArray(opts.entry)) {
- opts.entry.forEach(function (e) {
- w.addEntry(e);
+Browserify.prototype.deps = function (opts) {
+ var self = this;
+ if (self._pending) {
+ var tr = through();
+ self.on('_ready', function () {
+ self.deps(opts).pipe(tr);
+ });
+ return tr;
+ }
+
+ var d = mdeps(self.files, opts);
+
+ var tr = d.pipe(through(write));
+ d.on('error', tr.emit.bind(tr, 'error'));
+ return tr;
+
+ function write (row) {
+ self.emit('dep', row);
+
+ if (row.id === emptyModulePath) {
+ row.source = '';
+ }
+
+ if (self._expose[row.id]) {
+ this.queue({
+ exposed: self._expose[row.id],
+ deps: {},
+ source: 'module.exports=require(\'' + hash(row.id) + '\');'
});
}
- else {
- w.addEntry(opts.entry);
+
+ if (self.exports[row.id]) row.exposed = self.exports[row.id];
+
+ // skip adding this file if it is external
+ if (self._external[row.id]) {
+ return;
}
+
+ if (/\.json$/.test(row.id)) {
+ row.source = 'module.exports=' + row.source;
+ }
+
+ var ix = self._entries.indexOf(row.id);
+ row.entry = ix >= 0;
+ if (ix >= 0) row.order = ix;
+ this.queue(row);
}
+};
+
+Browserify.prototype.pack = function (debug, standalone) {
+ var self = this;
+ var packer = browserPack({ raw: true });
+ var ids = {};
+ var idIndex = 1;
- Object.keys(w).forEach(function (key) {
- Object.defineProperty(self, key, {
- set : function (value) { w[key] = value },
- get : function () { return w[key] }
- });
- });
+ var mainModule;
- Object.keys(Object.getPrototypeOf(w)).forEach(function (key) {
- self[key] = function () {
- var s = w[key].apply(self, arguments)
- if (s === self) { w._cache = null }
- return s;
- };
- });
-
- Object.keys(EventEmitter.prototype).forEach(function (key) {
- if (typeof w[key] === 'function' && w[key].bind) {
- self[key] = w[key].bind(w);
+ var input = through(function (row_) {
+ var row = copy(row_);
+ var ix;
+
+ if (debug) {
+ row.sourceRoot = 'file://localhost';
+ row.sourceFile = row.id;
}
+
+ if (row.exposed) {
+ ix = row.exposed;
+ }
else {
- self[key] = w[key];
+ ix = ids[row.id] !== undefined ? ids[row.id] : idIndex++;
}
+ if (ids[row.id] === undefined) ids[row.id] = ix;
+
+ if (/^#!/.test(row.source)) row.source = '//' + row.source;
+ var err = checkSyntax(row.source, row.id);
+ if (err) return this.emit('error', err);
+
+ row.id = ix;
+ if (row.entry) mainModule = mainModule || ix;
+ row.deps = Object.keys(row.deps).reduce(function (acc, key) {
+ var file = row.deps[key];
+
+ // reference external and exposed files directly by hash
+ if (self._external[file] || self.exports[file]) {
+ acc[key] = hash(file);
+ return acc;
+ }
+
+ if (ids[file] === undefined) ids[file] = idIndex++;
+ acc[key] = ids[file];
+ return acc;
+ }, {});
+
+ this.queue(row);
});
- var firstBundle = true;
- self.modified = new Date;
+ var first = true;
+ var hasExports = Object.keys(self.exports).length;
+ var output = through(write, end);
- self.bundle = function () {
- if (w._cache) return w._cache;
-
- var src = w.bundle.apply(w, arguments);
- self.ok = Object.keys(w.errors).length === 0;
-
- if (!firstBundle) {
- self.modified = new Date;
+ function writePrelude () {
+ if (!first) return;
+ if (standalone) {
+ return output.queue(umd.prelude(standalone) + 'return ');
}
- firstBundle = false;
-
- w._cache = src;
- return src;
- };
+ if (!hasExports) return output.queue(';');
+ output.queue('require=');
+ }
- self.end = function () {
- Object.keys(w.watches || {}).forEach(function (file) {
- w.watches[file].close();
- });
- };
+ input.pipe(packer);
+ packer.pipe(output);
+ return duplexer(input, output);
- return self;
+ function write (buf) {
+ if (first) writePrelude();
+ first = false;
+ this.queue(buf);
+ }
+
+ function end () {
+ if (first) writePrelude();
+ if (standalone) {
+ output.queue('(' + mainModule + ')' + umd.postlude(standalone));
+ }
+ this.queue('\n;');
+ this.queue(null);
+ }
};
-exports.bundle = function (opts) {
- return exports(opts).bundle();
+var packageFilter = function (info) {
+ if (typeof info.browserify === 'string' && !info.browser) {
+ info.browser = info.browserify;
+ delete info.browserify;
+ }
+ return info;
};
+
+var emptyModulePath = require.resolve('./_empty');
+Browserify.prototype._resolve = function (id, parent, cb) {
+ if (this._ignore[id]) return cb(null, emptyModulePath);
+ var self = this;
+ var result = function (file, x) {
+ if (self._pending === 0) {
+ self.emit('file', file, id, parent);
+ }
+ cb(null, file, x);
+ };
+ if (self._mapped[id]) return result(self._mapped[id]);
+
+ return browserResolve(id, parent, function(err, file) {
+ if (err) return cb(err);
+ if (!file) return cb(new Error('module '
+ + JSON.stringify(id) + ' not found from '
+ + JSON.stringify(parent.filename)
+ ));
+
+ if (self._ignore[file]) return cb(null, emptyModulePath);
+ if (self._external[file]) return result(file, true);
+
+ result(file);
+ });
+};
+
+function copy (obj) {
+ return Object.keys(obj).reduce(function (acc, key) {
+ acc[key] = obj[key];
+ return acc;
+ }, {});
+}