gulpfile.js
function bundleCircularDependencies() {

    function findCircular(deps, chain) {
      for (var i = 0, startIndex, c, p; i < deps.length; i++) {
        // Only top level dependencies will be included in the chain.
        p = sourcePackages.findByDependencyName(deps[i]);
        if (!p) {
          continue;
        }
        startIndex = chain.indexOf(p.name);
        if (startIndex !== -1) {
          return chain.slice(startIndex);
        } else {
          c = findCircular(p.dependencies, chain.concat(p.name));
          if (c) {
            return c;
          }
        }
      }
    }

    function bundleCircular(chain) {

      // Sort the chain so that all packages are
      // bundled into the first found in the source.
      chain = sortChain(chain);

      var target = sourcePackages.findByDependencyName(chain[0]);
      delete target.comments;
      chain.slice(1).forEach(function(n) {
        var src = sourcePackages.findByDependencyName(n);
        target.body += '\n\n' + src.body;
        target.bodyWithComments += '\n\n' + src.bodyWithComments;
        bundleArray(target, src, 'dependencies', true);
        bundleArray(target, src, 'varDependencies', true);
        bundleArray(target, src, 'vars');
        bundleMap(target, src, 'assigns');
        updateExternalDependencies(src.name, target.name);

        if (src.type === 'build' && (!target.vars || !target.vars.length)) {
          // A build function that is having it's call block being bundled
          // into it can also take on the type "build". This generally means
          // that it has no exports. However don't do this if the function is
          // building up variables, in which case it will have a "vars".
          target.type = 'build';
        }

        removePackage(src);
      });

    }

    function sortChain(chain) {
      return chain.sort(function(a, b) {
        return getPackageIndexByName(a) - getPackageIndexByName(b);
      });
    }

    function getPackageIndexByName(name) {
      return sourcePackages.findIndex(function(p) {
        return p.name === name;
      });
    }

    // Bundle all dependencies from the source into the target,
    // but only after removing the circular dependency itself.
    function bundleArray(target, src, name, notSelf) {
      var srcValues, targetValues;
      if (src[name]) {
        srcValues = src[name] || [];
        targetValues = target[name] || [];
        target[name] = uniq(targetValues.concat(srcValues.filter(function(d) {
          return !notSelf || d !== target.name;
        })));
      }
    }

    function bundleMap(target, src, name) {
      if (src[name]) {
        target[name] = target[name] || {};
        merge(target[name], src[name]);
      }
    }

    // Update all packages pointing to the old package.
    function updateExternalDependencies(oldName, newName) {
      sourcePackages.forEach(function(p) {
        var index = p.dependencies.indexOf(oldName);
        if (index !== -1) {
          if (p.name === newName || p.dependencies.indexOf(newName) !== -1) {
            // If the package has the same name as the one we are trying to
            // update to, then we are trying to update the package to point
            // to itself as a dependency, which isn't possible so just remove
            // the old dependency. Alternatively, if the package already has
            // the new name, then we can simply remove the old one and move on.
            p.dependencies.splice(index, 1);
          } else {
            // If the package is NOT trying to update to itself and does NOT
            // have the new dependency already, then add it in place of the
            // old one.
            p.dependencies.splice(index, 1, newName);
          }
        }
      });
    }

    function removePackage(p) {
      var index = sourcePackages.indexOf(p);
      sourcePackages.splice(index, 1);
    }

    sourcePackages.forEach(function(p) {
      var chain = findCircular(p.dependencies, []);
      if (chain) {
        bundleCircular(chain);
      }
    });
  }
function bundleCircularDependencies() {

    function findCircular(deps, chain) {
      for (var i = 0, startIndex, c, p; i < deps.length; i++) {
        // Only top level dependencies will be included in the chain.
        p = sourcePackages.findByDependencyName(deps[i]);
        if (!p) {
          continue;
        }
        startIndex = chain.indexOf(p.name);
        if (startIndex !== -1) {
          return chain.slice(startIndex);
        } else {
          c = findCircular(p.dependencies, chain.concat(p.name));
          if (c) {
            return c;
          }
        }
      }
    }

    function bundleCircular(chain) {

      // Sort the chain so that all packages are
      // bundled into the first found in the source.
      chain = sortChain(chain);

      var target = sourcePackages.findByDependencyName(chain[0]);
      delete target.comments;
      chain.slice(1).forEach(function(n) {
        var src = sourcePackages.findByDependencyName(n);
        target.body += '\n\n' + src.body;
        target.bodyWithComments += '\n\n' + src.bodyWithComments;
        bundleArray(target, src, 'dependencies', true);
        bundleArray(target, src, 'varDependencies', true);
        bundleArray(target, src, 'vars');
        bundleMap(target, src, 'assigns');
        updateExternalDependencies(src.name, target.name);

        if (src.type === 'build' && (!target.vars || !target.vars.length)) {
          // A build function that is having it's call block being bundled
          // into it can also take on the type "build". This generally means
          // that it has no exports. However don't do this if the function is
          // building up variables, in which case it will have a "vars".
          target.type = 'build';
        }

        removePackage(src);
      });

    }

    function sortChain(chain) {
      return chain.sort(function(a, b) {
        return getPackageIndexByName(a) - getPackageIndexByName(b);
      });
    }

    function getPackageIndexByName(name) {
      return sourcePackages.findIndex(function(p) {
        return p.name === name;
      });
    }

    // Bundle all dependencies from the source into the target,
    // but only after removing the circular dependency itself.
    function bundleArray(target, src, name, notSelf) {
      var srcValues, targetValues;
      if (src[name]) {
        srcValues = src[name] || [];
        targetValues = target[name] || [];
        target[name] = uniq(targetValues.concat(srcValues.filter(function(d) {
          return !notSelf || d !== target.name;
        })));
      }
    }

    function bundleMap(target, src, name) {
      if (src[name]) {
        target[name] = target[name] || {};
        merge(target[name], src[name]);
      }
    }

    // Update all packages pointing to the old package.
    function updateExternalDependencies(oldName, newName) {
      sourcePackages.forEach(function(p) {
        var index = p.dependencies.indexOf(oldName);
        if (index !== -1) {
          if (p.name === newName || p.dependencies.indexOf(newName) !== -1) {
            // If the package has the same name as the one we are trying to
            // update to, then we are trying to update the package to point
            // to itself as a dependency, which isn't possible so just remove
            // the old dependency. Alternatively, if the package already has
            // the new name, then we can simply remove the old one and move on.
            p.dependencies.splice(index, 1);
          } else {
            // If the package is NOT trying to update to itself and does NOT
            // have the new dependency already, then add it in place of the
            // old one.
            p.dependencies.splice(index, 1, newName);
          }
        }
      });
    }

    function removePackage(p) {
      var index = sourcePackages.indexOf(p);
      sourcePackages.splice(index, 1);
    }

    sourcePackages.forEach(function(p) {
      var chain = findCircular(p.dependencies, []);
      if (chain) {
        bundleCircular(chain);
      }
    });
  }
