<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>York Solutions, LLC</title>
    <description>Justin York is a full-stack web developer based in Monett, Missouri. He has a love for JavaScript and a unique expertise in using the FamilySearch API.
</description>
    <link>http://york.io/</link>
    <atom:link href="http://york.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Wed, 28 Jun 2017 17:46:53 +0000</pubDate>
    <lastBuildDate>Wed, 28 Jun 2017 17:46:53 +0000</lastBuildDate>
    <generator>Jekyll v3.4.3</generator>
    
      <item>
        <title>unpkg - A CDN for npm packages</title>
        <description>&lt;p&gt;Now we can stop the deadly sin of committing our assets to git for 
&lt;a href=&quot;https://bower.io/&quot;&gt;Bower&lt;/a&gt;, &lt;a href=&quot;https://cdnjs.com/&quot;&gt;CDNJS&lt;/a&gt;, and 
&lt;a href=&quot;http://www.jsdelivr.com/&quot;&gt;jsDelivr&lt;/a&gt;. Instead let’s use &lt;a href=&quot;https://unpkg.com/#/&quot;&gt;unpkg&lt;/a&gt;, 
a CDN for npm.&lt;/p&gt;

&lt;p&gt;We typically think of npm as a package manager for node modules written in
plain JS that will run without any compilation, but npm is actually built to
support the publishing of compiled and packaged assets. This is useful for
compiling CoffeeScript or transpiling ES2015. In fact, npm allows us to publish
anything. So lets publish our client-side assets there too.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://unpkg.com/#/&quot;&gt;unpkg&lt;/a&gt; is a CDN that runs in front of npm. Any package
published on npm is available through unpkg. Assets are accessed through URLs
using this simple format: &lt;code class=&quot;highlighter-rouge&quot;&gt;https://unpkg.com/package@version/file&lt;/code&gt;. For example,
&lt;code class=&quot;highlighter-rouge&quot;&gt;https://unpkg.com/lodash@4.17.2/lodash.min.js&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Generate a UMD package using your favorite build tool.&lt;/li&gt;
  &lt;li&gt;Add your packaged assets to &lt;code class=&quot;highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt; so it’s not commited to git.&lt;/li&gt;
  &lt;li&gt;Add your packaged assets to the &lt;code class=&quot;highlighter-rouge&quot;&gt;files&lt;/code&gt; array in &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; so they’re
part of the package published to npm.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It’s simple and beautiful. &lt;a href=&quot;https://unpkg.com/#/&quot;&gt;unpkg&lt;/a&gt; is now my preferred CDN.&lt;/p&gt;
</description>
        <pubDate>Wed, 30 Nov 2016 00:00:00 +0000</pubDate>
        <link>http://york.io/2016/11/30/unpkg-npm-cdn-assets.html</link>
        <guid isPermaLink="true">http://york.io/2016/11/30/unpkg-npm-cdn-assets.html</guid>
        
        
      </item>
    
      <item>
        <title>Element.querySelector() Evaluates the Entire DOM</title>
        <description>&lt;p&gt;I used to think that &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Element.querySelector()&lt;/code&gt;&lt;/a&gt;
and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelectorAll&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Element.querySelectorAll()&lt;/code&gt;&lt;/a&gt;
worked like &lt;a href=&quot;https://api.jquery.com/find/&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;jQuery.find()&lt;/code&gt;&lt;/a&gt; in that they would
evaluate a CSS selector against an element’s descendants. But today I learned
that they are not the same.&lt;/p&gt;

&lt;p&gt;Instead of evaluating selectors against an element’s descendants, &lt;code class=&quot;highlighter-rouge&quot;&gt;querySelector()&lt;/code&gt;
and &lt;code class=&quot;highlighter-rouge&quot;&gt;querySelectorAll()&lt;/code&gt; evaluate selectors against the entire DOM then filter
the results to those that are descendants of the base element.&lt;/p&gt;

&lt;p&gt;Consider the following example, inspired by MDN.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Some &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&amp;gt;&lt;/span&gt;paragraph&lt;span class=&quot;nt&quot;&gt;&amp;lt;/span&amp;gt;&lt;/span&gt; text.&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'p'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'div span'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// prints 0&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'p'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'div span'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// prints 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
</description>
        <pubDate>Tue, 01 Nov 2016 00:00:00 +0000</pubDate>
        <link>http://york.io/2016/11/01/element-queryselector-evaulates-entire-dom.html</link>
        <guid isPermaLink="true">http://york.io/2016/11/01/element-queryselector-evaulates-entire-dom.html</guid>
        
        
      </item>
    
      <item>
        <title>Using Redis to Persist PHP Sessions on Heroku</title>
        <description>&lt;p&gt;This article focuses on the specific task of using Redis to persist PHP sessions
when running your app on Heroku. If you’re not in that exact same situation then
this article will not apply to you.&lt;/p&gt;

&lt;p&gt;I assume that you have a pre-existing PHP app deployed to Heroku that uses
sessions and that, like me, you didn’t realize until after the app was deployed
that you lose your sessions every time you deploy a new version of your app.&lt;/p&gt;

