function buildModule(module, opts) {
  opts = opts || {};
  if (module.indexOf(".") < 0) {
    module = "material.components." + module;
  }
  gutil.log('Building ' + module + (opts.isRelease && ' minified' || '') + ' ...');

  const name = module.split('.').pop();
  utils.copyDemoAssets(name, 'src/components/', 'dist/demos/');

  let stream = utils.filesForModule(module)
  .pipe(filterNonCodeFiles())
  .pipe(filterLayoutAttrFiles())
  .pipe(gulpif('*.scss', buildModuleStyles(name)))
  .pipe(gulpif('*.js', buildModuleJs(name)));

  if (module === 'material.core') {
    stream = splitStream(stream);
  }

  return stream
  .pipe(BUILD_MODE.transform())
  .pipe(insert.prepend(config.banner))
  .pipe(gulpif(opts.minify, buildMin()))
  .pipe(gulpif(opts.useBower, buildBower()))
  .pipe(gulp.dest(BUILD_MODE.outputDir + name));

  function splitStream(stream) {
    const js = series(stream, themeBuildStream())
    .pipe(filter('**/*.js'))
    .pipe(concat('core.js'));

    const css = stream
    .pipe(filter(['**/*.css', '!**/ie_fixes.css']));

    return series(js, css);
  }

  function buildMin() {
    return lazypipe()
    .pipe(gulpif, /.css$/, minifyCss(),
      uglify({output: {comments: 'some'}})
      .on('error', function(e) {
          console.log('\x07', e.message);
          return this.end();
        }
      )
    )
    .pipe(rename, function(path) {
      path.extname = path.extname
      .replace(/.js$/, '.min.js')
      .replace(/.css$/, '.min.css');
    })
    ();
  }

  function buildBower() {
    return lazypipe()
    .pipe(utils.buildModuleBower, name, VERSION)();
  }

  function buildModuleJs(name) {
    const patterns = [
      {
        pattern: /@ngInject/g,
        replacement: 'ngInject'
      },
      {
        // Turns `thing.$inject` into `thing['$inject']` in order to prevent
        // Closure from stripping it from objects with an @constructor
        // annotation.
        pattern: /\.\$inject\b/g,
        replacement: "['$inject']"
      }
    ];
    return lazypipe()
    .pipe(plumber)
    .pipe(ngAnnotate)
    .pipe(frep, patterns)
    .pipe(concat, name + '.js')
    ();
  }

  /**
   * @param {string} name module name. I.e. 'select', 'dialog', etc.
   * @returns {*}
   */
  function buildModuleStyles(name) {
    let files = [];
    const inputVariableConsumers = [
      'input', 'select', 'checkbox', 'datepicker', 'radioButton', 'switch'
    ];
    config.themeBaseFiles.forEach(function(fileGlob) {
      files = files.concat(glob(fileGlob, {cwd: ROOT}));
    });

    // Handle md-input and md-input-container variables that need to be shared with md-select
    // in order to orchestrate identical layouts and alignments. In the future, it may be necessary
    // to also use these variables with md-datepicker and md-autocomplete.
    if (inputVariableConsumers.includes(name)) {
      files = files.concat(glob(config.inputVariables, {cwd: ROOT}));
    }

    const baseStyles = files.map(function(fileName) {
      return fs.readFileSync(fileName, 'utf8').toString();
    }).join('\n');

    let sassModules;
    // Don't add the Sass modules to core since they get automatically included already.
    if (name === 'core') {
      sassModules = '';
    } else {
      sassModules = fs.readFileSync(config.scssModules, 'utf8').toString();
    }

    return lazypipe()
    .pipe(insert.prepend, baseStyles)
    .pipe(gulpif, /theme.scss/, rename(name + '-default-theme.scss'), concat(name + '.scss'))
    // Theme files are suffixed with the `default-theme.scss` string.
    // In some cases there are multiple theme SCSS files, which should be concatenated together.
    .pipe(gulpif, /default-theme.scss/, concat(name + '-default-theme.scss'))
    // We can't prepend these earlier, or they get duplicated in a way that hoistScssAtUseStatements
    // can't deduplicate them.
    .pipe(insert.prepend, sassModules)
    .pipe(utils.hoistScssAtUseStatements)
    .pipe(sass)
    .pipe(dedupeCss)
    .pipe(utils.autoprefix)
    (); // Invoke the returning lazypipe function to create our new pipe.
  }
}
@param {string} module
@param {{isRelease, minify, useBower}=} opts