function bundleCircularDependencies ( ) { function findCircular ( deps , chain ) { for ( var i = 0 , startIndex , c , p ; i < deps . length ; i ++ ) { // Only top level dependencies will be included in the chain. p = sourcePackages . findByDependencyName ( deps [ i ] ) ; if ( ! p ) { continue ; } startIndex = chain . indexOf ( p . name ) ; if ( startIndex !== - 1 ) { return chain . slice ( startIndex ) ; } else { c = findCircular ( p . dependencies , chain . concat ( p . name ) ) ; if ( c ) { return c ; } } } } function bundleCircular ( chain ) { // Sort the chain so that all packages are // bundled into the first found in the source. chain = sortChain ( chain ) ; var target = sourcePackages . findByDependencyName ( chain [ 0 ] ) ; delete target . comments ; chain . slice ( 1 ) . forEach ( function ( n ) { var src = sourcePackages . findByDependencyName ( n ) ; target . body += '\n\n' + src . body ; target . bodyWithComments += '\n\n' + src . bodyWithComments ; bundleArray ( target , src , 'dependencies' , true ) ; bundleArray ( target , src , 'varDependencies' , true ) ; bundleArray ( target , src , 'vars' ) ; bundleMap ( target , src , 'assigns' ) ; updateExternalDependencies ( src . name , target . name ) ; if ( src . type === 'build' && ( ! target . vars || ! target . vars . length ) ) { // A build function that is having it's call block being bundled // into it can also take on the type "build". This generally means // that it has no exports. However don't do this if the function is // building up variables, in which case it will have a "vars". target . type = 'build' ; } removePackage ( src ) ; } ) ; } function sortChain ( chain ) { return chain . sort ( function ( a , b ) { return getPackageIndexByName ( a ) - getPackageIndexByName ( b ) ; } ) ; } function getPackageIndexByName ( name ) { return sourcePackages . findIndex ( function ( p ) { return p . name === name ; } ) ; } // Bundle all dependencies from the source into the target, // but only after removing the circular dependency itself. function bundleArray ( target , src , name , notSelf ) { var srcValues , targetValues ; if ( src [ name ] ) { srcValues = src [ name ] || [ ] ; targetValues = target [ name ] || [ ] ; target [ name ] = uniq ( targetValues . concat ( srcValues . filter ( function ( d ) { return ! notSelf || d !== target . name ; } ) ) ) ; } } function bundleMap ( target , src , name ) { if ( src [ name ] ) { target [ name ] = target [ name ] || { } ; merge ( target [ name ] , src [ name ] ) ; } } // Update all packages pointing to the old package. function updateExternalDependencies ( oldName , newName ) { sourcePackages . forEach ( function ( p ) { var index = p . dependencies . indexOf ( oldName ) ; if ( index !== - 1 ) { if ( p . name === newName || p . dependencies . indexOf ( newName ) !== - 1 ) { // If the package has the same name as the one we are trying to // update to, then we are trying to update the package to point // to itself as a dependency, which isn't possible so just remove // the old dependency. Alternatively, if the package already has // the new name, then we can simply remove the old one and move on. p . dependencies . splice ( index , 1 ) ; } else { // If the package is NOT trying to update to itself and does NOT // have the new dependency already, then add it in place of the // old one. p . dependencies . splice ( index , 1 , newName ) ; } } } ) ; } function removePackage ( p ) { var index = sourcePackages . indexOf ( p ) ; sourcePackages . splice ( index , 1 ) ; } sourcePackages . forEach ( function ( p ) { var chain = findCircular ( p . dependencies , [ ] ) ; if ( chain ) { bundleCircular ( chain ) ; } } ) ; }
Circular dependencies are not necessarily a problem for Javascript at execution time due to having different code paths, however they don't work for npm packages, so they must be bundled together. This isn't too fancy so more complicated dependencies should be refactored. First in the source will be the target package for the bundle.
Circular dependencies are not necessarily a problem for Javascript at execution time due to having different code paths however they don t work for npm packages so they must be bundled together . This isn t too fancy so more complicated dependencies should be refactored . First in the source will be the target package for the bundle .