posts:node: Add a post on Node and npm
authorW. Trevor King <wking@tremily.us>
Fri, 20 Sep 2013 00:20:18 +0000 (17:20 -0700)
committerW. Trevor King <wking@tremily.us>
Fri, 20 Sep 2013 18:36:19 +0000 (11:36 -0700)
posts/Node.mdwn [new file with mode: 0644]

diff --git a/posts/Node.mdwn b/posts/Node.mdwn
new file mode 100644 (file)
index 0000000..5f719c0
--- /dev/null
@@ -0,0 +1,175 @@
+[Node][] is a server-side [JavaScript][] engine (i.e. it executes
+JavaScript without using a browser).  This means that JavaScript
+developers can now develop tools in their native language, so it's not
+a surprise that the [Bootstrap][] folks use [Grunt][] for their build
+system.  I'm new to the whole Node ecosystem, so here are my notes on
+how it works.
+
+Start off by installing [npm][], the Node package manager.  On Gentoo,
+that's:
+
+    # USE=npm emerge -av net-libs/nodejs
+
+[Configure npm][npm-config] to make ["global"
+installs][npm-folders-prefix] in your personal space:
+
+    # npm config set prefix ~/.local/
+
+Install the [Grunt][] command line interface for building
+[Bootstrap][]:
+
+    $ npm install -g grunt-cli
+
+That installs the libraries under `~/.local/lib/node_modules` and
+drops symlinks to binaries in `~/.local/bin` (which is [already in my
+`PATH`][PATH] thanks to my [[dotfiles]]).
+
+Clone Boostrap and [install it's
+dependencies][bootstrap-dependencies]:
+
+    $ git clone git://github.com/twbs/bootstrap.git
+    $ cd bootstrap
+    $ npm install
+
+This looks in the local [package.json][] to extract a list of
+dependencies, and [installs each of them][npm-folders] under
+[node_modules][].  Node likes to isolate its packages, so every
+dependency for a given package is installed underneath that package.
+This leads to some crazy nesting:
+
+    $ find node_modules/ -name graceful-fs
+    node_modules/grunt/node_modules/glob/node_modules/graceful-fs
+    node_modules/grunt/node_modules/rimraf/node_modules/graceful-fs
+    node_modules/grunt-contrib-clean/node_modules/rimraf/node_modules/graceful-fs
+    node_modules/grunt-contrib-qunit/node_modules/grunt-lib-phantomjs/node_modules/phantomjs/node_modules/rimraf/node_modules/graceful-fs
+    node_modules/grunt-contrib-watch/node_modules/gaze/node_modules/globule/node_modules/glob/node_modules/graceful-fs
+
+Sometimes the redundancy is due to different version requirements, but
+sometimes the redundancy is just redundant :p.  Let's look with [npm
+ls][npm-ls].
+
+    $ npm ls graceful-fs
+    bootstrap@3.0.0 /home/wking/src/bootstrap
+    ├─┬ grunt@0.4.1
+    │ ├─┬ glob@3.1.21
+    │ │ └── graceful-fs@1.2.3
+    │ └─┬ rimraf@2.0.3
+    │   └── graceful-fs@1.1.14
+    ├─┬ grunt-contrib-clean@0.5.0
+    │ └─┬ rimraf@2.2.2
+    │   └── graceful-fs@2.0.1
+    ├─┬ grunt-contrib-qunit@0.2.2
+    │ └─┬ grunt-lib-phantomjs@0.3.1
+    │   └─┬ phantomjs@1.9.2-1
+    │     └─┬ rimraf@2.0.3
+    │       └── graceful-fs@1.1.14
+    └─┬ grunt-contrib-watch@0.5.3
+      └─┬ gaze@0.4.1
+        └─┬ globule@0.1.0
+          └─┬ glob@3.1.21
+            └── graceful-fs@1.2.3
+
+Regardless of on-disk duplication, Node [caches modules][caching] so a
+given module only loads once.  If it really bothers you, you can
+[avoid some duplicates by installing duplicated packages higher up in
+the local tree][npm-folders-nesting]:
+
+    $ rm -rf node_modules
+    $ npm install graceful-fs@1.1.14
+    $ npm install
+    $ npm ls graceful-fs
+    bootstrap@3.0.0 /home/wking/src/bootstrap
+    ├── graceful-fs@1.1.14  extraneous
+    ├─┬ grunt@0.4.1
+    │ └─┬ glob@3.1.21
+    │   └── graceful-fs@1.2.3 
+    ├─┬ grunt-contrib-clean@0.5.0
+    │ └─┬ rimraf@2.2.2
+    │   └── graceful-fs@2.0.1 
+    └─┬ grunt-contrib-watch@0.5.3
+      └─┬ gaze@0.4.1
+        └─┬ globule@0.1.0
+          └─┬ glob@3.1.21
+            └── graceful-fs@1.2.3 
+
+This is probably not worth the trouble.
+
+Now that we have Grunt and the Bootstrap dependencies, we can build
+the distributed libraries:
+
+    $ ~/src/node_modules/.bin/grunt dist
+    Running "clean:dist" (clean) task
+    Cleaning dist...OK
+
+    Running "recess:bootstrap" (recess) task
+    File "dist/css/bootstrap.css" created.
+
+    Running "recess:min" (recess) task
+    File "dist/css/bootstrap.min.css" created.
+    Original: 121876 bytes.
+    Minified: 99741 bytes.
+
+    Running "recess:theme" (recess) task
+    File "dist/css/bootstrap-theme.css" created.
+
+    Running "recess:theme_min" (recess) task
+    File "dist/css/bootstrap-theme.min.css" created.
+    Original: 18956 bytes.
+    Minified: 17003 bytes.
+
+    Running "copy:fonts" (copy) task
+    Copied 4 files
+
+    Running "concat:bootstrap" (concat) task
+    File "dist/js/bootstrap.js" created.
+
+    Running "uglify:bootstrap" (uglify) task
+    File "dist/js/bootstrap.min.js" created.
+    Original: 58543 bytes.
+    Minified: 27811 bytes.
+
+    Done, without errors.
+
+Wohoo!
+
+Unfortunately, like all [language-specific][pypi] [packing][gem]
+[systems][cpan], npm has trouble installing packages that aren't
+written in its native language.  This means you get things like:
+
+    $ ~/src/node_modules/.bin/grunt
+    …
+    Running "jekyll:docs" (jekyll) task
+    `jekyll build` was initiated.
+
+    Jekyll output:
+    Warning: Command failed: /bin/sh: jekyll: command not found
+     Use --force to continue.
+
+    Aborted due to warnings.
+
+Once everybody wises up and starts writing packages for [[Gentoo
+Prefix|Gentoo_Prefix_overlay]], we can stop worrying about
+installation and get back to work developing :p.
+
+[[!tag tags/programming]]
+[[!tag tags/tools]]
+[[!tag tags/web]]
+
+[Node]: http://nodejs.org/
+[JavaScript]: http://en.wikipedia.org/wiki/JavaScript
+[Bootstrap]: http://getbootstrap.com/
+[Grunt]: http://gruntjs.com/
+[npm]: https://npmjs.org/
+[npm-folders]: https://npmjs.org/doc/files/npm-folders.html
+[npm-folders-prefix]: https://npmjs.org/doc/files/npm-folders.html#prefix-Configuration
+[npm-folders-nesting]: https://npmjs.org/doc/files/npm-folders.html#Cycles-Conflicts-and-Folder-Parsimony
+[npm-config]: https://npmjs.org/doc/config.html
+[PATH]: http://git.tremily.us/?p=dotfiles-public.git;a=blob;f=src/.bash_profile;hb=HEAD
+[bootstrap-dependencies]: https://github.com/twbs/bootstrap/blob/master/README.md#install-grunt
+[package.json]: https://npmjs.org/doc/json.html
+[node_modules]: http://nodejs.org/api/modules.html#modules_loading_from_node_modules_folders
+[npm-ls]: https://npmjs.org/doc/cli/npm-ls.html
+[caching]: http://nodejs.org/api/modules.html#modules_caching
+[pypi]: https://pypi.python.org/pypi
+[gem]: http://rubygems.org/
+[cpan]: http://www.cpan.org/