lib/plugins/package/lib/zipService.js/excludeNodeDevDependencies
function excludeNodeDevDependencies(servicePath) {
  const exAndIn = {
    include: [],
    exclude: [],
  };

  // the files where we'll write the dependencies into
  const tmpDir = os.tmpdir();
  const randHash = crypto.randomBytes(8).toString('hex');
  const nodeDevDepFile = path.join(tmpDir, `node-dependencies-${randHash}-dev`);
  const nodeProdDepFile = path.join(tmpDir, `node-dependencies-${randHash}-prod`);

  try {
    const packageJsonFilePaths = globby.sync([
      '**/package.json',
      // TODO add glob for node_modules filtering
    ], {
      cwd: servicePath,
      dot: true,
      silent: true,
      follow: true,
      nosort: true,
    });

    // filter out non node_modules file paths
    const packageJsonPaths = _.filter(packageJsonFilePaths, (filePath) => {
      const isNodeModulesDir = !!filePath.match(/node_modules/);
      return !isNodeModulesDir;
    });

    if (_.isEmpty(packageJsonPaths)) {
      return BbPromise.resolve(exAndIn);
    }

    // NOTE: using mapSeries here for a sequential computation (w/o race conditions)
    return BbPromise.mapSeries(packageJsonPaths, (packageJsonPath) => {
      // the path where the package.json file lives
      const fullPath = path.join(servicePath, packageJsonPath);
      const dirWithPackageJson = fullPath.replace(path.join(path.sep, 'package.json'), '');

      // we added a catch which resolves so that npm commands with an exit code of 1
      // (e.g. if the package.json is invalid) won't crash the dev dependency exclusion process
      return BbPromise.map(['dev', 'prod'], (env) => {
        const depFile = env === 'dev' ? nodeDevDepFile : nodeProdDepFile;
        return childProcess.execAsync(
          `npm ls --${env}=true --parseable=true --long=false --silent >> ${depFile}`,
          { cwd: dirWithPackageJson }
        ).catch(() => BbPromise.resolve());
      });
    })
    // NOTE: using mapSeries here for a sequential computation (w/o race conditions)
    .then(() => BbPromise.mapSeries(['dev', 'prod'], (env) => {
      const depFile = env === 'dev' ? nodeDevDepFile : nodeProdDepFile;
      return fs.readFileAsync(depFile)
        .then((fileContent) => _.compact(
          (_.uniq(_.split(fileContent.toString('utf8'), '\n'))),
          elem => elem.length > 0
        )).catch(() => BbPromise.resolve());
    }))
    .then((devAndProDependencies) => {
      const devDependencies = devAndProDependencies[0];
      const prodDependencies = devAndProDependencies[1];

      // NOTE: the order for _.difference is important
      const dependencies = _.difference(devDependencies, prodDependencies);
      const nodeModulesRegex = new RegExp(`${path.join('node_modules', path.sep)}.*`, 'g');

      if (!_.isEmpty(dependencies)) {
        return BbPromise
          .map(dependencies, (item) => item.replace(path.join(servicePath, path.sep), ''))
          .filter((item) => item.length > 0 && item.match(nodeModulesRegex))
          .reduce((globs, item) => {
            const packagePath = path.join(servicePath, item, 'package.json');
            return fs.readFileAsync(packagePath, 'utf-8').then((packageJsonFile) => {
              const lastIndex = item.lastIndexOf(path.sep) + 1;
              const moduleName = item.substr(lastIndex);
              const modulePath = item.substr(0, lastIndex);

              const packageJson = JSON.parse(packageJsonFile);
              const bin = packageJson.bin;

              const baseGlobs = [path.join(item, '**')];

              // NOTE: pkg.bin can be object, string, or undefined
              if (typeof bin === 'object') {
                _.each(_.keys(bin), (executable) => {
                  baseGlobs.push(path.join(modulePath, '.bin', executable));
                });
              // only 1 executable with same name as lib
              } else if (typeof bin === 'string') {
                baseGlobs.push(path.join(modulePath, '.bin', moduleName));
              }

              return globs.concat(baseGlobs);
            });
          }, [])
          .then((globs) => {
            exAndIn.exclude = exAndIn.exclude.concat(globs);
            return exAndIn;
          });
      }

      return exAndIn;
    })
    .catch(() => exAndIn);
  } catch (e) {
    // fail silently
  }
}