Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ var browserify = require('browserify');
var fs = require('fs');

var files = [ './files/x.js', './files/y.js' ];
var b = browserify(files);
var b = browserify(files, { dedupe: false });
b.plugin('../', { o: [ 'bundle/x.js', 'bundle/y.js' ] });
b.bundle().pipe(fs.createWriteStream('bundle/common.js'));
1 change: 1 addition & 0 deletions example/files/a1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = 42
1 change: 1 addition & 0 deletions example/files/a2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = 42
3 changes: 2 additions & 1 deletion example/files/x.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var a = require('./a1.js');
var z = require('./z.js');
var w = require('./w.js');
console.log(z(5) * w(2));
console.log(a * z(5) * w(2));
3 changes: 2 additions & 1 deletion example/files/y.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
var a = require('./a2.js');
var z = require('./z.js');
console.log(z(2) + 111);
console.log(a + z(2) + 111);
49 changes: 31 additions & 18 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ module.exports = function f (b, opts) {
.concat(opts._).filter(Boolean);

var needRecords = !files.length;

var outopt = defined(opts.outputs, opts.output, opts.o);

opts.objectMode = true;
opts.raw = true;
opts.rmap = {};
Expand All @@ -44,6 +44,7 @@ module.exports = function f (b, opts) {

function addHooks () {
b.pipeline.get('record').push(through.obj(function(row, enc, next) {
// record entrypoints
if (row.file && needRecords) {
files.push(row.file);
}
Expand All @@ -65,47 +66,59 @@ module.exports = function f (b, opts) {
outputs = [];
}

// utility for creating output streams
function moreOutputs (file) {
if (isarray(outopt)) return [];
if (!outopt) return [];
var xopts = { env: xtend(process.env, { FILE: file }) };
return [ outpipe(outopt, xopts) ];
}

var pipelines = files.reduce(function (acc, x, ix) {
// create a pipeline (labeled-stream-splicer) for every entry file
// with only a packer
var pipelines = files.reduce(function (acc, file, index) {
var pipeline = splicer.obj([
'pack', [ pack(packOpts) ],
'wrap', []
]);

if (ix >= outputs.length) {
outputs.push.apply(outputs, moreOutputs(x));
// if not enough specified outputs, possibly add additional outputs (?)
if (index >= outputs.length) {
outputs.push.apply(outputs, moreOutputs(file));
}
if (outputs[ix]) pipeline.pipe(outputs[ix]);

acc[path.resolve(cwd, x)] = pipeline;
// pipe to output if one exists
if (outputs[index]) pipeline.pipe(outputs[index]);

acc[path.resolve(cwd, file)] = pipeline;
return acc;
}, {});

// Force browser-pack to wrap the common bundle
b._bpack.hasExports = true;

// for tests/debugging
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also for plugins to hook into factored pipelines. If you have a minification step for example it can be added to the factored pipeline by using this event.

Object.keys(pipelines).forEach(function (id) {
b.emit('factor.pipeline', id, pipelines[id]);
});

// create factor stream
var s = createStream(files, opts);

// connect each factor groups module stream to bundle pipeline
s.on('stream', function (bundle) {
// each group's output stream
bundle.pipe(pipelines[bundle.file]);
});

// add factor stream before pack
b.pipeline.get('pack').unshift(s);

if (needRecords) files = [];

next();
}));

// capture module's relative path. used for recovering entry point pathnames
Copy link
Member

@goto-bus-stop goto-bus-stop Mar 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would keep this comment but probably remove most of the others…tbh, I feel like many of the comments only restate the line and don't actually clarify much.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the comments to stay sane while trying to read through the code which i found unintuitive

b.pipeline.get('label').push(through.obj(function(row, enc, next) {
opts.rmap[row.id] = path.resolve(cwd, row.file);
next(null, row);
Expand All @@ -118,10 +131,10 @@ module.exports = function f (b, opts) {

function createStream (files, opts) {
if (!opts) opts = {};

var fr = new Factor(files, opts);
var parse, dup;

if (opts.objectMode) {
dup = combine(depsTopoSort(), reverse(), fr);
}
Expand All @@ -135,7 +148,7 @@ function createStream (files, opts) {
;
parse.on('error', function (err) { dup.emit('error', err) });
}

fr.on('error', function (err) { dup.emit('error', err) });
fr.on('stream', function (s) {
if (opts.raw) dup.emit('stream', s)
Expand All @@ -150,21 +163,21 @@ function Factor (files, opts) {
var self = this;
if (!(this instanceof Factor)) return new Factor(files, opts);
Transform.call(this, { objectMode: true });

if (!opts) opts = {};
this.basedir = defined(opts.basedir, process.cwd());

this._streams = {};
this._groups = {};
this._buffered = {};

this._ensureCommon = {};
this._files = files.reduce(function (acc, file) {
acc[path.resolve(self.basedir, file)] = true;
return acc;
}, {});
this._rmap = opts.rmap || {};

this._thresholdVal = typeof opts.threshold === "number"
? opts.threshold : 1
;
Expand Down Expand Up @@ -200,9 +213,9 @@ Factor.prototype._transform = function (row, enc, next) {
self._streams[id].push(row);
});
}

next();

function addGroups (gid) {
Object.keys(row.deps || {}).forEach(function (key) {
var file = row.deps[key];
Expand All @@ -215,7 +228,7 @@ Factor.prototype._transform = function (row, enc, next) {

Factor.prototype._flush = function () {
var self = this;

Object.keys(self._streams).forEach(function (key) {
self._streams[key].push(null);
});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
},
"devDependencies": {
"browser-unpack": "^1.1.1",
"browserify": "^11.0.1",
"browserify": "^16.5.0",
"concat-stream": "^1.4.6",
"mkdirp": "~0.5.0",
"module-deps": "^3.9.0",
Expand Down
29 changes: 17 additions & 12 deletions readme.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ module.exports = function (n) { return n * 50 }
Now run factor-bundle as a plugin (new in browserify 3.28.0):

``` sh
browserify x.js y.js -p [ factor-bundle -o bundle/x.js -o bundle/y.js ] \
browserify --no-dedupe x.js y.js -p [ factor-bundle -o bundle/x.js -o bundle/y.js ] \
-o bundle/common.js
```

Expand All @@ -54,7 +54,7 @@ $ module-deps x.js y.js | factor-bundle \
or factor out an existing bundle already compiled by browserify:

``` sh
$ browserify x.js y.js > bundle.js
$ browserify --no-dedupe x.js y.js > bundle.js
$ browser-unpack < bundle.js | factor-bundle \
x.js -o bundle/x.js \
y.js -o bundle/y.js \
Expand Down Expand Up @@ -84,13 +84,18 @@ $ cat bundle/common.js bundle/y.js | node
333
```

## usage note

You must disable browserify's dedupe feature in order to use this module.
It can be disabled by providing `{ dedupe: false }` in the js api, or by the `--no-dedup` cli argument.

## command-line outpipe example

We can pipe each output file through some other processes. Here we'll do
minification with uglify compression with gzip:

``` sh
browserify files/*.js \
browserify --no-dedupe files/*.js \
-p [ factor-bundle -o 'uglifyjs -cm | gzip > bundle/`basename $FILE`.gz' ] \
| uglifyjs -cm | gzip > bundle/common.js.gz
```
Expand All @@ -104,7 +109,7 @@ var browserify = require('browserify');
var fs = require('fs');

var files = [ './files/x.js', './files/y.js' ];
var b = browserify(files);
var b = browserify(files, { dedupe: true });
b.plugin('factor-bundle', { outputs: [ 'bundle/x.js', 'bundle/y.js' ] });
b.bundle().pipe(fs.createWriteStream('bundle/common.js'));
```
Expand All @@ -116,7 +121,7 @@ var browserify = require('browserify');
var concat = require('concat-stream');

var files = [ './files/x.js', './files/y.js' ];
var b = browserify(files);
var b = browserify(files, { dedupe: true });

b.plugin('factor-bundle', { outputs: [ write('x'), write('y') ] });
b.bundle().pipe(write('common'));
Expand All @@ -141,7 +146,7 @@ where OPTIONS are:
-o Output FILE or CMD that maps to a corresponding entry file at the same
index. CMDs are executed with $FILE set to the corresponding input file.
Optionally specify a function that returns a valid value for this argument.

-e Entry file to use, overriding the entry files listed in the original
bundle.

Expand All @@ -159,10 +164,10 @@ the corresponding output file (-o).

Write output to FILE or CMD. CMD is distinguished from FILE by the presence
of one or more `>` or `|` characters. For example, use:

factor-bundle browser/a.js browser/b.js \
-o bundle/a.js -o bundle/b.js

to write to a FILE. And do something like:

factor-bundle browser/*.js \
Expand Down Expand Up @@ -203,10 +208,10 @@ this information is gathered from browserify itself.
The files held in common among `> opts.threshold` (default: 1) bundles will be
output on the `fr` stream itself. The entry-specific bundles are diverted into
each `'stream'` event's output. `opts.threshold` can be a number or a function
`opts.threshold(row, groups)` where `row` is a
[module-deps](https://github.com/substack/module-deps) object and `groups` is
an array of bundles which depend on the row. If the threshold function returns
`true`, that row and all its dependencies will go to the `common` bundle. If
`opts.threshold(row, groups)` where `row` is a
[module-deps](https://github.com/substack/module-deps) object and `groups` is
an array of bundles which depend on the row. If the threshold function returns
`true`, that row and all its dependencies will go to the `common` bundle. If
false, the row (but not its dependencies) will go to each bundle in `groups`.
For example:

Expand Down