···
1
+
<section xmlns="http://docbook.org/ns/docbook"
2
+
xmlns:xlink="http://www.w3.org/1999/xlink"
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
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.
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>.
30
+
<section xml:id="ssec-bower2nix-usage">
31
+
<title><command>bower2nix</command> usage</title>
34
+
Suppose you have a <filename>bower.json</filename> with the following contents:
37
+
<example xml:id="ex-bowerJson"><title><filename>bower.json</filename></title>
38
+
<programlisting language="json">
40
+
"name": "my-web-app",
42
+
"angular": "~1.5.0",
43
+
"bootstrap": "~3.3.6"
52
+
Running <command>bower2nix</command> will produce something like the
55
+
<programlisting language="nix">
56
+
<![CDATA[{ fetchbower, buildEnv }:
57
+
buildEnv { 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")
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.
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.
80
+
<section xml:id="ssec-build-bower-components"><title><varname>buildBowerComponents</varname> function</title>
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>.
87
+
<example xml:id="ex-buildBowerComponents"><title>buildBowerComponents</title>
88
+
<programlisting language="nix">
89
+
bowerComponents = 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" />
99
+
In <xref linkend="ex-buildBowerComponents" />, the following arguments
100
+
are of special significance to the function:
103
+
<callout arearefs="ex-buildBowerComponents-1">
105
+
<varname>generated</varname> specifies the file which was created by <command>bower2nix</command>.
109
+
<callout arearefs="ex-buildBowerComponents-2">
111
+
<varname>src</varname> is your project's sources. It needs to
112
+
contain a <filename>bower.json</filename> file.
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.
125
+
Here is an example of a web frontend build process using
126
+
<command>gulp</command>. You might use <command>grunt</command>, or
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');
134
+
gulp.task('default', [], function () {
135
+
gulp.start('build');
138
+
gulp.task('build', [], function () {
139
+
console.log("Just a dummy gulp build");
141
+
.src(["./bower_components/**/*"])
142
+
.pipe(gulp.dest("./gulpdist/"));
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> {}
154
+
pkgs.stdenv.mkDerivation {
155
+
name = "my-web-app-frontend";
158
+
buildInputs = [ pkgs.nodePackages.gulp ];
160
+
bowerComponents = pkgs.buildBowerComponents { <co xml:id="ex-buildBowerComponentsDefault-1" />
161
+
name = "my-web-app";
162
+
generated = ./bower-packages.nix;
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" />
172
+
installPhase = "mv gulpdist $out";
178
+
A few notes about <xref linkend="ex-buildBowerComponentsDefaultNix" />:
181
+
<callout arearefs="ex-buildBowerComponentsDefault-1">
183
+
The result of <varname>buildBowerComponents</varname> is an
184
+
input to the frontend build.
188
+
<callout arearefs="ex-buildBowerComponentsDefault-2">
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.
197
+
<callout arearefs="ex-buildBowerComponentsDefault-3">
199
+
<command>gulp</command> requires <varname>HOME</varname> to
200
+
refer to a writeable directory.
204
+
<callout arearefs="ex-buildBowerComponentsDefault-4">
206
+
The actual build command. Other tools could be used.
213
+
<section xml:id="ssec-bower2nix-troubleshooting">
214
+
<title>Troubleshooting</title>
220
+
<literal>ENOCACHE</literal> errors from
221
+
<varname>buildBowerComponents</varname>
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>.
230
+
If <filename>bower.json</filename> has been updated, then run
231
+
<command>bower2nix</command> again.
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>.