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