&lt;h2 id=&quot;1-provision-the-heroku-redis-add-on&quot;&gt;1. Provision the Heroku Redis Add-on&lt;/h2&gt;

&lt;p&gt;Provisioning the &lt;a href=&quot;https://elements.heroku.com/addons/heroku-redis&quot;&gt;Heroku Redis&lt;/a&gt;
addon is straight forward. I prefer provisioning add-ons via the dashboard.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/img/posts/provision-heroku-redis-addon.png&quot; alt=&quot;Hand drawing of logo&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;2-add-the-redis-platform-package-to-composer&quot;&gt;2. Add the Redis Platform Package to Composer&lt;/h2&gt;

&lt;p&gt;Add this line to your &lt;code class=&quot;highlighter-rouge&quot;&gt;composer.json&lt;/code&gt; require list:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;ext-redis&quot;: &quot;*&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;That’s a special composer syntax for &lt;a href=&quot;https://getcomposer.org/doc/02-libraries.md#platform-packages&quot;&gt;platform packages&lt;/a&gt;.
This informs Heroku that it should enable the PHPRedis package.&lt;/p&gt;

&lt;p&gt;You will know if Heroku recognized the platform package by seeing an entry in
your build log that looks like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-----&amp;gt; Installing platform packages...
       - php (5.6.24)
       - ext-redis (2.2.7)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Locally, you’ll have to install Redis yourself or use regular PHP sessions. If
you choose not to install Redis locally then you can use the &lt;code class=&quot;highlighter-rouge&quot;&gt;--ignore-platform-reqs&lt;/code&gt;
flag when running &lt;code class=&quot;highlighter-rouge&quot;&gt;composer update&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;composer install&lt;/code&gt;, otherwise Composer
will throw an error when it’s unable to find the extension.&lt;/p&gt;

&lt;p&gt;You might review the &lt;a href=&quot;https://devcenter.heroku.com/articles/php-support#extensions&quot;&gt;full list&lt;/a&gt; 
of other PHP extension that you can enable on Heroku via &lt;code class=&quot;highlighter-rouge&quot;&gt;composer.json&lt;/code&gt;. I noticed
I was compiling a 3rd party extension that Heroku already had available for me.
Using Heroku’s built-in version lowered my deploy time from minutes to seconds
and lowered my slug size by about 200 MB.&lt;/p&gt;

&lt;h2 id=&quot;3-configure-php-sessions-to-use-redis&quot;&gt;3. Configure PHP Sessions to use Redis&lt;/h2&gt;

&lt;p&gt;PHP session storage is configured via the &lt;a href=&quot;http://php.net/manual/en/ini.list.php&quot;&gt;php.ini variables&lt;/a&gt;
&lt;code class=&quot;highlighter-rouge&quot;&gt;session.save_handler&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;session.save_path&lt;/code&gt;. Normally with Heroku we would
recommend setting those in a &lt;a href=&quot;http://php.net/manual/en/configuration.file.per-user.php&quot;&gt;.user.ini file&lt;/a&gt;.
However, the default conenction string that Heroku uses for Redis is not the 
same format that we need to use in PHP. Therefore we must set this values in
our PHP app code so that we can parse Heroku’s format and construct the format
that PHP expects.&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Assume we don't want to use Redis if the environment variable isn't set.
&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// This prevents us from needing to install PHPRedis locally. We're okay with
&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// using the default file storage for sessions in our development environments.
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'REDIS_URL'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$redisUrlParts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parse_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$_ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'REDIS_URL'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;ini_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'session.save_handler'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'redis'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;ini_set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'session.save_path'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;tcp://&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$redisUrlParts[host]:$redisUrlParts[port]?auth=$redisUrlParts[pass]&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;4-validate&quot;&gt;4. Validate&lt;/h2&gt;

&lt;p&gt;Load any page in your app that starts a session then connect to your Heroku Redis
instance and check for the existing of a session key.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;heroku redis:cli -a APP-NAME -c APP-NAME
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;That opens a connection to the Redis CLI in the remote Heroku instance.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ec2-54-221-206-137.compute-1.amazonaws.com:6379&amp;gt; keys *
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;That tells Redis to list all keys. You should see something like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1) PHPREDIS_SESSION:vm0790r1veot5dhkkpdotjek71
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;There we see that our PHP app successfully saved a session to Redis.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Herouk is an amazing platform. It made this a painless experience.&lt;/p&gt;

&lt;p&gt;A mighty thanks to DigitalOcean for a guide on how to 
&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-set-up-a-redis-server-as-a-session-handler-for-php-on-ubuntu-14-04&quot;&gt;setup Redis for PHP session handling&lt;/a&gt; the hard way.&lt;/p&gt;

