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