<section xmlns="http://docbook.org/ns/docbook"
         xmlns:xlink="http://www.w3.org/1999/xlink"
         xml:id="sec-bower">

<title>Bower</title>

<para>
  <link xlink:href="http://bower.io">Bower</link> is a package manager
  for web site front-end components. Bower packages (comprising of
  build artefacts and sometimes sources) are stored in
  <command>git</command> repositories, typically on Github. The
  package registry is run by the Bower team with package metadata
  coming from the <filename>bower.json</filename> file within each
  package.
</para>

<para>
  The end result of running Bower is a
  <filename>bower_components</filename> directory which can be included
  in the web app's build process.
</para>

<para>
  Bower can be run interactively, by installing
  <varname>nodePackages.bower</varname>. More interestingly, the Bower
  components can be declared in a Nix derivation, with the help of
  <varname>nodePackages.bower2nix</varname>.
</para>

<section xml:id="ssec-bower2nix-usage">
  <title><command>bower2nix</command> usage</title>

<para>
  Suppose you have a <filename>bower.json</filename> with the following contents:


<example xml:id="ex-bowerJson"><title><filename>bower.json</filename></title>
<programlisting language="json">
<![CDATA[{
  "name": "my-web-app",
  "dependencies": {
    "angular": "~1.5.0",
    "bootstrap": "~3.3.6"
  }
}]]>
</programlisting>
</example>
</para>


<para>
  Running <command>bower2nix</command> will produce something like the
  following output:

<programlisting language="nix">
<![CDATA[{ fetchbower, buildEnv }:
buildEnv { name = "bower-env"; ignoreCollisions = true; paths = [
  (fetchbower "angular" "1.5.3" "~1.5.0" "1749xb0firxdra4rzadm4q9x90v6pzkbd7xmcyjk6qfza09ykk9y")
  (fetchbower "bootstrap" "3.3.6" "~3.3.6" "1vvqlpbfcy0k5pncfjaiskj3y6scwifxygfqnw393sjfxiviwmbv")
  (fetchbower "jquery" "2.2.2" "1.9.1 - 2" "10sp5h98sqwk90y4k6hbdviwqzvzwqf47r3r51pakch5ii2y7js1")
]; }]]>
</programlisting>
</para>


<para>
  Using the <command>bower2nix</command> command line arguments, the
  output can be redirected to a file. A name like
  <filename>bower-packages.nix</filename> would be fine.
</para>

<para>
  The resulting derivation is a union of all the downloaded Bower
  packages (and their dependencies). To use it, they still need to be
  linked together by Bower, which is where
  <varname>buildBowerComponents</varname> is useful.
</para>
</section>

<section xml:id="ssec-build-bower-components"><title><varname>buildBowerComponents</varname> function</title>

  <para>
  The function is implemented in <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/bower-modules/generic/default.nix">
  <filename>pkgs/development/bower-modules/generic/default.nix</filename></link>.
  Example usage:

<example xml:id="ex-buildBowerComponents"><title>buildBowerComponents</title>
<programlisting language="nix">
bowerComponents = buildBowerComponents {
  name = "my-web-app";
  generated = ./bower-packages.nix; <co xml:id="ex-buildBowerComponents-1" />
  src = myWebApp; <co xml:id="ex-buildBowerComponents-2" />
};
</programlisting>
</example>
  </para>

<para>
In <xref linkend="ex-buildBowerComponents" />, the following arguments
are of special significance to the function:

<calloutlist>
  <callout arearefs="ex-buildBowerComponents-1">
    <para>
      <varname>generated</varname> specifies the file which was created by <command>bower2nix</command>.
    </para>
  </callout>

  <callout arearefs="ex-buildBowerComponents-2">
    <para>
      <varname>src</varname> is your project's sources. It needs to
      contain a <filename>bower.json</filename> file.
    </para>
  </callout>
</calloutlist>
</para>

<para>
  <varname>buildBowerComponents</varname> will run Bower to link
  together the output of <command>bower2nix</command>, resulting in a
  <filename>bower_components</filename> directory which can be used.
</para>

<para>
  Here is an example of a web frontend build process using
  <command>gulp</command>. You might use <command>grunt</command>, or
  anything else.
</para>

<example xml:id="ex-bowerGulpFile"><title>Example build script (<filename>gulpfile.js</filename>)</title>
<programlisting language="javascript">
<![CDATA[var gulp = require('gulp');

gulp.task('default', [], function () {
  gulp.start('build');
});

gulp.task('build', [], function () {
  console.log("Just a dummy gulp build");
  gulp
    .src(["./bower_components/**/*"])
    .pipe(gulp.dest("./gulpdist/"));
});]]>
</programlisting>
</example>

<example xml:id="ex-buildBowerComponentsDefaultNix">
  <title>Full example — <filename>default.nix</filename></title>
<programlisting language="nix">
{ myWebApp ? { outPath = ./.; name = "myWebApp"; }
, pkgs ? import &lt;nixpkgs&gt; {}
}:

pkgs.stdenv.mkDerivation {
  name = "my-web-app-frontend";
  src = myWebApp;

  buildInputs = [ pkgs.nodePackages.gulp ];

  bowerComponents = pkgs.buildBowerComponents { <co xml:id="ex-buildBowerComponentsDefault-1" />
    name = "my-web-app";
    generated = ./bower-packages.nix;
    src = myWebApp;
  };

  buildPhase = ''
    cp --reflink=auto --no-preserve=mode -R $bowerComponents/bower_components . <co xml:id="ex-buildBowerComponentsDefault-2" />
    export HOME=$PWD <co xml:id="ex-buildBowerComponentsDefault-3" />
    ${pkgs.nodePackages.gulp}/bin/gulp build <co xml:id="ex-buildBowerComponentsDefault-4" />
  '';

  installPhase = "mv gulpdist $out";
}
</programlisting>
</example>

<para>
A few notes about <xref linkend="ex-buildBowerComponentsDefaultNix" />:

<calloutlist>
  <callout arearefs="ex-buildBowerComponentsDefault-1">
    <para>
      The result of <varname>buildBowerComponents</varname> is an
      input to the frontend build.
    </para>
  </callout>

  <callout arearefs="ex-buildBowerComponentsDefault-2">
    <para>
      Whether to symlink or copy the
      <filename>bower_components</filename> directory depends on the
      build tool in use. In this case a copy is used to avoid
      <command>gulp</command> silliness with permissions.
    </para>
  </callout>

  <callout arearefs="ex-buildBowerComponentsDefault-3">
    <para>
      <command>gulp</command> requires <varname>HOME</varname> to
      refer to a writeable directory.
    </para>
  </callout>

  <callout arearefs="ex-buildBowerComponentsDefault-4">
    <para>
      The actual build command. Other tools could be used.
    </para>
  </callout>
</calloutlist>
</para>
</section>

<section xml:id="ssec-bower2nix-troubleshooting">
  <title>Troubleshooting</title>

<variablelist>

  <varlistentry>
    <term>
    <literal>ENOCACHE</literal> errors from
    <varname>buildBowerComponents</varname>
    </term>
    <listitem>
      <para>
        This means that Bower was looking for a package version which
        doesn't exist in the generated
        <filename>bower-packages.nix</filename>.
      </para>
      <para>
        If <filename>bower.json</filename> has been updated, then run
        <command>bower2nix</command> again.
      </para>
      <para>
        It could also be a bug in <command>bower2nix</command> or
        <command>fetchbower</command>. If possible, try reformulating
        the version specification in <filename>bower.json</filename>.
      </para>
    </listitem>
  </varlistentry>
</variablelist>

</section>

</section>