&lt;p&gt;If you prefer to use Memcached, Heroku has written &lt;a href=&quot;https://devcenter.heroku.com/articles/php-sessions&quot;&gt;a guide for you&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Fri, 22 Jul 2016 00:00:00 +0000</pubDate>
        <link>http://york.io/2016/07/22/redis-persist-sessions-php-heroku.html</link>
        <guid isPermaLink="true">http://york.io/2016/07/22/redis-persist-sessions-php-heroku.html</guid>
        
        
      </item>
    
      <item>
        <title>Using JSON Schema to Validate JSON</title>
        <description>&lt;p&gt;When creating a new REST API I wanted to validate the return format of the JSON
response. While sarching for a solution, I discovered &lt;a href=&quot;http://json-schema.org/&quot;&gt;JSON Schema&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;JSON Schema defines a human and machine readable description of a JSON
structure and format. It looks like this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;s2&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Example Schema&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;object&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;s2&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;s2&quot;&gt;&quot;firstName&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;string&quot;&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
		&lt;span class=&quot;s2&quot;&gt;&quot;lastName&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;string&quot;&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
		&lt;span class=&quot;s2&quot;&gt;&quot;age&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;s2&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Age in years&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;integer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;s2&quot;&gt;&quot;minimum&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;s2&quot;&gt;&quot;required&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;firstName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;lastName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;It’s a little verbose, but it’s flexible. Most importantly it enables automatic
validation of JSON responses. With many &lt;a href=&quot;http://json-schema.org/implementations.html&quot;&gt;JSON schema validators&lt;/a&gt;
available, you can quickly integrate them into your tests. Here’s an example
using &lt;a href=&quot;https://github.com/geraintluff/tv4&quot;&gt;tv4&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tv4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The first weakness you might run into is that the spec allows undefined properties
by default. In most situations, you want unexpected properties to be an error.
Most validators account for this by having a “ban unknown properties” mode.&lt;/p&gt;

&lt;p&gt;If your schema is advanced you might start wanting some form of inheritance,
but JSON schema doesn’t support it. &lt;a href=&quot;https://github.com/rootsdev/gedcomx-json-schema&quot;&gt;GEDCOM X JSON Schema&lt;/a&gt;
gets around this by merging the property objects itself as it assembles the schema.&lt;/p&gt;
</description>
        <pubDate>Wed, 04 May 2016 00:00:00 +0000</pubDate>
        <link>http://york.io/2016/05/04/using-json-schema-validate.html</link>
        <guid isPermaLink="true">http://york.io/2016/05/04/using-json-schema-validate.html</guid>
        
        
      </item>
    
      <item>
        <title>Reset Migrations With Knex</title>
        <description>&lt;p&gt;&lt;a href=&quot;http://knexjs.org/&quot;&gt;Knex&lt;/a&gt; is a Node.js SQL query builder that supports multiple
database implementations. It also supports &lt;a href=&quot;http://knexjs.org/#Migrations&quot;&gt;migrations&lt;/a&gt;
which are essential to any serious project using a relational db.&lt;/p&gt;

&lt;p&gt;During local development, when running tests, and particuarly when testing
migrations, I often wanted to reset the db and rerun all migrations. I was
shocked to find that Knex migrations doesn’t have a reset method.&lt;/p&gt;

&lt;p&gt;I first tried to follow some advice and write a bash script. After a coule of
hours trying different methods of running postgres commands from the CLI and
battling database user permissions (both for authentication and db access rights)
I ended up with this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Delete and recreate the database&lt;/span&gt;
psql -U postgres -h 127.0.0.1 -c &lt;span class=&quot;s1&quot;&gt;'DROP DATABASE IF EXISTS my_database;'&lt;/span&gt;
psql -U postgres -h 127.0.0.1 -c &lt;span class=&quot;s1&quot;&gt;'CREATE DATABASE my_database;'&lt;/span&gt;
psql -U postgres -h 127.0.0.1 -c &lt;span class=&quot;s1&quot;&gt;'GRANT CONNECT ON DATABASE my_database TO my_db_user;'&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Run migrations to generate the schema&lt;/span&gt;
knex migrate:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;It did finally work, but I wasn’t happy with it. It was very specific to my
environment. Plus I don’t like including bash scripts in Node projects unless
there’s absolutely no other sane method.&lt;/p&gt;

&lt;p&gt;After reading more about Knex migrations and realizing that the long promised
&lt;a href=&quot;https://github.com/knex/arctic&quot;&gt;arctic &lt;/a&gt; migrations API wasn’t coming, I looked
at the current &lt;a href=&quot;https://github.com/tgriesser/knex/blob/8a303f1a964acc98205575b1fcb594f5d6b0ea90/test/integration/migrate/index.js&quot;&gt;Migrate&lt;/a&gt;
source to find that the API was very neat (perhaps it’s improved in the past
year). I quickly found a very simple solution.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;migrate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;knex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;migrate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Force unlock in case of a bad state&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;migrate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forceFreeMigrationsLock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Get completed migrations&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;migrate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_listCompleted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Rollback migrations&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;completedMigrations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;migrate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_waterfallBatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;completedMigrations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'down'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Migrate to the latest&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;migrate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;latest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 04 May 2016 00:00:00 +0000</pubDate>
        <link>http://york.io/2016/05/04/knex-reset-migrations.html</link>
        <guid isPermaLink="true">http://york.io/2016/05/04/knex-reset-migrations.html</guid>
        
        
      </item>
    
      <item>
        <title>Affordable Email Forwarding For Small Projects</title>
        <description>&lt;p&gt;The biggest frustration I’ve had recently as a developer is finding cheap email
