UNPKG

steal-tools

Version:

Futuristic build tools for ES6 Module applications.

136 lines (119 loc) 3.73 kB
var makeBundleGraph = require("./make_graph_with_bundles"); var through = require("through2"); var clone = require("lodash").clone; var getDependencies = require("../node_trace"); var xor = require("lodash").xor; var removeActiveSourceKeys = require("./remove_active_source_keys"); /** * @module regraph * @description Consumes a Dependency Graph and can regenerate another when * modules change. */ module.exports = function(config, options){ var cachedData; // Regenerate a new bundle graph and copy over the transforms so they can // be reused. function regenerate(moduleName, done){ var cfg = clone(config, true); // if the moduleName is not in the graph, make it the main. if(moduleName && !cachedData.graph[moduleName]) { cfg.main = moduleName; } makeBundleGraph(cfg, options).then(function(data){ var graph = data.graph; var oldGraph = cachedData.graph; for(var name in graph){ if(name !== moduleName && oldGraph[name]) { graph[name].transforms = oldGraph[name].transforms; } } cachedData = cloneData(data); done(null, data); }, done); } function clean(node, newSource) { node.load.source = newSource; delete node.transforms; delete node.sourceNode; } function cloneData(data) { var newData = clone(data); newData.graph = clone(newData.graph); return newData; } function cached(data, enc, next){ // This will only happen the first time, just to cache. if(typeof data === "object") { // Looks like: // { graph, steal, loader, buildLoader, mains } cachedData = cloneData(data); next(null, data); } else { var moduleName = data; // Reload happened before the graph was loaded. if(!cachedData) { next(null, {}); return; } // Get the old node and check to see if it has any new dependencies, // if so just regenerate the entire graph. var node = cachedData.graph[moduleName]; if(node) { diff(node).then(function(result){ if(result.same) { removeActiveSourceKeys(cachedData.graph); // don't pass the local `cachedData` variable down the // stream, it might be mutated var oldCachedData = cachedData; cachedData = cloneData(cachedData); return next(null, oldCachedData); } regenerate(moduleName, next); }, function(err){ err.moduleName = moduleName; next(err); }); } else { // Either load the module name, which is not part of the graph // or will pass null thus reloading the main graph. regenerate(moduleName || null, next); } } } /** * Check to see if the node has changed. Do this by looking at the source * and running it through System.instantiate to see if new deps were added. * Recursively do the same for any System.defined modules. */ function diff(node) { var oldBundle = (cachedData.loader.bundle || []).slice(); return getDependencies(node.load).then(function(result){ var newBundle = (cachedData.loader.bundle || []).slice(); // If the deps are the same we can return the existing graph. if(same(node.deps, result.deps) && same(oldBundle, newBundle)) { clean(node, result.source); if(result.virtualModules.length) { var promises = result.virtualModules.map(function(l){ var node = cachedData.graph[l.name]; node.load.source = l.source; node.load.metadata.useSource = true; return diff(node); }); return Promise.all(promises).then(function(results){ result.same = results.every(function(res){ return res.same; }); return result; }); } result.same = true; } return result; }); } return through.obj(cached); }; function same(a, b){ return !xor(a, b).length; }