1<section xmlns="http://docbook.org/ns/docbook"
2 xmlns:xlink="http://www.w3.org/1999/xlink"
3 xml:id="sec-bower">
4 <title>Bower</title>
5
6 <para>
7 <link xlink:href="http://bower.io">Bower</link> is a package manager for web
8 site front-end components. Bower packages (comprising of build artefacts and
9 sometimes sources) are stored in <command>git</command> repositories,
10 typically on Github. The package registry is run by the Bower team with
11 package metadata coming from the <filename>bower.json</filename> file within
12 each package.
13 </para>
14
15 <para>
16 The end result of running Bower is a <filename>bower_components</filename>
17 directory which can be included in the web app's build process.
18 </para>
19
20 <para>
21 Bower can be run interactively, by installing
22 <varname>nodePackages.bower</varname>. More interestingly, the Bower
23 components can be declared in a Nix derivation, with the help of
24 <varname>nodePackages.bower2nix</varname>.
25 </para>
26
27 <section xml:id="ssec-bower2nix-usage">
28 <title><command>bower2nix</command> usage</title>
29
30 <para>
31 Suppose you have a <filename>bower.json</filename> with the following
32 contents:
33 <example xml:id="ex-bowerJson">
34 <title><filename>bower.json</filename></title>
35<programlisting language="json">
36<![CDATA[{
37 "name": "my-web-app",
38 "dependencies": {
39 "angular": "~1.5.0",
40 "bootstrap": "~3.3.6"
41 }
42}]]>
43</programlisting>
44 </example>
45 </para>
46
47 <para>
48 Running <command>bower2nix</command> will produce something like the
49 following output:
50<programlisting language="nix">
51<![CDATA[{ fetchbower, buildEnv }:
52buildEnv { name = "bower-env"; ignoreCollisions = true; paths = [
53 (fetchbower "angular" "1.5.3" "~1.5.0" "1749xb0firxdra4rzadm4q9x90v6pzkbd7xmcyjk6qfza09ykk9y")
54 (fetchbower "bootstrap" "3.3.6" "~3.3.6" "1vvqlpbfcy0k5pncfjaiskj3y6scwifxygfqnw393sjfxiviwmbv")
55 (fetchbower "jquery" "2.2.2" "1.9.1 - 2" "10sp5h98sqwk90y4k6hbdviwqzvzwqf47r3r51pakch5ii2y7js1")
56]; }]]>
57</programlisting>
58 </para>
59
60 <para>
61 Using the <command>bower2nix</command> command line arguments, the output
62 can be redirected to a file. A name like
63 <filename>bower-packages.nix</filename> would be fine.
64 </para>
65
66 <para>
67 The resulting derivation is a union of all the downloaded Bower packages
68 (and their dependencies). To use it, they still need to be linked together
69 by Bower, which is where <varname>buildBowerComponents</varname> is useful.
70 </para>
71 </section>
72
73 <section xml:id="ssec-build-bower-components">
74 <title><varname>buildBowerComponents</varname> function</title>
75
76 <para>
77 The function is implemented in
78 <link xlink:href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/bower-modules/generic/default.nix">
79 <filename>pkgs/development/bower-modules/generic/default.nix</filename></link>.
80 Example usage:
81 <example xml:id="ex-buildBowerComponents">
82 <title>buildBowerComponents</title>
83<programlisting language="nix">
84bowerComponents = buildBowerComponents {
85 name = "my-web-app";
86 generated = ./bower-packages.nix; <co xml:id="ex-buildBowerComponents-1" />
87 src = myWebApp; <co xml:id="ex-buildBowerComponents-2" />
88};
89</programlisting>
90 </example>
91 </para>
92
93 <para>
94 In <xref linkend="ex-buildBowerComponents" />, the following arguments are
95 of special significance to the function:
96 <calloutlist>
97 <callout arearefs="ex-buildBowerComponents-1">
98 <para>
99 <varname>generated</varname> specifies the file which was created by
100 <command>bower2nix</command>.
101 </para>
102 </callout>
103 <callout arearefs="ex-buildBowerComponents-2">
104 <para>
105 <varname>src</varname> is your project's sources. It needs to contain a
106 <filename>bower.json</filename> file.
107 </para>
108 </callout>
109 </calloutlist>
110 </para>
111
112 <para>
113 <varname>buildBowerComponents</varname> will run Bower to link together the
114 output of <command>bower2nix</command>, resulting in a
115 <filename>bower_components</filename> directory which can be used.
116 </para>
117
118 <para>
119 Here is an example of a web frontend build process using
120 <command>gulp</command>. You might use <command>grunt</command>, or anything
121 else.
122 </para>
123
124 <example xml:id="ex-bowerGulpFile">
125 <title>Example build script (<filename>gulpfile.js</filename>)</title>
126<programlisting language="javascript">
127<![CDATA[var gulp = require('gulp');
128
129gulp.task('default', [], function () {
130 gulp.start('build');
131});
132
133gulp.task('build', [], function () {
134 console.log("Just a dummy gulp build");
135 gulp
136 .src(["./bower_components/**/*"])
137 .pipe(gulp.dest("./gulpdist/"));
138});]]>
139</programlisting>
140 </example>
141
142 <example xml:id="ex-buildBowerComponentsDefaultNix">
143 <title>Full example — <filename>default.nix</filename></title>
144<programlisting language="nix">
145{ myWebApp ? { outPath = ./.; name = "myWebApp"; }
146, pkgs ? import <nixpkgs> {}
147}:
148
149pkgs.stdenv.mkDerivation {
150 name = "my-web-app-frontend";
151 src = myWebApp;
152
153 buildInputs = [ pkgs.nodePackages.gulp ];
154
155 bowerComponents = pkgs.buildBowerComponents { <co xml:id="ex-buildBowerComponentsDefault-1" />
156 name = "my-web-app";
157 generated = ./bower-packages.nix;
158 src = myWebApp;
159 };
160
161 buildPhase = ''
162 cp --reflink=auto --no-preserve=mode -R $bowerComponents/bower_components . <co xml:id="ex-buildBowerComponentsDefault-2" />
163 export HOME=$PWD <co xml:id="ex-buildBowerComponentsDefault-3" />
164 ${pkgs.nodePackages.gulp}/bin/gulp build <co xml:id="ex-buildBowerComponentsDefault-4" />
165 '';
166
167 installPhase = "mv gulpdist $out";
168}
169</programlisting>
170 </example>
171
172 <para>
173 A few notes about <xref linkend="ex-buildBowerComponentsDefaultNix" />:
174 <calloutlist>
175 <callout arearefs="ex-buildBowerComponentsDefault-1">
176 <para>
177 The result of <varname>buildBowerComponents</varname> is an input to the
178 frontend build.
179 </para>
180 </callout>
181 <callout arearefs="ex-buildBowerComponentsDefault-2">
182 <para>
183 Whether to symlink or copy the <filename>bower_components</filename>
184 directory depends on the build tool in use. In this case a copy is used
185 to avoid <command>gulp</command> silliness with permissions.
186 </para>
187 </callout>
188 <callout arearefs="ex-buildBowerComponentsDefault-3">
189 <para>
190 <command>gulp</command> requires <varname>HOME</varname> to refer to a
191 writeable directory.
192 </para>
193 </callout>
194 <callout arearefs="ex-buildBowerComponentsDefault-4">
195 <para>
196 The actual build command. Other tools could be used.
197 </para>
198 </callout>
199 </calloutlist>
200 </para>
201 </section>
202
203 <section xml:id="ssec-bower2nix-troubleshooting">
204 <title>Troubleshooting</title>
205
206 <variablelist>
207 <varlistentry>
208 <term>
209 <literal>ENOCACHE</literal> errors from <varname>buildBowerComponents</varname>
210 </term>
211 <listitem>
212 <para>
213 This means that Bower was looking for a package version which doesn't
214 exist in the generated <filename>bower-packages.nix</filename>.
215 </para>
216 <para>
217 If <filename>bower.json</filename> has been updated, then run
218 <command>bower2nix</command> again.
219 </para>
220 <para>
221 It could also be a bug in <command>bower2nix</command> or
222 <command>fetchbower</command>. If possible, try reformulating the version
223 specification in <filename>bower.json</filename>.
224 </para>
225 </listitem>
226 </varlistentry>
227 </variablelist>
228 </section>
229</section>