forwarding. When working on a small project, such as &lt;a href=&quot;https://rootssearch.io&quot;&gt;RootsSearch&lt;/a&gt;,
I want to have an email listed somewhere for anyone to contact me. I want that 
email to be forwarded to my personal inbox so that I don’t have to check multiple
accounts with multiple hosts.&lt;/p&gt;

&lt;p&gt;Domain registrars often offer free email forwarding, such as 
&lt;a href=&quot;https://www.namecheap.com/&quot;&gt;Namecheap&lt;/a&gt; or &lt;a href=&quot;https://domains.google.com&quot;&gt;Google&lt;/a&gt;.
But I like to use &lt;a href=&quot;https://www.cloudflare.com/&quot;&gt;CloudFlare&lt;/a&gt; for my DNS and 
CloudFlare requires you to use their nameservers which means your registrar
can’t control your MX records and therefore you need a separate solution for 
email forwarding.&lt;/p&gt;

&lt;p&gt;When I first ran into this problem I figured the solution would be easy. A previous
employer had used &lt;a href=&quot;http://dyn.com/email/dyn-email-forward/&quot;&gt;Dyn&lt;/a&gt; and later
&lt;a href=&quot;http://www.duocircle.com/services/email-forwarding&quot;&gt;DuoCircle&lt;/a&gt; for email forwarding
so there was at least one company out there. But DuoCircle charges $59.95 a year
per domain. That quickly adds up for small projects, especially if you have multiple.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.33mail.com/&quot;&gt;33Mail&lt;/a&gt; looked promising, especially at only $1 a month
to use custom domains. But I quickly ran into a feature I couldn’t tolerate nor
prevent: to every email I received, 33Mail added a banner that said 
“This email was sent to the alias… and 33Mail forwarded it to you.” I didn’t
mind so much seeing the banner in the emails I received, but I didn’t want them to appear
in the quoted section of an email thread when I responded to customers. I could
easily remove them when replying (which I did) but it meant I was again on the
hunt for a good email forwarding solution.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.pobox.com/pricing&quot;&gt;Pobox&lt;/a&gt; was another promising candidate. It has
been around a while and was cheap at $20 a month. Though their volume limits 
seemed low and I didn’t want to be paying for services that I wouldn’t be using.&lt;/p&gt;

&lt;p&gt;After &lt;em&gt;weeks&lt;/em&gt; of searching on and off, I finally found &lt;a href=&quot;https://mailgun.com&quot;&gt;Mailgun&lt;/a&gt;
by Rackspace. I was skeptical at first because it looked just like &lt;a href=&quot;http://mandrill.com/&quot;&gt;Mandrill&lt;/a&gt;
which doesn’t support inbound email forwarding out of the box. But it turns out
that Mailgun &lt;em&gt;does&lt;/em&gt; support email forwarding. Their pricing is also perfect: 
10,000 emails every month for &lt;strong&gt;free&lt;/strong&gt;. Sold.&lt;/p&gt;
</description>
        <pubDate>Wed, 23 Sep 2015 00:00:00 +0000</pubDate>
        <link>http://york.io/2015/09/23/affordable-email-forwarding-for-small-projects.html</link>
        <guid isPermaLink="true">http://york.io/2015/09/23/affordable-email-forwarding-for-small-projects.html</guid>
        
        
      </item>
    
      <item>
        <title>Drawing Family Pedigrees With D3</title>
        <description>&lt;p&gt;I recently set out to learn how to draw family pedigrees with &lt;a href=&quot;http://d3js.org/&quot;&gt;D3&lt;/a&gt;. Their
website is full of examples including an actual &lt;a href=&quot;http://bl.ocks.org/mbostock/2966094&quot;&gt;pedigree chart&lt;/a&gt;.
That example was much too simple for my requirements. I wanted it to be styled
like most pedigrees in software with a box around the person. I also wanted it
to expand, collapse, pan, and zoom. As I perused other D3 examples, I had difficulty 
mixing and matching techniques and separating the basics from the fancy stylistic 
additions. I decided to document and share what I learned in a incremental set 
of examples so that you wouldn’t have to become an expert in D3 just to draw a pedigree.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/justincy/d3-pedigree-examples&quot;&gt;D3 pedigree examples&lt;/a&gt; are hosted on GitHub. At the time
of writing, they include 5 examples:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://justincy.github.io/d3-pedigree-examples/basic.html&quot;&gt;Basic&lt;/a&gt;: A basic static pedigree.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://justincy.github.io/d3-pedigree-examples/expandable.html&quot;&gt;Expand and Collapse&lt;/a&gt;: Click on persons to expand and collapse the tree.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://justincy.github.io/d3-pedigree-examples/transitions.html&quot;&gt;Smooth Transitions&lt;/a&gt;: Changes are animated when the tree is expanded or collapsed.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://justincy.github.io/d3-pedigree-examples/descendants.html&quot;&gt;Ancestors and Descendants&lt;/a&gt;: Show both ancestors and descendants.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://justincy.github.io/d3-pedigree-examples/descendants-oop.html&quot;&gt;Ancestors and Descendants - OOP&lt;/a&gt;: A more sane example of ancestors and descendants using classes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Visit &lt;a href=&quot;https://github.com/justincy/d3-pedigree-examples&quot;&gt;the repo&lt;/a&gt; to learn more about the implementation details.
Here, I want to share my thoughts about whether D3 is a good tool for drawing pedigrees.&lt;/p&gt;

