pp-parachute
Version:
Airdrop JS Applications
153 lines (133 loc) • 4.66 kB
JavaScript
var browserify = require('browserify');
var Promise = require('bluebird');
var Bundler = require('./bundler');
var inherits = require('util').inherits;
var path = require('path');
var through = require('through2');
var xtend = require('xtend');
var tsify = require('tsify');
var ScriptBundler = function (assetGlobs) {
Bundler.call(this, assetGlobs);
this.transforms = [];
this.scriptBuilder = null;
this.requires = [];
this.externals = [];
this.standaloneFile = '';
this.fileCache = {};
this.tscOptions = {
noImplicitAny: true,
target: "es5"
};
this.debug = true;
};
inherits(ScriptBundler, Bundler);
ScriptBundler.prototype.browserifyArgs = function () {
return {
debug: this.debug,
detectGlobals: false,
cache: this.fileCache,
packageCache: {},
fullPaths: true,
standalone: (typeof this.standaloneFile === 'string' && this.standaloneFile || '')
};
};
ScriptBundler.prototype.require = function (req) {
this.requires.push(req);
return this;
};
ScriptBundler.prototype.external = function (ext) {
this.externals.push(ext);
return this;
};
ScriptBundler.prototype.createSourceMaps = function (debug) {
this.debug = debug;
return this;
};
ScriptBundler.prototype.transform = function (transform) {
this.transforms.push(transform);
return this;
};
ScriptBundler.prototype.standalone = function (filename) {
this.standaloneFile = filename;
return this;
};
ScriptBundler.prototype.typeScriptOptions = function(options) {
this.tscOptions = options;
return this;
};
ScriptBundler.prototype.ensureBrowserify = function (filePaths) {
if (!this.scriptBuilder || this.dirtyFileList) {
this.dirtyFileList = false;
// reset cache when files are added / removed, build times will be longer
// because of this but I think thats tolerable.
this.fileCache = {};
this.scriptBuilder = browserify(filePaths, this.browserifyArgs());
try {
this.scriptBuilder.plugin(tsify, this.tscOptions);
} catch(e) {
console.log('Failed to load tsify plugin');
console.log(e.stack);
}
var self = this;
//this is basically 80% of what watchify does, but I dont want to have execss watchers
//since we already have them for all the files watchify cares about.
this.scriptBuilder.on('reset', function () {
var stream = through.obj(function (row, enc, next) {
var file = row.expose ? self.scriptBuilder._expose[row.id] : row.file;
self.fileCache[file] = {
source: row.source,
deps: xtend({}, row.deps)
};
this.push(row);
next();
});
self.scriptBuilder.pipeline.get('deps').push(stream);
});
this.scriptBuilder.on('transform', function (transform) {
transform.on('file', function (file) {
if (file.indexOf('node_modules') === -1 && self.assetWatcher) {
self.assetWatcher.ensureFileIsWatched(file);
}
});
});
this.scriptBuilder.on('file', function (file) {
if (file.indexOf('node_modules') === -1 && self.assetWatcher) {
self.assetWatcher.ensureFileIsWatched(file);
}
});
this.scriptBuilder.on('package', function (pkg) {
if (pkg.__dirname.indexOf('node_modules') === -1) {
self.assetWatcher && self.assetWatcher.ensureFileIsWatched(path.join(pkg.__dirname, 'package.json'));
}
});
}
};
ScriptBundler.prototype.bundle = function (filePaths) {
this.ensureBrowserify(filePaths);
var self = this;
var fn = function (resolve, reject) {
self.requires.forEach(function (req) {
self.scriptBuilder.require(req);
});
self.externals.forEach(function (ext) {
self.scriptBuilder.external(ext);
});
self.transforms.forEach(function (transform) {
self.scriptBuilder.transform(transform);
});
self.scriptBuilder.bundle(function bundleCallback(error, result) {
if (error) {
reject(error.message);
} else {
resolve(result.toString());
}
});
};
return new Promise(fn);
};
ScriptBundler.prototype.onFileChanged = function (file) {
if (this.fileCache[file]) {
delete this.fileCache[file];
}
};
module.exports = ScriptBundler;