fuse-box
Version:
Fuse-Box a bundler that does it right
359 lines (357 loc) • 14.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const path = require("path");
const process = require("process");
const realm_utils_1 = require("realm-utils");
const Utils_1 = require("./../Utils");
const ShimCollection_1 = require("./../ShimCollection");
const Server_1 = require("./../devServer/Server");
const JSONplugin_1 = require("./../plugins/JSONplugin");
const PathMaster_1 = require("./PathMaster");
const WorkflowContext_1 = require("./WorkflowContext");
const CollectionSource_1 = require("./../CollectionSource");
const Arithmetic_1 = require("./../arithmetic/Arithmetic");
const ModuleCollection_1 = require("./ModuleCollection");
const MagicalRollup_1 = require("../rollup/MagicalRollup");
const UserOutput_1 = require("./UserOutput");
const BundleProducer_1 = require("./BundleProducer");
const Bundle_1 = require("./Bundle");
const isWin = /^win/.test(process.platform);
const appRoot = require("app-root-path");
class FuseBox {
constructor(opts) {
this.opts = opts;
this.producer = new BundleProducer_1.BundleProducer(this);
this.context = new WorkflowContext_1.WorkFlowContext();
this.context.fuse = this;
this.collectionSource = new CollectionSource_1.CollectionSource(this.context);
opts = opts || {};
let homeDir = appRoot.path;
if (opts.writeBundles !== undefined) {
this.context.userWriteBundles = opts.writeBundles;
}
if (opts.target !== undefined) {
this.context.target = opts.target;
}
if (opts.polyfillNonStandardDefaultUsage !== undefined) {
this.context.polyfillNonStandardDefaultUsage = opts.polyfillNonStandardDefaultUsage;
}
if (opts.useJsNext !== undefined) {
this.context.useJsNext = opts.useJsNext;
}
if (opts.useTypescriptCompiler !== undefined) {
this.context.useTypescriptCompiler = opts.useTypescriptCompiler;
}
if (opts.experimentalFeatures !== undefined) {
this.context.experimentalFeaturesEnabled = opts.experimentalFeatures;
}
if (opts.homeDir) {
homeDir = Utils_1.ensureUserPath(opts.homeDir);
}
if (opts.debug !== undefined) {
this.context.debugMode = opts.debug;
}
if (opts.debug !== undefined) {
this.context.debugMode = opts.debug;
}
if (opts.warnings !== undefined) {
this.context.showWarnings = opts.warnings;
}
if (opts.ignoreModules) {
this.context.ignoreGlobal = opts.ignoreModules;
}
this.context.debugMode = opts.debug !== undefined ? opts.debug : Utils_1.contains(process.argv, "--debug");
if (opts.modulesFolder) {
this.context.customModulesFolder =
Utils_1.ensureUserPath(opts.modulesFolder);
}
if (opts.tsConfig) {
this.context.tsConfig = opts.tsConfig;
}
if (opts.sourceMaps) {
this.context.setSourceMapsProperty(opts.sourceMaps);
}
this.context.runAllMatchedPlugins = !!opts.runAllMatchedPlugins;
this.context.plugins = opts.plugins || [JSONplugin_1.JSONPlugin()];
if (opts.package) {
if (realm_utils_1.utils.isPlainObject(opts.package)) {
const packageOptions = opts.package;
this.context.defaultPackageName = packageOptions.name || "default";
this.context.defaultEntryPoint = packageOptions.main;
}
else {
this.context.defaultPackageName = opts.package;
}
}
if (opts.cache !== undefined) {
this.context.useCache = opts.cache ? true : false;
}
if (opts.log !== undefined) {
this.context.doLog = opts.log;
this.context.log.printLog = opts.log;
}
if (opts.hash !== undefined) {
this.context.hash = opts.hash;
}
if (opts.alias) {
this.context.addAlias(opts.alias);
}
this.context.initAutoImportConfig(opts.natives, opts.autoImport);
if (opts.globals) {
this.context.globals = opts.globals;
}
if (opts.shim) {
this.context.shim = opts.shim;
}
if (opts.standalone !== undefined) {
this.context.standaloneBundle = opts.standalone;
}
if (opts.rollup) {
this.context.rollupOptions = opts.rollup;
}
if (opts.customAPIFile) {
this.context.customAPIFile = opts.customAPIFile;
}
this.context.setHomeDir(homeDir);
if (opts.cache !== undefined) {
this.context.setUseCache(opts.cache);
}
this.virtualFiles = opts.files;
if (opts.output) {
this.context.output = new UserOutput_1.UserOutput(this.context, opts.output);
}
this.compareConfig(this.opts);
}
static init(opts) {
return new FuseBox(opts);
}
triggerPre() {
this.context.triggerPluginsMethodOnce("preBundle", [this.context]);
}
triggerStart() {
this.context.triggerPluginsMethodOnce("bundleStart", [this.context]);
}
triggerEnd() {
this.context.triggerPluginsMethodOnce("bundleEnd", [this.context]);
}
triggerPost() {
this.context.triggerPluginsMethodOnce("postBundle", [this.context]);
}
copy() {
const config = Object.assign({}, this.opts);
config.plugins = [].concat(config.plugins || []);
return FuseBox.init(config);
}
bundle(name, arithmetics) {
let fuse = this.copy();
const bundle = new Bundle_1.Bundle(name, fuse, this.producer);
bundle.arithmetics = arithmetics;
this.producer.add(name, bundle);
return bundle;
}
dev(opts, fn) {
opts = opts || {};
opts.port = opts.port || 4444;
this.producer.devServerOptions = opts;
this.producer.runner.bottom(() => {
let server = new Server_1.Server(this);
server.start(opts);
if (opts.open) {
try {
const opn = require('opn');
opn(`http://localhost:${opts.port}`);
}
catch (e) {
this.context.log.echoRed('If you want to open the browser, please install "opn" package. "npm install opn --save-dev"');
}
}
if (fn) {
fn(server);
}
});
}
register(packageName, opts) {
this.producer.runner.top(() => {
return this.producer.register(packageName, opts);
});
}
run(opts) {
return this.producer.run(opts);
}
compareConfig(config) {
if (!this.context.useCache)
return;
const mainStr = fs.readFileSync(require.main.filename, "utf8");
if (this.context.cache) {
const configPath = path.resolve(this.context.cache.cacheFolder, "config.json");
if (fs.existsSync(configPath)) {
const storedConfigStr = fs.readFileSync(configPath, "utf8");
if (storedConfigStr !== mainStr)
this.context.nukeCache();
}
if (isWin)
fs.writeFileSync(configPath, mainStr);
else
fs.writeFile(configPath, mainStr, () => { });
}
}
createSplitBundle(conf) {
let files = conf.files;
let defaultCollection = new ModuleCollection_1.ModuleCollection(this.context, this.context.defaultPackageName);
defaultCollection.pm = new PathMaster_1.PathMaster(this.context, this.context.homeDir);
this.context.reset();
const bundleData = new Arithmetic_1.BundleData();
this.context.source.init();
bundleData.entry = "";
this.context.log.subBundleStart(this.context.output.filename, conf.parent.name);
return defaultCollection.resolveSplitFiles(files).then(() => {
return this.collectionSource.get(defaultCollection).then((cnt) => {
this.context.log.echoDefaultCollection(defaultCollection, cnt);
});
}).then(() => {
return new Promise((resolve, reject) => {
this.context.source.finalize(bundleData);
this.triggerEnd();
this.triggerPost();
this.context.writeOutput(() => {
return resolve(conf);
});
});
});
}
process(bundleData, bundleReady) {
let bundleCollection = new ModuleCollection_1.ModuleCollection(this.context, this.context.defaultPackageName);
bundleCollection.pm = new PathMaster_1.PathMaster(this.context, bundleData.homeDir);
if (bundleData.typescriptMode) {
this.context.tsMode = true;
bundleCollection.pm.setTypeScriptMode();
}
let self = this;
return bundleCollection.collectBundle(bundleData).then(module => {
this.context.log.bundleStart(this.context.bundle.name);
return realm_utils_1.chain(class extends realm_utils_1.Chainable {
constructor() {
super(...arguments);
this.globalContents = [];
}
setDefaultCollection() {
return bundleCollection;
}
addDefaultContents() {
return self.collectionSource.get(this.defaultCollection).then((cnt) => {
self.context.log.echoDefaultCollection(this.defaultCollection, cnt);
});
}
addNodeModules() {
return realm_utils_1.each(self.context.nodeModules, (collection) => {
if (collection.cached || (collection.info && !collection.info.missing)) {
return self.collectionSource.get(collection).then((cnt) => {
self.context.log.echoCollection(collection, cnt);
if (!collection.cachedName && self.context.useCache) {
self.context.cache.set(collection.info, cnt);
}
this.globalContents.push(cnt);
});
}
});
}
format() {
return {
contents: this.globalContents,
};
}
}).then(() => {
if (self.context.bundle && self.context.bundle.bundleSplit) {
return self.context.bundle.bundleSplit.beforeMasterWrite(self.context);
}
}).then(result => {
let self = this;
const rollup = this.handleRollup();
if (rollup) {
self.context.source.finalize(bundleData);
rollup().then(() => {
self.context.log.end();
this.triggerEnd();
this.triggerPost();
this.context.writeOutput(bundleReady);
return self.context.source.getResult();
});
}
else {
self.context.log.end();
this.triggerEnd();
self.context.source.finalize(bundleData);
this.triggerPost();
this.context.writeOutput(bundleReady);
return self.context.source.getResult();
}
});
});
}
handleRollup() {
if (this.context.rollupOptions) {
return () => {
let rollup = new MagicalRollup_1.MagicalRollup(this.context);
return rollup.parse();
};
}
else {
return false;
}
}
addShims() {
let shim = this.context.shim;
if (shim) {
for (let name in shim) {
if (shim.hasOwnProperty(name)) {
let data = shim[name];
if (data.exports) {
let shimedCollection = ShimCollection_1.ShimCollection.create(this.context, name, data.exports);
this.context.addNodeModule(name, shimedCollection);
if (data.source) {
let source = Utils_1.ensureUserPath(data.source);
let contents = fs.readFileSync(source).toString();
this.context.source.addContent(contents);
}
}
}
}
}
}
initiateBundle(str, bundleReady) {
this.context.reset();
this.context.defer.lock();
this.triggerPre();
this.context.source.init();
this.addShims();
this.triggerStart();
let parser = Arithmetic_1.Arithmetic.parse(str);
let bundle;
return Arithmetic_1.Arithmetic.getFiles(parser, this.virtualFiles, this.context.homeDir).then(data => {
bundle = data;
if (bundle.tmpFolder) {
this.context.homeDir = bundle.tmpFolder;
}
if (bundle.standalone !== undefined) {
this.context.debug("Arithmetic", `Override standalone ${bundle.standalone}`);
this.context.standaloneBundle = bundle.standalone;
}
if (bundle.cache !== undefined) {
this.context.debug("Arithmetic", `Override cache ${bundle.cache}`);
this.context.useCache = bundle.cache;
}
return this.process(data, bundleReady);
}).then((contents) => {
bundle.finalize();
return contents;
}).catch(e => {
console.log(e.stack || e);
});
}
}
exports.FuseBox = FuseBox;
process.on('unhandledRejection', (reason, promise) => {
console.log(reason.stack);
});
//# sourceMappingURL=FuseBox.js.map