&lt;h3 id=&quot;pros&quot;&gt;Pros&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;D3 has a built-in [tree layout]. It’s defaults need to be tweaked a little for
rendering pedigrees, but it still works great.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Drawing the connecting lines is trivial in SVG.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Startup time for a basic pedigree is very small.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;cons&quot;&gt;Cons&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://d3js.org/&quot;&gt;D3&lt;/a&gt; is too powerful for most people
to tame. Without being able to copy and paste from the enormous library of examples,
most users would not be able to get anything done&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. The moment you need to modify
anything, you have to become an expert in both SVG and D3.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;SVG is great for shapes with a little bit of text. But pedigrees are lots of
text with a few shapes. SVG does not support text wrapping nor inline styles (the
ability to style one word, character, or phrase different than the other text
around it). You can mimic those feature by adding different text nodes and calculating
their position, but it’s not ideal. Some browsers allow you to embed HTML in a 
&lt;code class=&quot;highlighter-rouge&quot;&gt;foreignObject&lt;/code&gt; so that you can use HTML and CSS to style text, which has all 
the tools we need, but support is partial for those browsers that allow it while
no version of IE supports it at all. That renders the &lt;code class=&quot;highlighter-rouge&quot;&gt;foreignObject&lt;/code&gt; useless 
for the majority of production projects.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The complexity increases by orders of magnitude if you want to make the pedigree
dynamic and interactive (in our case to expand and collapse).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;D3 does not lend itself well to an OOP approach. This is why the examples are 
generally one large wall of code.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;If you just need a basic pedigree display than D3 is great. You’ll end up spending
most of your time getting your data into the proper format than you will configuring
the tree. However, if you need anything more advanced then I would recommend just
using HTML. Ancestry, FamilySearch, and findmypast all use HTML for their pedigrees.
MyHeritage is the only large tree website I know of that uses SVG and they didn’t
use D3 to do it.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;I don’t think I could’ve done anything either without those examples.&amp;nbsp;&lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 11 Jun 2015 00:00:00 +0000</pubDate>
        <link>http://york.io/2015/06/11/drawing-family-pedigrees-with-d3.html</link>
        <guid isPermaLink="true">http://york.io/2015/06/11/drawing-family-pedigrees-with-d3.html</guid>
        
        
      </item>
    
      <item>
        <title>Automated Testing and Code Coverage in Node.js</title>
        <description>&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Code_coverage&quot;&gt;Code coverage&lt;/a&gt; is a valuable metric for understanding the quality of your test
suite. In this post we will show how to quickly generate code coverage statistics
for your JavaScript and Node.js libraries using &lt;a href=&quot;http://mochajs.org/&quot;&gt;Mocha&lt;/a&gt;, &lt;a href=&quot;https://travis-ci.org&quot;&gt;Travis CI&lt;/a&gt;,
&lt;a href=&quot;https://github.com/gotwarlost/istanbul&quot;&gt;Istanbul&lt;/a&gt;, and &lt;a href=&quot;https://coveralls.io/&quot;&gt;Coveralls&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;test-suite-with-mocha&quot;&gt;Test Suite with Mocha&lt;/h3&gt;

&lt;p&gt;We need a test suite before we can generate code coverage. Our favorite testing
framework is &lt;a href=&quot;http://mochajs.org/&quot;&gt;Mocha &lt;/a&gt; with &lt;a href=&quot;http://chaijs.com/&quot;&gt;Chai&lt;/a&gt; for assertions. A test file might
look like this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'chai'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Array'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'#indexOf()'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'should return -1 when the value is not present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Then in our &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file we would add a test script to run with &lt;code class=&quot;highlighter-rouge&quot;&gt;npm test&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s2&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;mocha&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 id=&quot;automated-testing-with-travis-ci&quot;&gt;Automated Testing with Travis CI&lt;/h3&gt;

