index.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. var path = require('path');
  2. var mdeps = require('module-deps');
  3. var depsSort = require('deps-sort');
  4. var bpack = require('browser-pack');
  5. var insertGlobals = require('insert-module-globals');
  6. var syntaxError = require('syntax-error');
  7. var builtins = require('./lib/builtins.js');
  8. var splicer = require('labeled-stream-splicer');
  9. var through = require('through2');
  10. var concat = require('concat-stream');
  11. var inherits = require('inherits');
  12. var EventEmitter = require('events').EventEmitter;
  13. var xtend = require('xtend');
  14. var isArray = Array.isArray;
  15. var defined = require('defined');
  16. var has = require('has');
  17. var sanitize = require('htmlescape').sanitize;
  18. var shasum = require('shasum');
  19. var bresolve = require('browser-resolve');
  20. var resolve = require('resolve');
  21. var readonly = require('read-only-stream');
  22. module.exports = Browserify;
  23. inherits(Browserify, EventEmitter);
  24. var fs = require('fs');
  25. var path = require('path');
  26. var cachedPathRelative = require('cached-path-relative');
  27. var paths = {
  28. empty: path.join(__dirname, 'lib/_empty.js')
  29. };
  30. function Browserify (files, opts) {
  31. var self = this;
  32. if (!(this instanceof Browserify)) return new Browserify(files, opts);
  33. if (!opts) opts = {};
  34. if (typeof files === 'string' || isArray(files) || isStream(files)) {
  35. opts = xtend(opts, { entries: [].concat(opts.entries || [], files) });
  36. }
  37. else opts = xtend(files, opts);
  38. if (opts.node) {
  39. opts.bare = true;
  40. opts.browserField = false;
  41. }
  42. if (opts.bare) {
  43. opts.builtins = false;
  44. opts.commondir = false;
  45. if (opts.insertGlobalVars === undefined) {
  46. opts.insertGlobalVars = {}
  47. Object.keys(insertGlobals.vars).forEach(function (name) {
  48. if (name !== '__dirname' && name !== '__filename') {
  49. opts.insertGlobalVars[name] = undefined;
  50. }
  51. })
  52. }
  53. }
  54. self._options = opts;
  55. if (opts.noparse) opts.noParse = opts.noparse;
  56. if (opts.basedir !== undefined && typeof opts.basedir !== 'string') {
  57. throw new Error('opts.basedir must be either undefined or a string.');
  58. }
  59. opts.dedupe = opts.dedupe === false ? false : true;
  60. self._external = [];
  61. self._exclude = [];
  62. self._ignore = [];
  63. self._expose = {};
  64. self._hashes = {};
  65. self._pending = 0;
  66. self._transformOrder = 0;
  67. self._transformPending = 0;
  68. self._transforms = [];
  69. self._entryOrder = 0;
  70. self._ticked = false;
  71. self._bresolve = opts.browserField === false
  72. ? function (id, opts, cb) {
  73. if (!opts.basedir) opts.basedir = path.dirname(opts.filename)
  74. resolve(id, opts, cb)
  75. }
  76. : bresolve
  77. ;
  78. self._syntaxCache = {};
  79. var ignoreTransform = [].concat(opts.ignoreTransform).filter(Boolean);
  80. self._filterTransform = function (tr) {
  81. if (isArray(tr)) {
  82. return ignoreTransform.indexOf(tr[0]) === -1;
  83. }
  84. return ignoreTransform.indexOf(tr) === -1;
  85. };
  86. self.pipeline = self._createPipeline(opts);
  87. [].concat(opts.transform).filter(Boolean).filter(self._filterTransform)
  88. .forEach(function (tr) {
  89. self.transform(tr);
  90. });
  91. [].concat(opts.entries).filter(Boolean).forEach(function (file) {
  92. self.add(file, { basedir: opts.basedir });
  93. });
  94. [].concat(opts.require).filter(Boolean).forEach(function (file) {
  95. self.require(file, { basedir: opts.basedir });
  96. });
  97. [].concat(opts.plugin).filter(Boolean).forEach(function (p) {
  98. self.plugin(p, { basedir: opts.basedir });
  99. });
  100. }
  101. Browserify.prototype.require = function (file, opts) {
  102. var self = this;
  103. if (isArray(file)) {
  104. file.forEach(function (x) {
  105. if (typeof x === 'object') {
  106. self.require(x.file, xtend(opts, x));
  107. }
  108. else self.require(x, opts);
  109. });
  110. return this;
  111. }
  112. if (!opts) opts = {};
  113. var basedir = defined(opts.basedir, self._options.basedir, process.cwd());
  114. var expose = opts.expose;
  115. if (file === expose && /^[\.]/.test(expose)) {
  116. expose = '/' + relativePath(basedir, expose);
  117. }
  118. if (expose === undefined && this._options.exposeAll) {
  119. expose = true;
  120. }
  121. if (expose === true) {
  122. expose = '/' + relativePath(basedir, file);
  123. }
  124. if (isStream(file)) {
  125. self._pending ++;
  126. var order = self._entryOrder ++;
  127. file.pipe(concat(function (buf) {
  128. var filename = opts.file || file.file || path.join(
  129. basedir,
  130. '_stream_' + order + '.js'
  131. );
  132. var id = file.id || expose || filename;
  133. if (expose || opts.entry === false) {
  134. self._expose[id] = filename;
  135. }
  136. if (!opts.entry && self._options.exports === undefined) {
  137. self._bpack.hasExports = true;
  138. }
  139. var rec = {
  140. source: buf.toString('utf8'),
  141. entry: defined(opts.entry, false),
  142. file: filename,
  143. id: id
  144. };
  145. if (rec.entry) rec.order = order;
  146. if (rec.transform === false) rec.transform = false;
  147. self.pipeline.write(rec);
  148. if (-- self._pending === 0) self.emit('_ready');
  149. }));
  150. return this;
  151. }
  152. var row;
  153. if (typeof file === 'object') {
  154. row = xtend(file, opts);
  155. }
  156. else if (!opts.entry && isExternalModule(file)) {
  157. // external module or builtin
  158. row = xtend(opts, { id: expose || file, file: file });
  159. }
  160. else {
  161. row = xtend(opts, { file: path.resolve(basedir, file) });
  162. }
  163. if (!row.id) {
  164. row.id = expose || row.file;
  165. }
  166. if (expose || !row.entry) {
  167. // Make this available to mdeps so that it can assign the value when it
  168. // resolves the pathname.
  169. row.expose = row.id;
  170. }
  171. if (opts.external) return self.external(file, opts);
  172. if (row.entry === undefined) row.entry = false;
  173. if (!row.entry && self._options.exports === undefined) {
  174. self._bpack.hasExports = true;
  175. }
  176. if (row.entry) row.order = self._entryOrder ++;
  177. if (opts.transform === false) row.transform = false;
  178. self.pipeline.write(row);
  179. return self;
  180. };
  181. Browserify.prototype.add = function (file, opts) {
  182. var self = this;
  183. if (!opts) opts = {};
  184. if (isArray(file)) {
  185. file.forEach(function (x) { self.add(x, opts) });
  186. return this;
  187. }
  188. return this.require(file, xtend({ entry: true, expose: false }, opts));
  189. };
  190. Browserify.prototype.external = function (file, opts) {
  191. var self = this;
  192. if (isArray(file)) {
  193. file.forEach(function (f) {
  194. if (typeof f === 'object') {
  195. self.external(f, xtend(opts, f));
  196. }
  197. else self.external(f, opts)
  198. });
  199. return this;
  200. }
  201. if (file && typeof file === 'object' && typeof file.bundle === 'function') {
  202. var b = file;
  203. self._pending ++;
  204. var bdeps = {};
  205. var blabels = {};
  206. b.on('label', function (prev, id) {
  207. self._external.push(id);
  208. if (prev !== id) {
  209. blabels[prev] = id;
  210. self._external.push(prev);
  211. }
  212. });
  213. b.pipeline.get('deps').push(through.obj(function (row, enc, next) {
  214. bdeps = xtend(bdeps, row.deps);
  215. this.push(row);
  216. next();
  217. }));
  218. self.on('dep', function (row) {
  219. Object.keys(row.deps).forEach(function (key) {
  220. var prev = bdeps[key];
  221. if (prev) {
  222. var id = blabels[prev];
  223. if (id) {
  224. row.indexDeps[key] = id;
  225. }
  226. }
  227. });
  228. });
  229. b.pipeline.get('label').once('end', function () {
  230. if (-- self._pending === 0) self.emit('_ready');
  231. });
  232. return this;
  233. }
  234. if (!opts) opts = {};
  235. var basedir = defined(opts.basedir, process.cwd());
  236. this._external.push(file);
  237. this._external.push('/' + relativePath(basedir, file));
  238. return this;
  239. };
  240. Browserify.prototype.exclude = function (file, opts) {
  241. if (!opts) opts = {};
  242. if (isArray(file)) {
  243. var self = this;
  244. file.forEach(function(file) {
  245. self.exclude(file, opts);
  246. });
  247. return this;
  248. }
  249. var basedir = defined(opts.basedir, process.cwd());
  250. this._exclude.push(file);
  251. this._exclude.push('/' + relativePath(basedir, file));
  252. return this;
  253. };
  254. Browserify.prototype.ignore = function (file, opts) {
  255. if (!opts) opts = {};
  256. if (isArray(file)) {
  257. var self = this;
  258. file.forEach(function(file) {
  259. self.ignore(file, opts);
  260. });
  261. return this;
  262. }
  263. var basedir = defined(opts.basedir, process.cwd());
  264. // Handle relative paths
  265. if (file[0] === '.') {
  266. this._ignore.push(path.resolve(basedir, file));
  267. }
  268. else {
  269. this._ignore.push(file);
  270. }
  271. return this;
  272. };
  273. Browserify.prototype.transform = function (tr, opts) {
  274. var self = this;
  275. if (typeof opts === 'function' || typeof opts === 'string') {
  276. tr = [ opts, tr ];
  277. }
  278. if (isArray(tr)) {
  279. opts = tr[1];
  280. tr = tr[0];
  281. }
  282. //if the bundler is ignoring this transform
  283. if (typeof tr === 'string' && !self._filterTransform(tr)) {
  284. return this;
  285. }
  286. function resolved () {
  287. self._transforms[order] = rec;
  288. -- self._pending;
  289. if (-- self._transformPending === 0) {
  290. self._transforms.forEach(function (transform) {
  291. self.pipeline.write(transform);
  292. });
  293. if (self._pending === 0) {
  294. self.emit('_ready');
  295. }
  296. }
  297. }
  298. if (!opts) opts = {};
  299. opts._flags = '_flags' in opts ? opts._flags : self._options;
  300. var basedir = defined(opts.basedir, this._options.basedir, process.cwd());
  301. var order = self._transformOrder ++;
  302. self._pending ++;
  303. self._transformPending ++;
  304. var rec = {
  305. transform: tr,
  306. options: opts,
  307. global: opts.global
  308. };
  309. if (typeof tr === 'string') {
  310. var topts = {
  311. basedir: basedir,
  312. paths: (self._options.paths || []).map(function (p) {
  313. return path.resolve(basedir, p);
  314. })
  315. };
  316. resolve(tr, topts, function (err, res) {
  317. if (err) return self.emit('error', err);
  318. rec.transform = res;
  319. resolved();
  320. });
  321. }
  322. else process.nextTick(resolved);
  323. return this;
  324. };
  325. Browserify.prototype.plugin = function (p, opts) {
  326. if (isArray(p)) {
  327. opts = p[1];
  328. p = p[0];
  329. }
  330. if (!opts) opts = {};
  331. var basedir = defined(opts.basedir, this._options.basedir, process.cwd());
  332. if (typeof p === 'function') {
  333. p(this, opts);
  334. }
  335. else {
  336. var pfile = resolve.sync(String(p), { basedir: basedir })
  337. var f = require(pfile);
  338. if (typeof f !== 'function') {
  339. throw new Error('plugin ' + p + ' should export a function');
  340. }
  341. f(this, opts);
  342. }
  343. return this;
  344. };
  345. Browserify.prototype._createPipeline = function (opts) {
  346. var self = this;
  347. if (!opts) opts = {};
  348. this._mdeps = this._createDeps(opts);
  349. this._mdeps.on('file', function (file, id) {
  350. pipeline.emit('file', file, id);
  351. self.emit('file', file, id);
  352. });
  353. this._mdeps.on('package', function (pkg) {
  354. pipeline.emit('package', pkg);
  355. self.emit('package', pkg);
  356. });
  357. this._mdeps.on('transform', function (tr, file) {
  358. pipeline.emit('transform', tr, file);
  359. self.emit('transform', tr, file);
  360. });
  361. var dopts = {
  362. index: !opts.fullPaths && !opts.exposeAll,
  363. dedupe: opts.dedupe,
  364. expose: this._expose
  365. };
  366. this._bpack = bpack(xtend(opts, { raw: true }));
  367. var pipeline = splicer.obj([
  368. 'record', [ this._recorder() ],
  369. 'deps', [ this._mdeps ],
  370. 'json', [ this._json() ],
  371. 'unbom', [ this._unbom() ],
  372. 'unshebang', [ this._unshebang() ],
  373. 'syntax', [ this._syntax() ],
  374. 'sort', [ depsSort(dopts) ],
  375. 'dedupe', [ this._dedupe() ],
  376. 'label', [ this._label(opts) ],
  377. 'emit-deps', [ this._emitDeps() ],
  378. 'debug', [ this._debug(opts) ],
  379. 'pack', [ this._bpack ],
  380. 'wrap', []
  381. ]);
  382. if (opts.exposeAll) {
  383. var basedir = defined(opts.basedir, process.cwd());
  384. pipeline.get('deps').push(through.obj(function (row, enc, next) {
  385. if (self._external.indexOf(row.id) >= 0) return next();
  386. if (self._external.indexOf(row.file) >= 0) return next();
  387. if (isAbsolutePath(row.id)) {
  388. row.id = '/' + relativePath(basedir, row.file);
  389. }
  390. Object.keys(row.deps || {}).forEach(function (key) {
  391. row.deps[key] = '/' + relativePath(basedir, row.deps[key]);
  392. });
  393. this.push(row);
  394. next();
  395. }));
  396. }
  397. return pipeline;
  398. };
  399. Browserify.prototype._createDeps = function (opts) {
  400. var self = this;
  401. var mopts = xtend(opts);
  402. var basedir = defined(opts.basedir, process.cwd());
  403. // Let mdeps populate these values since it will be resolving file paths
  404. // anyway.
  405. mopts.expose = this._expose;
  406. mopts.extensions = [ '.js', '.json' ].concat(mopts.extensions || []);
  407. self._extensions = mopts.extensions;
  408. mopts.transform = [];
  409. mopts.transformKey = defined(opts.transformKey, [ 'browserify', 'transform' ]);
  410. mopts.postFilter = function (id, file, pkg) {
  411. if (opts.postFilter && !opts.postFilter(id, file, pkg)) return false;
  412. if (self._external.indexOf(file) >= 0) return false;
  413. if (self._exclude.indexOf(file) >= 0) return false;
  414. //filter transforms on module dependencies
  415. if (pkg && pkg.browserify && pkg.browserify.transform) {
  416. //In edge cases it may be a string
  417. pkg.browserify.transform = [].concat(pkg.browserify.transform)
  418. .filter(Boolean)
  419. .filter(self._filterTransform);
  420. }
  421. return true;
  422. };
  423. mopts.filter = function (id) {
  424. if (opts.filter && !opts.filter(id)) return false;
  425. if (self._external.indexOf(id) >= 0) return false;
  426. if (self._exclude.indexOf(id) >= 0) return false;
  427. if (opts.bundleExternal === false && isExternalModule(id)) {
  428. return false;
  429. }
  430. return true;
  431. };
  432. mopts.resolve = function (id, parent, cb) {
  433. if (self._ignore.indexOf(id) >= 0) return cb(null, paths.empty, {});
  434. self._bresolve(id, parent, function (err, file, pkg) {
  435. if (file && self._ignore.indexOf(file) >= 0) {
  436. return cb(null, paths.empty, {});
  437. }
  438. if (file && self._ignore.length) {
  439. var nm = file.replace(/\\/g, '/').split('/node_modules/')[1];
  440. if (nm) {
  441. nm = nm.split('/')[0];
  442. if (self._ignore.indexOf(nm) >= 0) {
  443. return cb(null, paths.empty, {});
  444. }
  445. }
  446. }
  447. if (file) {
  448. var ex = '/' + relativePath(basedir, file);
  449. if (self._external.indexOf(ex) >= 0) {
  450. return cb(null, ex);
  451. }
  452. if (self._exclude.indexOf(ex) >= 0) {
  453. return cb(null, ex);
  454. }
  455. if (self._ignore.indexOf(ex) >= 0) {
  456. return cb(null, paths.empty, {});
  457. }
  458. }
  459. if (err) cb(err, file, pkg)
  460. else if (file) {
  461. if (opts.preserveSymlinks && parent.id !== self._mdeps.top.id) {
  462. return cb(err, path.resolve(file), pkg, file)
  463. }
  464. fs.realpath(file, function (err, res) {
  465. cb(err, res, pkg, file);
  466. });
  467. } else cb(err, null, pkg)
  468. });
  469. };
  470. if (opts.builtins === false) {
  471. mopts.modules = {};
  472. self._exclude.push.apply(self._exclude, Object.keys(builtins));
  473. }
  474. else if (opts.builtins && isArray(opts.builtins)) {
  475. mopts.modules = {};
  476. opts.builtins.forEach(function (key) {
  477. mopts.modules[key] = builtins[key];
  478. });
  479. }
  480. else if (opts.builtins && typeof opts.builtins === 'object') {
  481. mopts.modules = opts.builtins;
  482. }
  483. else mopts.modules = xtend(builtins);
  484. Object.keys(builtins).forEach(function (key) {
  485. if (!has(mopts.modules, key)) self._exclude.push(key);
  486. });
  487. mopts.globalTransform = [];
  488. if (!this._bundled) {
  489. this.once('bundle', function () {
  490. self.pipeline.write({
  491. transform: globalTr,
  492. global: true,
  493. options: {}
  494. });
  495. });
  496. }
  497. var no = [].concat(opts.noParse).filter(Boolean);
  498. var absno = no.filter(function(x) {
  499. return typeof x === 'string';
  500. }).map(function (x) {
  501. return path.resolve(basedir, x);
  502. });
  503. function globalTr (file) {
  504. if (opts.detectGlobals === false) return through();
  505. if (opts.noParse === true) return through();
  506. if (no.indexOf(file) >= 0) return through();
  507. if (absno.indexOf(file) >= 0) return through();
  508. var parts = file.replace(/\\/g, '/').split('/node_modules/');
  509. for (var i = 0; i < no.length; i++) {
  510. if (typeof no[i] === 'function' && no[i](file)) {
  511. return through();
  512. }
  513. else if (no[i] === parts[parts.length-1].split('/')[0]) {
  514. return through();
  515. }
  516. else if (no[i] === parts[parts.length-1]) {
  517. return through();
  518. }
  519. }
  520. if (opts.commondir === false && opts.builtins === false) {
  521. opts.insertGlobalVars = xtend({
  522. __dirname: function(file, basedir) {
  523. var dir = path.dirname(path.relative(basedir, file));
  524. return 'require("path").join(__dirname,' + dir.split(path.sep).map(JSON.stringify).join(',') + ')';
  525. },
  526. __filename: function(file, basedir) {
  527. var filename = path.relative(basedir, file);
  528. return 'require("path").join(__dirname,' + filename.split(path.sep).map(JSON.stringify).join(',') + ')';
  529. }
  530. }, opts.insertGlobalVars);
  531. }
  532. var vars = xtend({
  533. process: function () { return "require('_process')" },
  534. }, opts.insertGlobalVars);
  535. if (opts.bundleExternal === false) {
  536. vars.process = undefined;
  537. vars.buffer = undefined;
  538. }
  539. return insertGlobals(file, xtend(opts, {
  540. debug: opts.debug,
  541. always: opts.insertGlobals,
  542. basedir: opts.commondir === false && isArray(opts.builtins)
  543. ? '/'
  544. : opts.basedir || process.cwd()
  545. ,
  546. vars: vars
  547. }));
  548. }
  549. return mdeps(mopts);
  550. };
  551. Browserify.prototype._recorder = function (opts) {
  552. var self = this;
  553. var ended = false;
  554. this._recorded = [];
  555. if (!this._ticked) {
  556. process.nextTick(function () {
  557. self._ticked = true;
  558. self._recorded.forEach(function (row) {
  559. stream.push(row);
  560. });
  561. if (ended) stream.push(null);
  562. });
  563. }
  564. var stream = through.obj(write, end);
  565. return stream;
  566. function write (row, enc, next) {
  567. self._recorded.push(row);
  568. if (self._ticked) this.push(row);
  569. next();
  570. }
  571. function end () {
  572. ended = true;
  573. if (self._ticked) this.push(null);
  574. }
  575. };
  576. Browserify.prototype._json = function () {
  577. return through.obj(function (row, enc, next) {
  578. if (/\.json$/.test(row.file)) {
  579. row.source = 'module.exports=' + sanitize(row.source);
  580. }
  581. this.push(row);
  582. next();
  583. });
  584. };
  585. Browserify.prototype._unbom = function () {
  586. return through.obj(function (row, enc, next) {
  587. if (/^\ufeff/.test(row.source)) {
  588. row.source = row.source.replace(/^\ufeff/, '');
  589. }
  590. this.push(row);
  591. next();
  592. });
  593. };
  594. Browserify.prototype._unshebang = function () {
  595. return through.obj(function (row, enc, next) {
  596. if (/^#!/.test(row.source)) {
  597. row.source = row.source.replace(/^#![^\n]*\n/, '');
  598. }
  599. this.push(row);
  600. next();
  601. });
  602. };
  603. Browserify.prototype._syntax = function () {
  604. var self = this;
  605. return through.obj(function (row, enc, next) {
  606. var h = shasum(row.source);
  607. if (typeof self._syntaxCache[h] === 'undefined') {
  608. var err = syntaxError(row.source, row.file || row.id);
  609. if (err) return this.emit('error', err);
  610. self._syntaxCache[h] = true;
  611. }
  612. this.push(row);
  613. next();
  614. });
  615. };
  616. Browserify.prototype._dedupe = function () {
  617. return through.obj(function (row, enc, next) {
  618. if (!row.dedupeIndex && row.dedupe) {
  619. row.source = 'arguments[4]['
  620. + JSON.stringify(row.dedupe)
  621. + '][0].apply(exports,arguments)'
  622. ;
  623. row.nomap = true;
  624. }
  625. else if (row.dedupeIndex) {
  626. row.source = 'arguments[4]['
  627. + JSON.stringify(row.dedupeIndex)
  628. + '][0].apply(exports,arguments)'
  629. ;
  630. row.nomap = true;
  631. }
  632. if (row.dedupeIndex && row.indexDeps) {
  633. row.indexDeps.dup = row.dedupeIndex;
  634. }
  635. this.push(row);
  636. next();
  637. });
  638. };
  639. Browserify.prototype._label = function (opts) {
  640. var self = this;
  641. var basedir = defined(opts.basedir, process.cwd());
  642. return through.obj(function (row, enc, next) {
  643. var prev = row.id;
  644. if (self._external.indexOf(row.id) >= 0) return next();
  645. if (self._external.indexOf('/' + relativePath(basedir, row.id)) >= 0) {
  646. return next();
  647. }
  648. if (self._external.indexOf(row.file) >= 0) return next();
  649. if (row.index) row.id = row.index;
  650. self.emit('label', prev, row.id);
  651. if (row.indexDeps) row.deps = row.indexDeps || {};
  652. Object.keys(row.deps).forEach(function (key) {
  653. if (self._expose[key]) {
  654. row.deps[key] = key;
  655. return;
  656. }
  657. var afile = path.resolve(path.dirname(row.file), key);
  658. var rfile = '/' + relativePath(basedir, afile);
  659. if (self._external.indexOf(rfile) >= 0) {
  660. row.deps[key] = rfile;
  661. }
  662. if (self._external.indexOf(afile) >= 0) {
  663. row.deps[key] = rfile;
  664. }
  665. if (self._external.indexOf(key) >= 0) {
  666. row.deps[key] = key;
  667. return;
  668. }
  669. for (var i = 0; i < self._extensions.length; i++) {
  670. var ex = self._extensions[i];
  671. if (self._external.indexOf(rfile + ex) >= 0) {
  672. row.deps[key] = rfile + ex;
  673. break;
  674. }
  675. }
  676. });
  677. if (row.entry || row.expose) {
  678. self._bpack.standaloneModule = row.id;
  679. }
  680. this.push(row);
  681. next();
  682. });
  683. };
  684. Browserify.prototype._emitDeps = function () {
  685. var self = this;
  686. return through.obj(function (row, enc, next) {
  687. self.emit('dep', row);
  688. this.push(row);
  689. next();
  690. })
  691. };
  692. Browserify.prototype._debug = function (opts) {
  693. var basedir = defined(opts.basedir, process.cwd());
  694. return through.obj(function (row, enc, next) {
  695. if (opts.debug) {
  696. row.sourceRoot = 'file://localhost';
  697. row.sourceFile = relativePath(basedir, row.file);
  698. }
  699. this.push(row);
  700. next();
  701. });
  702. };
  703. Browserify.prototype.reset = function (opts) {
  704. if (!opts) opts = {};
  705. var hadExports = this._bpack.hasExports;
  706. this.pipeline = this._createPipeline(xtend(opts, this._options));
  707. this._bpack.hasExports = hadExports;
  708. this._entryOrder = 0;
  709. this._bundled = false;
  710. this.emit('reset');
  711. };
  712. Browserify.prototype.bundle = function (cb) {
  713. var self = this;
  714. if (cb && typeof cb === 'object') {
  715. throw new Error(
  716. 'bundle() no longer accepts option arguments.\n'
  717. + 'Move all option arguments to the browserify() constructor.'
  718. );
  719. }
  720. if (this._bundled) {
  721. var recorded = this._recorded;
  722. this.reset();
  723. recorded.forEach(function (x) {
  724. self.pipeline.write(x);
  725. });
  726. }
  727. var output = readonly(this.pipeline);
  728. if (cb) {
  729. output.on('error', cb);
  730. output.pipe(concat(function (body) {
  731. cb(null, body);
  732. }));
  733. }
  734. function ready () {
  735. self.emit('bundle', output);
  736. self.pipeline.end();
  737. }
  738. if (this._pending === 0) ready();
  739. else this.once('_ready', ready);
  740. this._bundled = true;
  741. return output;
  742. };
  743. function isStream (s) { return s && typeof s.pipe === 'function' }
  744. function isAbsolutePath (file) {
  745. var regexp = process.platform === 'win32' ?
  746. /^\w:/ :
  747. /^\//;
  748. return regexp.test(file);
  749. }
  750. function isExternalModule (file) {
  751. var regexp = process.platform === 'win32' ?
  752. /^(\.|\w:)/ :
  753. /^[\/.]/;
  754. return !regexp.test(file);
  755. }
  756. function relativePath (from, to) {
  757. // Replace \ with / for OS-independent behavior
  758. return cachedPathRelative(from, to).replace(/\\/g, '/');
  759. }