goreutils/gore-gulp

View on GitHub
webpack/index.js

Summary

Maintainability
B
5 hrs
Test Coverage
/**
 * Copyright (c) 2015-present, goreutils
 * All rights reserved.
 *
 * This source code is licensed under the MIT-style license found in the
 * LICENSE file in the root directory of this source tree.
 */

'use strict';

/* eslint-disable max-len */
const chunk = require('lodash/chunk');
const ecmaScriptFileExtensions = require('../src/pckg/ecmaScriptFileExtensions');
const ecmaScriptFileExtensionsGlobPattern = require('../src/pckg/ecmaScriptFileExtensionsGlobPattern');
const endsWith = require('lodash/endsWith');
const flatten = require('lodash/flatten');
const glob = require('ultra-glob');
const groupBy = require('lodash/groupBy');
const gutil = require('gulp-util');
const kebabCase = require('lodash/kebabCase');
const libDirs = require('../src/pckg/libDirs');
const map = require('lodash/map');
const mapValues = require('lodash/mapValues');
const MissingBabelPluginErrorHandle = require('./MissingBabelPluginErrorHandle');
const os = require('os');
const path = require('path');
const Promise = require('bluebird');
const reduce = require('lodash/reduce');
const values = require('lodash/values');
const workerFarm = require('worker-farm');
/* eslint-enable max-len */

const cpus = os.cpus();

function normalizeEntry(config, pckg, libDir, entry, fileExtensions) {
  for (let i = 0; i < fileExtensions.length; i += 1) {
    const fileExtension = `.entry${fileExtensions[i]}`;

    if (endsWith(entry, fileExtension)) {
      let entryPointStem = path.relative(path.resolve(config.baseDir, libDir), entry);
      // replace all path.sep with spaces for more meaningful slugss
      entryPointStem = entryPointStem.split(path.sep).join(' ');
      entryPointStem = entryPointStem.substr(0, entryPointStem.length - fileExtension.length);

      return kebabCase(entryPointStem);
    }
  }

  return entry;
}

function normalizeEntries(config, pckg, libDir, entries) {
  const ret = {};

  for (let i = 0; i < entries.length; i += 1) {
    ret[
      normalizeEntry(config, pckg, libDir, entries[i], ecmaScriptFileExtensions(pckg))
    ] = entries[i];
  }

  return ret;
}

function groupEntries(config, pckg) {
  return Promise.all(map(libDirs(pckg), libDir => {
    const pattern = path.resolve(
      config.baseDir,
      libDir,
      '**',
      `*.entry${ecmaScriptFileExtensionsGlobPattern(pckg)}`
    );

    return glob(pattern).then(entries => (
      map(entries, entry => ({
        entry,
        libDir,
        pckg,
      }))
    ));
  }))
  .then(results => flatten(results))
  .then(results => groupBy(results, 'libDir'))
  .then(results => values(mapValues(results, entryPoints => {
    const chunkLength = Math.ceil(entryPoints.length / cpus.length);

    return chunk(entryPoints, chunkLength);
  })))
  .then(results => (
    map(results, entryPointsChunk => (
      map(entryPointsChunk, entryPoints => (
        reduce(entryPoints, (acc, entryPoint) => ({
          entries: acc.entries.concat(entryPoint.entry),
          libDir: entryPoint.libDir,
          pckg: entryPoint.pckg,
        }), {
          entries: [],
          libDir: null,
          pckg: null,
        })
      ))
    ))
  ))
  .then(results => flatten(results))
  .then(results => map(results, result => ({
    entries: normalizeEntries(config, result.pckg, result.libDir, result.entries),
    pckg: result.pckg,
  })));
}

function createVariant(variant) {
  return function webpack(config, pckg) {
    const runnerPath = require.resolve(path.resolve(__dirname, 'forkableRunner'));
    const workers = workerFarm(runnerPath);

    return groupEntries(config, pckg)
      .then(results => (
        results.map(result => (
          Promise.fromCallback(callback => (
            workers({
              config: {
                baseDir: config.baseDir,
                developmentDevtool: config.developmentDevtool,
                productionDevtool: config.productionDevtool,
              },
              entries: result.entries,
              pckg: result.pckg,
              variant,
            }, callback)
          ))
        ))
      ))
      .then(webpackConfigList => Promise.all(webpackConfigList))
      .catch(err => {
        if (!MissingBabelPluginErrorHandle.isMissingPluginError(err)) {
          throw err;
        }

        return new MissingBabelPluginErrorHandle(err)
          .createMissingPluginMessage()
          .then(msg => gutil.log(msg))
          .then(() => {
            throw err
          })
        ;
      })
      .finally(() => workerFarm.end(workers))
    ;
  };
}

module.exports = {
  development: createVariant('development'),
  production: createVariant('production'),
};