&lt;p&gt;We can automatically run our test suite for each commit using &lt;a href=&quot;https://travis-ci.org&quot;&gt;Travis CI&lt;/a&gt;.
Sign up, add your GitHub repository, then add a &lt;code class=&quot;highlighter-rouge&quot;&gt;.travis.yml&lt;/code&gt; file to the repo.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node_js&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;node_js&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;0.10'&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;npm&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;test'&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# tell Travis how to run your test suite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Every time a commit is pushed to your repository on any branch, Travis will
automatically queue up a test runner that clones your repository, installs all
dependencies, runs your test suite, and reports the status. You can even add a
&lt;a href=&quot;http://docs.travis-ci.com/user/status-images/&quot;&gt;status badge&lt;/a&gt; to your repos README that shows the current build status and acts as a
handy link for Travis. The best part is it’s 100% free for public GitHub repos.&lt;/p&gt;

&lt;h3 id=&quot;code-coverage-with-istanbul&quot;&gt;Code Coverage with Istanbul&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/gotwarlost/istanbul&quot;&gt;Istanbul&lt;/a&gt; is the only viable JavaScript code coverage tool we are aware
of. It’s fast, easy to use, can be installed via npm, and doesn’t need to be installed
globally. To run, just add another entry in the &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; scripts field.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;coverage&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;istanbul cover ./node_modules/mocha/bin/_mocha&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;You’ll notice that we have to call the mocha bin file directly. This is because
the main mocha file forks into a child process as &lt;a href=&quot;https://github.com/gotwarlost/istanbul/issues/44&quot;&gt;explained here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When you run &lt;code class=&quot;highlighter-rouge&quot;&gt;npm run coverage&lt;/code&gt; it will generate coverage statistics in the
&lt;code class=&quot;highlighter-rouge&quot;&gt;coverage&lt;/code&gt; directory including a browsable HTML report in &lt;code class=&quot;highlighter-rouge&quot;&gt;coverage/lcov-report/index.html&lt;/code&gt;.
We suggest adding &lt;code class=&quot;highlighter-rouge&quot;&gt;coverage&lt;/code&gt; to your &lt;code class=&quot;highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt; file so
that it’s not committed to your repo.&lt;/p&gt;

&lt;h3 id=&quot;automated-code-coverage-with-coveralls&quot;&gt;Automated Code Coverage with Coveralls&lt;/h3&gt;

&lt;p&gt;Similar to how we used &lt;a href=&quot;https://travis-ci.org&quot;&gt;Travis CI&lt;/a&gt; to automate our testing, we can use
&lt;a href=&quot;https://coveralls.io/&quot;&gt;Coveralls&lt;/a&gt; to automate our code coverage. The first step is to sign up
and enable your repository. This will generate a token which you need to add to a
&lt;code class=&quot;highlighter-rouge&quot;&gt;.coveralls.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;repo_token&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;mycoverallsrepoymltoken&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Second, you need to install the &lt;a href=&quot;https://github.com/cainus/node-coveralls&quot;&gt;coveralls node&lt;/a&gt; package. This
allows us to send our node coverage stats to Coveralls so that they can store
and process it.&lt;/p&gt;

&lt;p&gt;Third, we need a new command in our &lt;code class=&quot;highlighter-rouge&quot;&gt;scripts&lt;/code&gt; field:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;coveralls&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;npm run coverage &amp;amp;&amp;amp; cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This command will run our test suite to gather coverage stats then pipe them into
the coveralls node package which sends the stats to coveralls.&lt;/p&gt;

&lt;p&gt;The last thing to do is update &lt;code class=&quot;highlighter-rouge&quot;&gt;.travis.yml&lt;/code&gt; so that our new coveralls command
is run automatically by Travis each time a commit is pushed to our repository.
This will still run tests and track our build status while also allowing coveralls
to track changes to our code coverage.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;npm&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;coveralls'&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# tell Travis how to run your test suite&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;An option step, though one we highly recommend, is to add a coverage badge to
your README that shows off your coverage percentage and adds a quick link to
Coveralls browsable coverage stats.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Our full &lt;code class=&quot;highlighter-rouge&quot;&gt;scripts&lt;/code&gt; field in &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; now looks like this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s2&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;mocha&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;coverage&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;istanbul cover ./node_modules/mocha/bin/_mocha&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;coveralls&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;npm run coverage &amp;amp;&amp;amp; cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Of course, you can add additional scripts. We encourage you to browse the
documentation for &lt;a href=&quot;http://mochajs.org/&quot;&gt;Mocha&lt;/a&gt;, &lt;a href=&quot;https://travis-ci.org&quot;&gt;Travis CI&lt;/a&gt;, &lt;a href=&quot;https://github.com/gotwarlost/istanbul&quot;&gt;Istanbul&lt;/a&gt;, 
and &lt;a href=&quot;https://coveralls.io/&quot;&gt;Coveralls&lt;/a&gt; to see what else is possible.&lt;/p&gt;

&lt;p&gt;See &lt;a href=&quot;https://github.com/genealogysystems/fs-traversal/tree/16c306a0e0c168e59a875f2f1d74cb32a3f6bc8e&quot;&gt;FS-Traversal&lt;/a&gt; for a real example of the setup we described here.&lt;/p&gt;

</description>
        <pubDate>Wed, 20 May 2015 00:00:00 +0000</pubDate>
        <link>http://york.io/2015/05/20/automated-testing-code-coverage-node.html</link>
        <guid isPermaLink="true">http://york.io/2015/05/20/automated-testing-code-coverage-node.html</guid>
        
        
      </item>
    
      <item>
        <title>Using HTML Templates with JavaScript on the Client</title>
        <description>&lt;p&gt;Generating HTML in JavaScript can be painful. It quickly gets out of control
when building any advanced UI.&lt;/p&gt;

&lt;p&gt;Let’s say we want to display a contact list using a list of contacts with this schema:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Joe'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/pics/Joe.png'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;phone&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'987-654-3210'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;We want the resulting HTML to look like this:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;contacts&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;contact&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;thumb&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/pics/Joe.png&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Joe&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;phone&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;987-654-3210&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- more contacts... --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 id=&quot;vanilla-javascript&quot;&gt;Vanilla JavaScript&lt;/h3&gt;

&lt;p&gt;Traditionally, with vanilla JS, we generated elements directly. &lt;a href=&quot;http://jsfiddle.net/g00xzpsf/&quot;&gt;jsFiddle&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'div'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;className&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'contacts'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;contacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;contact&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'div'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;className&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'contact'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'img'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'http://lorempixel.com/50/50/people/'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;contacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;className&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'thumb'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;img&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'div'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;className&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'name'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;contacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;phone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'div'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;className&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'phone'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;contacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Using vanilla JS is a lot of work; 23 lines of code to generate our simple contact
list. It’s also error prone because of cross-browser compatibility issues.&lt;/p&gt;

&lt;h3 id=&quot;jquery&quot;&gt;jQuery&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://jquery.com/&quot;&gt;jQuery&lt;/a&gt;, released in 2006, solved our browser compatibility issues
and made DOM manipulation easier. &lt;a href=&quot;http://jsfiddle.net/et1zt7uj/&quot;&gt;jsFiddle&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;div&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'contacts'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;contacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;contact&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;div&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'contact'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;img&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'src'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'http://lorempixel.com/50/50/people/'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;contacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'thumb'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;div&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'name'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;phone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;div&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'phone'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This is about the same number of lines of code as vanilla JS, though there
are many less characters which I say leads to enhanced readability. We also
don’t have to worry about browser compatibility.&lt;/p&gt;

&lt;h3 id=&quot;handlebars&quot;&gt;Handlebars&lt;/h3&gt;

&lt;p&gt;We can do better. Instead of building the HTML in JavaScript, let’s separate the
HTML from the JavaScript in the same way we separate CSS from HTML. We’ll use
&lt;a href=&quot;http://handlebarsjs.com/&quot;&gt;Handlebars&lt;/a&gt; to create HTML templates which are later compiled and 
populated.&lt;/p&gt;

&lt;p&gt;First, our HTML template is embedded in a script tag in our HTML page.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html-handlbars&quot; data-lang=&quot;html+handlbars&quot;&gt;&amp;lt;script id=&quot;contacts-template&quot; type=&quot;text/x-handlebars-template&quot;&amp;gt;
    &amp;lt;div class=&quot;contacts&quot;&amp;gt;
        {{#each contacts}}
        &amp;lt;div class=&quot;contact&quot;&amp;gt;
            &amp;lt;img class=&quot;thumb&quot; src=&quot;http://lorempixel.com/50/50/people/{{name}}&quot; /&amp;gt;
            &amp;lt;div class=&quot;name&quot;&amp;gt;{{name}}&amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;phone&quot;&amp;gt;{{phone}}&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        {{/each}}
    &amp;lt;/div&amp;gt;
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then in JavaScript we retrieve, compile, and evaluate our template. &lt;a href=&quot;http://jsfiddle.net/e2Lonvh7/1/&quot;&gt;jsFiddle&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'contacts-template'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Handlebars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;That is much better. Our HTML is in a template which makes refactoring the HTML
much easier (imagine trying to refactor the HTML construction in the first two examples).
We also get syntax highlighting for the HTML when in our IDE. And now our JavaScript
has been reduced from 23 lines to 3 lines for this simple example (the savings can
be much larger for more complex projects).&lt;/p&gt;

&lt;p&gt;Checkout the jsFiddles for complete and working examples of the three usecases
we presented here: &lt;a href=&quot;http://jsfiddle.net/g00xzpsf/&quot;&gt;vanilla JS&lt;/a&gt;, &lt;a href=&quot;http://jsfiddle.net/et1zt7uj/&quot;&gt;jQuery&lt;/a&gt;, and &lt;a href=&quot;http://jsfiddle.net/e2Lonvh7/1/&quot;&gt;Handlebars&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>Thu, 07 May 2015 00:00:00 +0000</pubDate>
        <link>http://york.io/2015/05/07/html-templates-in-javascript-on-the-client.html</link>
        <guid isPermaLink="true">http://york.io/2015/05/07/html-templates-in-javascript-on-the-client.html</guid>
        
        
      </item>
    
      <item>
        <title>Asset Bundling in Express</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://www.findarecord.com&quot;&gt;Find-A-Record&lt;/a&gt; is built on &lt;a href=&quot;http://expressjs.com/&quot;&gt;Express&lt;/a&gt;, a web framework for Node.js.
Remarkably, &lt;a href=&quot;https://www.findarecord.com&quot;&gt;Find-A-Record&lt;/a&gt; has no tests, no build system, and no asset bundling 
system. That’s okay for the static pages such as the home page, but the main web 
app relies on 15 JavaScript files and 3 CSS files in addition to the 3 JavaScript 
files and 3 CSS files included on every page in the site. It’s unwieldy.&lt;/p&gt;

&lt;p&gt;Including so many static assets has undesirable consequences. First, it increases
page load times because each asset needs to be downloaded separately.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; Each
request incurs the overhead of HTTP, TCP, and the limitations of the speed
of light as it travels over the wire.&lt;/p&gt;

&lt;p&gt;A cascading consequence of having so many assets is that we don’t want to add more.
Therefore, the majority of the custom JavaScript is kept in one 1,500 line file.
We don’t want to split it up because it just adds more asset files for downloading.&lt;/p&gt;

&lt;p&gt;We need a way to bundle our assets. If the assets are bundled then we reduce the
overhead of 24 total requests to 4: global CSS file, global JS file, page-specific
CSS file, and page-specific JS file.&lt;/p&gt;

&lt;p&gt;The main reason why we’ve been avoiding a build or bundle system is that it’s a
big commitment; you have to buy into a specific workflow and hope it scales well
into the future with your code base. Does it support minifying of JS and CSS?
Does it have a development mode where you can include unbundled and unprocessed
versions of your assets (very helpful for debugging)? Does it require bundled and
processed files to be committed to your repository? Does bundling occur when the
app is started? Does the app need to be restarted when source files are changed?&lt;/p&gt;

&lt;p&gt;Since we’re using Express, middleware was our first thought but all we could find
were &lt;a href=&quot;https://github.com/FGRibreau/bundle-up&quot;&gt;BundleUp&lt;/a&gt; and &lt;a href=&quot;https://github.com/FGRibreau/pound&quot;&gt;Pound&lt;/a&gt; (which is built on BundleUp). We have
successfully integrated bundle-up but we know it’s not a long-term solution 
since it’s not being maintained and its dependencies are way out of date.&lt;/p&gt;

&lt;p&gt;What we like about BundleUp is that bundles are configured inside of the app itself.
This makes it easier to figure which assets are included in which views and makes
the development mode possible where assets are included directly instead of bundled.
If you use an external bundling system and you want a development mode then bundles
need to be configured both internally and externally which can be a mess.&lt;/p&gt;

&lt;p&gt;One downside of BundleUp is that it runs when the app starts so it slows startup time.
The documentation also leaves a lot to be desired. We noticed it was touching our
source files and causing &lt;a href=&quot;https://github.com/remy/nodemon&quot;&gt;Nodemon&lt;/a&gt; to consistently restart the app.
It turns out that it’s written to “compile” all assets, even if they’re not being
processed (such as SASS or CoffeeScript) or minified. The default compile behavior
for vanilla JS and CSS is to copy but our paths were configured such that it was
writing over the originals with an exact copy.&lt;/p&gt;

&lt;p&gt;We don’t like &lt;a href=&quot;http://bower.io/&quot;&gt;Bower&lt;/a&gt; because of it’s reliance on manifest files and how you can
only exclude files in the manifest as opposed to marking only a few for inclusion.
Besides, Bower is designed to handle and bundle external dependencies. All of
the assets we want to bundle are already installed locally and committed to the repo.
We just want to process local files and bundle them all together.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://browserify.org/&quot;&gt;Browserify&lt;/a&gt;’s strong point is for bundling CommonJS modules in a
way that enables them to be used in the browser. This allows you to right
JavaScript code in Node (leveraging Node’s handy require syntax for modules)
and then package it up for the front end. We use Browserify for other projects
but that’s not our use case here.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://duojs.org/&quot;&gt;Duo&lt;/a&gt; is a new kid on the block and fits our development style a little better, 
but again it’s likely much more than we need.&lt;/p&gt;

&lt;p&gt;In the future we hope to create our own middleware for Express. All it needs to
do is allow for bundles to be configured and then process and minify them. It
can’t be too hard, and we can’t believe &lt;a href=&quot;https://github.com/FGRibreau/bundle-up&quot;&gt;BundleUp&lt;/a&gt; is the only thing out there
like it.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot;&gt;
      &lt;p&gt;I can’t wait until &lt;a href=&quot;https://http2.github.io/&quot;&gt;HTTP2&lt;/a&gt; is more ubiquitous.&amp;nbsp;&lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 29 Apr 2015 00:00:00 +0000</pubDate>
        <link>http://york.io/2015/04/29/express-asset-bundling.html</link>
        <guid isPermaLink="true">http://york.io/2015/04/29/express-asset-bundling.html</guid>
        
        
      </item>
    
  </channel>
</rss>
