Jack Franklin2024-03-04T00:00:00+00:00https://www.jackfranklin.co.uk/Jack Franklinjack@jackfranklin.netUsing objects in jQuery's .css()2012-04-06T00:00:00+00:00http://www.jackfranklin.co.uk/blog/using-objects-in-jquerys-css/<p>Something I will be focusing on on a regular basis here at JSP is producing tidy code that's easier to maintain in the future as well as nicer to work with. One such area where people often produce messy code is when using jQuery's <code>.css()</code> method.</p>
<p>Basic usage of this goes like so:</p>
<p>$(elem).css("display"); //returns value
$(elem).css("display", "block"); //sets value</p>
<p>And in order to set multiple values, people will often do this:</p>
<p>$(elem)
.css("display", "block")
.css("border", "1px solid blue")
.css("background", "#F00")
{and so on}</p>
<p>However this is the wrong way to do this, on so many levels. jQuery is written pretty cleverly, and <code>.css()</code> can take an object of properties & their respective values:</p>
<p>$(elem).css({
"border" : "1px solid blue",
"display" : "block",
"background" : "#F00"
});</p>
<p>It's worth noting that you don't actually need the quotes around the properties (but you do around the values), this would be valid:</p>
<p>$(elem).css({
border: "1px solid blue",
{so on}
});</p>
<p>However, you have to use quotes if you want to use a reserved word as a property. For example if you were creating a new element & setting the class attribute:</p>
<p>$("<div>", {
class: "myDiv"
});</div></p>
<p>That's invalid, as <code>class</code> is a reserved word, so you'd have to do :</p>
<p>$("<div>", {
"class" : "myDiv"
});</div></p>
<p>Because this always trips me up, I've simply gotten into the habit of always putting quotes around my property names in JS objects. This is more a personal preference than anything else, just pick what makes the most sense to you.</p>
The JavaScript Module Pattern2012-04-08T00:00:00+00:00http://www.jackfranklin.co.uk/blog/javascript-module-pattern/<p>Lets say you've got a little library like this, that just increments a number:</p>
<p>var jspy = {
count: 0,</p>
<p>incrementCount: function() {
this.count++;
},</p>
<p>decrementCount: function() {
this.count--;
},</p>
<p>getCount: function() {
return this.count;
}</p>
<p>};</p>
<p>However, people using this library are able to do <code>jspy.count = 5</code> to manually adjust the value. Lets say for the purpose of this tutorial, that users should not be able to do that. In other languages you'd be able to define a private variable, but JavaScript doesn't explcitly have them. However, we are able to manipulate JavaScript to provide them to us, and that brings us on nicely to one of the most popular JavaScript design patterns, the <strong>Module</strong> or <strong>Modular</strong> pattern.</p>
<p>The solution to the above is:</p>
<p>var jspy = (function() {
var _count = 0;</p>
<p>var incrementCount = function() {
_count++;
}</p>
<p>var getCount = function() {
return _count;
}
return {
incrementCount: incrementCount,
getCount: getCount
};</p>
<p>})();</p>
<p>Firstly I create the variable <code>_count</code>, with the underscore denoting that it's private. The underscore means <em>nothing programmatically</em> in JavaScript's case, but it's a common notation used to denote private variables, and one I like to stick to. You can then see the functions that manipulate & return that variable.</p>
<p>However, you'll notice I've wrapped the entire library in a self-invoking anonymous function. This is a function that's executed immediately at runtime. The function runs, defines the variables & functions and then hits the <code>return {}</code> statement, telling this function what to return to the variable <code>jspy</code>, or in other words, what <em>to expose to the user</em>. I chose to expose the two functions but <strong>not</strong> the <code>_count</code> variable, which means I can do this:</p>
<p>jspy.incrementCount();
jspy.getCount();</p>
<p>But if I attempt:</p>
<p>jspy._count; //undefined</p>
<p>It returns <code>undefined</code>.</p>
<p>There are a couple of different approaches to the way I've done things above. Some people like to define the function in the return statement:</p>
<p>var jspy = (function() {
var _count = 0;</p>
<p>return {
incrementCount: function() {
_count++;
},
getCount: function() {
return _count;
}
};
})();</p>
<p>And following on from that, Christian Heilmann coined the <em>Revealing Module Pattern</em>. His approach is to define all methods privately, that is, not in the <code>return</code> block, but expose them there instead, like so:</p>
<p>var jspy = (function() {
var _count = 0;
var incrementCount = function() {
_count++;
};
var resetCount = function() {
_count = 0;
};
var getCount = function() {
return _count;
};
return {
add: incrementCount,
reset: resetCount,
get: getCount
};
})();</p>
<p>The two advantages of this are:</p>
<ul>
<li>It's easier to see at a glace the methods that get exposed; when you're not defining all your methods within <code>return {}</code> it means it's one exposed function per line, making it easier to scan.</li>
<li>You can expose methods via shorter names (eg <code>add</code>) but define them slightly more verbosely in your definition (eg <code>incrementCount</code>).</li>
</ul>
<p>In future tutorials we'll be looking at other types of patterns and putting these to use in a real world context. For now if you're looking for further reading, I highly recommend <a href="http://addyosmani.com/resources/essentialjsdesignpatterns/book/">Addy Osmani's online book, JavaScript Design Patterns</a>.</p>
An introduction to jQuery Deferreds2012-04-08T00:00:00+00:00http://www.jackfranklin.co.uk/blog/jquery-deferreds-tutorial/<p>Prior to jQuery 1.5, Ajax requests could get a bit messy. You'd probably do something like this, if we were making a simple <code>get</code> request:</p>
<p>$(function() {
$.get(
"content.txt",
function(resp) {
console.log("first code block");
console.log(resp);
}
);</p>
<p>});</p>
<p>But this gives you a potential issue - what happens if this fails? What if you can't define the function to run in this code? These are issues before that have required a fair amount of work arounds but with 1.5 onwards we've got the <a href="http://api.jquery.com/category/deferred-object/">jQuery Deferred Object</a>. In this post I'll show you why this is so useful. All of the following code relies on <strong>jQuery 1.5 or higher</strong>.</p>
<p>jQuery Ajax calls now return the jQuery Deferred object I linked to above. The documentation is a little overwhelming & not entirely clear, so don't worry if a brief look at that leaves you confused. Simply put, Ajax calls now return a jQuery object containing what's known as a <a href="http://api.jquery.com/promise/">promise</a>:</p>
<blockquote>
<p>The .promise() method returns a dynamically generated Promise that is resolved once all actions of a certain type bound to the collection, queued or not, have ended.</p>
</blockquote>
<p>In reality whilst working with basic Ajax calls, you don't need to worry about the exact specifications or inner workings. Continuing from the <code>get</code> example above, here's how we'd implement it using jQuery's <code>when()</code>, <code>then()</code> and <code>fail()</code> methods:</p>
<p>$.when($.get("content.txt"))
.then(function(resp) {
console.log("third code block, then() call");
console.log(resp);
})
.fail(function(resp) {
console.log(resp);
});</p>
<p>It can basically be read as:</p>
<p>$.when(some ajax request).then(do this if it succeeds).fail(or do this if it fails)</p>
<p>The main feature of this is that <code>$.when()</code> can take multiple functions, and will then call the functions you pass to <code>.then()</code> once <em>all those functions</em> have finished:</p>
<p>$.when(fn1(), fn2()).then().fail()</p>
<p>You still might not be able to see the main advantage of this method yet, compared to just defining the methods within an object via <code>$.ajax()</code>. However, more importantly, we are able to <em>save Ajax calls to bind events later</em>:</p>
<p>var xhrreq = $.get("content.txt");</p>
<p>We can then define <code>.success</code> and <code>.error</code> methods on this variable:</p>
<p>xhrreq.success(function(resp) {
console.log(resp);
});</p>
<p>And:</p>
<p>xhrreq.error(function(resp) {
console.log(resp);
});</p>
<p>With the main advantage here, being that we can declare many functions to run:</p>
<p>xhrreq.success(fn1);
xhrreq.success(fn2);</p>
<p>Or, an even easier way:</p>
<p>xhrreq.success(fn1, fn2);</p>
<p>So, to conclude, hopefully this article has shown you that deferreds are a much improved way to work with Ajax calls in jQuery. In the future I'll be doing follow up articles going into more depth.</p>
jQuery 1.7 Event Binding: .on() & .off()2012-04-09T00:00:00+00:00http://www.jackfranklin.co.uk/blog/jquery-1-7-event-binding-on-and-off/<p>From jQuery 1.7 new methods were added for binding events, <code>.on()</code> and <code>.off()</code> which, unsurprisingly, does the opposite of <code>.on()</code>. Amongst the community, there seems to have been a bit of confusion over these methods & in this post I want to clear this up, once & for all.</p>
<p>Firstly, I'm going to hit you with a rule:</p>
<p><strong>From now on, you should use <code>.on()</code> and <code>.off()</code> for all your event binding in jQuery.</strong></p>
<p>You actually will be doing this, whether you like it or not, if you're using jQuery 1.7+. If you take a look at the source for <code>.click()</code>, you can see it actually just calls <code>.on()</code>:</p>
<p>function (data, fn) {
if (fn == null) {
fn = data;
data = null;
}</p>
<p>return arguments.length > 0 ? this.on(name, null, data, fn) : this.trigger(name);
}</p>
<p><em>For looking at the jQuery source I really like James Padolsey's <a href="http://james.padolsey.com/jquery/#v=git">jQuery source viewer</a></em></p>
<p>It won't surprise you to know that all the other methods like <code>.bind()</code>, <code>.delegate()</code> and so on all internally use <code>.on()</code>.</p>
<p>In the most basic form, this is how we'd assign a click handler now:</p>
<p>$(elem).on("click", function() {
console.log("clicked");
});</p>
<p>The preferred way now of binding events is through <em>delegation</em>. The idea of delegating is that you delegate an event to a parent, and then every time it detects that event, it looks to see if the item clicked on is what we want, and then it triggers that event. This is perhaps easier to see in an example:</p>
<p>$("table").on("click", "tr", function() {
console.log("tr inside table clicked");
});</p>
<p>The advantage of this is that it's much easier work for the browser to bind one click event to one item, and then run a conditional every time that event fires, compared to binding a click event to every single <code>tr</code>. Essentially, with delegate, the process for the above code goes like this:</p>
<ol>
<li>Bind 1 click event to <code>table</code></li>
<li>Detected a click event on <code>table</code></li>
<li>Was that click event on a <code>tr</code> ?</li>
<li>If so, fire the function.</li>
<li>If not, do nothing.</li>
</ol>
<p>The final question you might be wondering is how we convert <code>.live()</code> events to <code>.on()</code> ? For those who are not familiar with <code>.live()</code>, it allowed you to bind an event to a selector and have that event still bound to elements you programmatically inserted into the page <em>after</em> the event binding.</p>
<p>The solution is to use <code>.on()</code> & delegation. Taking our <code>$("table").on()</code> example from above, this would still fire click events on <code>tr</code> items, even if those <code>tr</code> items had been dynamically inserted by our code.</p>
<p>Events can be removed with <code>.off()</code>, for example:
$("p").off();
<code>.off()</code> is actually pretty clever in the way it works, again the <a href="http://api.jquery.com/off/">jQuery docs</a> offer a good overview. Personally I only want to briefly mention it here, as I don't think it's something I've ever used in practice.</p>
<p>That concludes our brief look into <code>.on()</code>. From jQuery 1.7 onwards <code>.bind()</code>, <code>.live()</code> & <code>.delegate()</code> are all <strong>deprecated</strong> and I would encourage you to use the new APIs available to use, as <code>.on()</code> is a far superior method in my opinion.</p>
<p>For more, I suggest you read the <a href="http://api.jquery.com/on/">jQuery documentation for <code>.on()</code></a> as it is a very comprehensive read.</p>
JS WTF: 5 < 4 < 32012-04-10T00:00:00+00:00http://www.jackfranklin.co.uk/blog/js-wtf/<p>A quick fun "JS WTF?" post for you today. If you load up your JavaScript console & enter:</p>
<p>5 < 4 < 3</p>
<p>You'd be expecting to see <code>false</code>, right? However, you'll actually see <code>true</code>. <strong>WTF?</strong></p>
<p>This is actually down to the way JavaScript evaluates this and <em>operator precedence</em>. What it sees is:</p>
<p>(5 < 4) < 3</p>
<p>Which in turn gives</p>
<p>false < 3</p>
<p>JavaScript then coerces <code>false</code> into an integer <code>0</code>:</p>
<p>0 < 3</p>
<p>And zero is indeed less than 3, so we get <code>true</code> returned.</p>
<p>Not much learned from this one but it's quite a fun thing to show someone & then explain why. I'll be trying to do a lot of these small "fun" posts as there's a fair few areas of "WTF?" in JavaScript, as we all know.</p>
A jQuery Pub Sub Implementation2012-04-12T00:00:00+00:00http://www.jackfranklin.co.uk/blog/a-jquery-pub-sub-implementation/<p>Having <a href="http://javascriptplayground.com/blog/2012/04/javascript-module-pattern">discussed the Module pattern</a> briefly a few days ago, today I want to tackle another pattern, the Pub Sub (or <em>Publish</em> and <em>Subscribe</em>) pattern, also known as the Observer Pattern. If you've not heard of this implementation, it's pretty straight forward. It allows different aspects of your application, usually called <em>modules</em>, to both subscribe to events other modules might publish, & publish events itself. This means no two modules of your system are directly linked, as each module just relies on events to know what to do & when to do it. In the future we'll look into this pattern using plain JavaScript, but as an introduction to it it makes sense to use jQuery, a framework that allows us to publish & subscribe to events really easily, using <code>.on()</code> <a href="http://javascriptplayground.com/blog/2012/04/jquery-1-7-event-binding-on-and-off">which I covered very recently on this very blog</a> and then <code>.trigger()</code>, which lets us trigger events. Most people will use this to trigger events like <code>click</code> or <code>submit</code>, but did you know you can use it to trigger your own, custom events? It's this functionality we will use today.</p>
<p>The app we will be building is very simple, it's a little app that lets you send messages to yourself. Of course, this is very, very easy (it's a bit of DOM manipulation) but the app is split up into 3 parts which lets me nicely demonstrate some of the PubSub ideas. The app can be seen on the <a href="http://javascriptplayground.com/demos/jquerypubsub/">online demo here</a></p>
<p>There are three key parts:</p>
<ul>
<li>User sends a message via the form,</li>
<li>message is shown on the right panel,</li>
<li>flash notice displays on top of screen to notify user.</li>
</ul>
<p>The source code for this is all available on Github so for the purposes of this tutorial I wont talk at all about the (tiny) bit of CSS I've done or even the HTML, it will focus purely on the JavaScript. All you need to know really is that I've got a <code>div#flash</code> for the flash message, a <code>form</code> for sending a message and that each message is displayed as a <code>li</code> inside a <code>ul</code>. All of our code will go inside a JavaScript object I'm going to call <code>pubsub</code>, although in real life it would most likely be called something more relevant to your app:</p>
<p>var pubsub = {</p>
<p>}</p>
<p>Firstly, lets tackle what happens when a user submits the form. We can use jQuery's <code>submit</code> event to hijack the event & prevent the default action easily enough:</p>
<p>$("form").on("submit", function() {
return false;
});</p>
<p>Then I'm going to want to call my method for dealing with this event. In practise, each module would probably have its own namespace and have its events in there, such as:</p>
<p>pubsub.messages.send
pubsub.messages.receive
pubsub.flash.show
pubsub.flash.hide</p>
<p>But as we have only 3 events, I'm going to keep them in the main <code>pubsub</code> namespace. So lets create our event for the sending of a message. Within our <code>pubsub</code> object, add this method:</p>
<p>sendMessage: function() {
var message = $("input").val();
$("body").trigger("messageReceived", { message: message});
return false;
}</p>
<p>Notice how with <code>.trigger()</code> we can send extra data through as the second parameter, so this makes it easy to send custom data with our custom events. You may have realised, but as part of our system we're going to need to bind our functions to regular DOM events, such as the form <code>submit</code> event. I decided, as there's very few, to create a new method within <code>pubsub</code>, called <code>bindEvents()</code> that will do that for me. Here's the code for all the events we need:</p>
<p>bindEvents: function() {
$("form").on("submit",function() {
pubsub.sendMessage();
return false;
});
$("body").on("messageReceived", function(event,data) {
pubsub.displayMessage(data);
});
$("body").on("messageDisplayed", function(event, data) {
pubsub.flashMessage();
});
}</p>
<p>Note that when we pass data through an event, like we did with <code>messageReceived</code>, we get at it through <code>function(event, data)</code>. By default jQuery passes us lots of information about the event and then custom data is passed as the <em>second parameter</em>.</p>
<p>Obviously, this could (and will) get messy if we had many more events, so again if there were more I'd split these up further into the individual modules, and probably give each module an <code>init()</code> method to do the set up, and then a <code>bindEvents()</code> method for each module to set it up. Speaking of <code>init()</code> methods, I'll add one to <code>pubsub</code> and for now have it just call <code>bindEvents()</code>:</p>
<p>init: function() {
this.bindEvents();
}</p>
<p>Then we can set our entire app up when the DOM is ready with:
$(function() {
pubsub.init();
});
Now, the <code>displayMessage()</code> and <code>flashMessage()</code> methods are fairly straight forward:</p>
<p>displayMessage: function(data) {
$("body").trigger("messageDisplayed");
var li = $("<li>").text(data.message).css("display", "none");
$("ul").append(li);
$("ul>li").last().fadeIn()
},
flashMessage: function() {
$(".flash").text("you've got a new message")
.fadeIn(500, function() {
var that = this;
setTimeout(function() {
$(that).fadeOut(500);
}, 2000);
});
}</li></p>
<p>Notice that every event I trigger is on <code>$("body")</code>. There's no reason I couldn't do it on a particular <code>div</code>, but I like to do it on <code>body</code> as I know that <code>body</code> incorporates everything on the page. The code for each of these methods are pretty straight forward, just a bit of jQuery DOM manipulation.</p>
<p>All the code covered in this article is available on <a href="https://github.com/jackfranklin/JavaScript-Playground--Simple-jQuery-PubSub">My Github as a Public Repository</a>, and if you want to try it, <a href="http://javascriptplayground.com/demos/jquerypubsub/">there's a demo online here</a>.</p>
<p>Now, this might not seem very worthwhile <em>in this instance</em>, but take a moment to think what you would have had code wise, if you had implemented all of the code above within the form's <code>submit</code> event (like I have done in the past with projects, and I'm sure you have too). It would be a complete mess of code, all within one form event. Then imagine you had another method of sending a message. How would you deal with that? You would either have to copy & paste all the code into another event, or trigger the form's <code>submit</code> event. Neither of those solutions are good. With this method though, all you have to do is make that new way of sending messages trigger a <code>messageReceived</code> event & pass the message with it, and then you're set. You could then remove the other way of sending messages, and nothing would break. Another issue is if one module breaks, it <em>shouldn't break the entire application</em>. Having the entire implementation within one function means if just one line fails, the entire application will fall to its knees. With each module firing events, if one module fails and doesn't send the events it's expected to, other modules can still send theirs, and as such one module breaking doesn't bring the application down. This is the advantage of using such a pattern, code resuse, not repeating code & implementing a modular approach.</p>
<p>I will be covering this pattern in large detail over the near future as it's something I've been using a lot recently. I'm aware that this implementation is another post on the JavaScript Playground that uses jQuery, but fear not, in a coming article we will go head on into a basic PubSub written in plain JavaScript. If you can't wait that long, <a href="http://addyosmani.com/resources/essentialjsdesignpatterns/book/#observerpatternjavascript">Addy Osmani's section on the Observer Pattern</a> in his JS Patterns book is well worth your time.</p>
Testing with QUnit: Part 12012-04-14T00:00:00+00:00http://www.jackfranklin.co.uk/blog/javascript-testing-qunit-1/<p>Recently I was asked on Twitter to do a tutorial on <a href="http://qunitjs.com/">QUnit</a>, a JavaScript Unit Testing framework, and the one used by jQuery. What I wanted to do however, is use it with a real project, rather than set up some fake project. So, I've done just that. Having worked with the <a href="http://instagr.am/developer/">Instagr.am API</a> recently, I'm going to use this series of tutorials to write a JavaScript wrapper for the Instagram API & test it with QUnit. Unlike most content on this site, this is going to be a multi-part tutorial, but I hope to still manage to achieve 1-2 specific things within each post. If you've any questions, please leave a comment & I will answer all questions at the beginning of the next tutorial. I'll presume you're vaguely familiar with the idea of Unit Testing in general. At the end of the series you should have a working knowledge of QUnit and how to use it. I'll also open source the Instagram Wrapper we create onto Github. As this series is mainly focusing on testing, I wont highlight how I do everything in terms of querying the Instagram API but I will point out specific bits that I think are useful.</p>
<p><strong>What we will achieve today</strong></p>
<ul>
<li>Set up a QUnit testing suite</li>
<li>Write our first QUnit tests</li>
<li>Query the Instagram API to get information on a specific Instagram Image</li>
<li>Learn how to test Async calls in QUnit</li>
</ul>
<p>The first step is to set up our directory. I like to set mine up like so:</p>
<p>/app
instagramwrapper.js
/test
instagramwrapper_tests.js
/qunitsrc
tests.html</p>
<p>The first thing we need to do is include all the QUnit source. QUnit needs 3 things:</p>
<ol>
<li>We need to include the QUnit JS Source</li>
<li>We can link to the QUnit stylesheet to make the output look good</li>
<li>It needs a specific HTML structure.</li>
</ol>
<p>You can find download links for the JS & CSS files <a href="http://docs.jquery.com/Qunit#Using_QUnit">here</a>. You could include them direct but I like to download them & add them locally, putting them into the <code>qunitsrc</code> directory.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>qunitsrc/qunit.css<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/css<span class="token punctuation">"</span></span> <span class="token attr-name">media</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>screen<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>qunitsrc/qunit.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>app/instagramwrapper.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>test/instagramwrapper_tests.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span></code></pre>
<p>And the HTML structure we need:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>qunit-header<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>QUnit Test Suite<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h2</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>qunit-banner<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h2</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>qunit-testrunner-toolbar<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h2</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>qunit-userAgent<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h2</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ol</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>qunit-tests<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>ol</span><span class="token punctuation">></span></span></code></pre>
<p>Most of those are fairly explanatory. If not, don't worry, once we run an actual test it should become more apparent. Before we write our actual code, lets set up a test test just to make sure it works. Load up <code>instagramwrapper_tests.js</code> (I'll refer to this as just "the tests file" from now on) and put in:</p>
<p>function saysHi(name) {
return "Hi, " + name;
};</p>
<p>test('saysHi()', function() {
equal(sayHi("Jack"), "Hi, Jack", "function outputs string correctly")</p>
<p>});</p>
<p>You can see I define a simple function and then run tests on it, expecting <code>sayHi("Jack")</code> to equal <code>"Hi, Jack"</code>. If you run it however, we get a failure:</p>
<p>saysHi() (1, 0, 1)
Died on test #1: sayHi is not defined
Source: at Object.<anonymous> (http://instagram.jsp/test/instagramwrapper_tests.js:6:10)</anonymous></p>
<p>Why's that? Well, turns out in the <code>equal()</code> call I referenced <code>sayHi</code>, but it's actually <code>saysHi</code>.</p>
<p>Run it again, and it passes!</p>
<p><img src="https://cl.ly/1Y1l0m0T1o0T0E0t2s0H/Screen%20Shot%202012-04-13%20at%2023.15.58.png" alt=""></p>
<p>Now, for our first real test, lets take a look at the Instagram API. Say I have an Instagram URL, such as <code>http://instagr.am/p/JYAdvJr0K9/</code> (which happened to be the first URL I found in my Twitter feed). And I want to get the exact URL to it. When we're testing, we first write tests, see them fail, and then make them pass. Before we dive in, I'll just do a little set up in the main implementation file:</p>
<p>(function() {
var instagramwrapper = {
oembed: {
web_url: "",
}
};
window.instagramwrapper = instagramwrapper;
})();</p>
<p>The reason for the <code>oembed</code> namespace is that the bit of the API we'll be using is <a href="http://instagr.am/developer/embedding/">named as such</a>. So, time to write some tests. I'll write a couple just to check we've set things up correctly, and then we can get into specific tests for this bit. Here's my initial tests:</p>
<p>test('Set Up Tests', function() {
ok(instagramwrapper, "instagram wrapper is exists and is not undefined");
});</p>
<p>test('oembed', function() {
ok(instagramwrapper.oembed, "oembed namespace exists");
instagramwrapper.oembed.web_url = "http://instagr.am/p/JYAdvJr0K9/";
equal(instagramwrapper.oembed.web_url, "http://instagr.am/p/JYAdvJr0K9/", "Can set the web_url correctly");
});</p>
<p>All these tests pass, but one thing was irritating me, and that is that by default QUnit doesn't show all the tests, but just the heading:</p>
<p><img src="https://cl.ly/0Y0M0o121t1I44403m1R/Screen%20Shot%202012-04-13%20at%2023.31.32.png" alt=""></p>
<p>I wanted to change this, so I delved into the QUnit JS source and on line 192 I found:</p>
<p>if (bad === 0) {
ol.style.display = "none";
}</p>
<p>I simply commented out that middle line and now it shows the full details:</p>
<p><img src="https://cl.ly/2b3S191c0Y1z011U1S13/Screen%20Shot%202012-04-13%20at%2023.32.29.png" alt=""></p>
<p>Obviously this is more a personal preference, so if you want to do it, feel free, but if not, that's fine too.</p>
<p>Now I want to write some code to get the media URL that is returned from this API end point: <code>http://api.instagram.com/oembed?url=http://instagr.am/p/BUG/</code>. I could write the Ajax call in a <code>get_url()</code> function but as this query returns a set of data, I'll write a function to take a callback that has the data passed into it, and let the user then grab what they need. I'll also be using jQuery here for the Ajax calls. We could do them in cross browser JS, but that's a huge pain & beyond the scope of this tutorial.</p>
<p>Normally at this stage I'd say to write the test, but we have a problem. How do we test asynchronously?</p>
<p>The obvious answer is to make the Ajax test non-async, but that's not a good solution. Thankfully, QUnit helps us out here with its <code>asyncTest()</code> method.</p>
<p>QUnit has <code>stop()</code> and <code>start()</code> methods which tell the framework to stop its tests, so it can wait for a Ajax call to run and then start the requests again. The <code>asyncTest()</code> method just does the <code>stop()</code> bit for us. So most asynchronous tests look a bit like:</p>
<p>asyncTest("some Ajax call", function() {
someAjaxCall(function(resp) {
//callback
start(); //tell QUnit to run tests again
});
});</p>
<p>And inside the callback, before you call <code>start()</code>, is where you run your assertions that rely on the Ajax result. I've written some tests within the callback that should validate everything works correctly. I then call <code>start()</code> to tell QUnit it can run the rest of its tests again.</p>
<p>test('oembed', function() {
ok(instagramwrapper.oembed, "oembed namespace exists");
instagramwrapper.oembed.web_url = "http://instagr.am/p/JYAdvJr0K9/";
equal(instagramwrapper.oembed.web_url, "http://instagr.am/p/JYAdvJr0K9/", "Can set the web_url correctly");
});
asyncTest("oembed AJAX", function() {
instagramwrapper.oembed.web_url = "http://instagr.am/p/JYAdvJr0K9/";
instagramwrapper.oembed.query(function(res) {
ok(res, "AJAX call got a result");
ok(res.url, "URL exists in response");
equal(res.url, "http://distilleryimage5.instagram.com/9436051c85b011e18cf91231380fd29b_7.jpg", "URL returned is correct");
equal(res.title, "Drainpipe", "The title returned is correct");
start();
});
});</p>
<p>Running these tests (without any implementation, rememeber!) will give you some errors. Now we take the next TDD step. Fix those errors, one at a time. The first will complain about <code>query()</code> being undefined, so add the function, refresh & continue on. You'll hit a bit of a problem here. The tests will just run forever, as that <code>start()</code> never gets called. This is because the function <code>query()</code> exists, but it does nothing. So QUnit doesn't get an error that <code>query()</code> is undefined, so it calls it but then never gets that <code>start()</code> call again. What we can do to prevent this issue is to add a <code>setTimeout</code> after my assertions that will run after 1000 milliseconds, telling QUnit to continue anyway:</p>
<p>setTimeout(function() {
start();
}, 1000);</p>
<p>That gives us the error:</p>
<p>Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.</p>
<p>Another feature is that we can tell QUnit how many assertions we expect, so it knows when that doesn't happen & can tell us. In our case, we expect 4. Two calls to <code>ok()</code>, and two to <code>equal()</code>. We pass this in as the second parameter to <code>asyncTest()</code>:</p>
<p>asyncTest("oembed AJAX", 4, function() {</p>
<p>At this point QUnit gives us the error:</p>
<p>Expected 4 assertions, but 0 were run</p>
<p>I'm not going to show you how to solve all these issues as most are straight forward from here on in, it's a simple Ajax call. Here's my implementation:</p>
<p>query: function(cb) {
var ajxreq = $.Ajax({
url: "http://api.instagram.com/oembed?url=" + this.web_url,
dataType: 'jsonp'
});
ajxreq.success(function(resp) {
cb(resp);
});
}</p>
<p>The code works by taking a callback, that it will automatically pass our data into.
Run the tests, and I'm greeted with all greens, lovely!</p>
<p><img src="https://cl.ly/0J0c3Z3J0r1K3M2a0m0a/Screen%20Shot%202012-04-14%20at%2000.01.33.png" alt=""></p>
<p>That brings us to the end of the first tutorial. In this we've achieved a great deal, learning how QUnit works, how to run async tests in QUnit and working with the Instagram API too. Not bad at all! Next time we will continue writing & testing, but at a bit more of a faster pace, now you've got the hang of QUnit. You can get all the code from the <a href="https://github.com/jackfranklin/JS-Instagram-Wrapper">Github Repo</a>. Each tutorial is on its own branch, for this one you want the branch <em>tutorial1</em>. The <code>master</code> branch will contain the current up to date code, whereas the tutorial branches will only contain the code from each tutorial and no more. Any questions, please leave a comment and I will answer them in part 2.</p>
Scope and this in JavaScript2012-04-16T00:00:00+00:00http://www.jackfranklin.co.uk/blog/javascript-variable-scope-this/<p>Today I want to talk a little about scope in JavaScript and the <code>this</code> variable. The idea of "scope" is that it's where certain functions or variables are accessible from in our code, & the context in which they exist & are executed in.</p>
<p>If you've ever seen someone do something like:</p>
<p>function someFunc() {
var _this = this;
something.on("click", function() {
console.log(_this);
});
};</p>
<p>And wondered what the <code>var _this=this;</code> is all about, hopefully this article should clear it all up.</p>
<p>The first scope is <strong>Global Scope</strong>. This is very easy to define. If a variable or function is <em>global</em>, it can be got at from anywhere. In a browser, the global scope is the <code>window</code> object. So if in your code you simply have:</p>
<p>var x = 9;</p>
<p>You're actually setting the property <code>window.x</code> to 9 (when working in a browser). You could type <code>window.x = 9;</code> if you like, but because it's the global object you don't have to. Properties on the global object can be accessed from anywhere in our code.</p>
<p>The only other scope we can have is <strong>Local Scope</strong>. JavaScript scopes at a function level. For example:</p>
<p>function myFunc() {
var x = 5;
};
console.log(x); //undefined</p>
<p>Since <code>x</code> was initialised within <code>myFunc()</code>, it is only accessible within <code>myFunc()</code>.</p>
<p><strong>A word of Caution</strong></p>
<p>If you declare a variable & forget to use the <code>var</code> keyword, that variable is automatically made global. So this code would work:</p>
<p>function myFunc() {
x = 5;
});
console.log(x); //5</p>
<p>This is a <strong>very bad idea</strong>. It's considered bad practise to clutter the global scope. You should add as fewer properties as you possibly can to the global object. That's why you'll see libraries such as jQuery often do this:</p>
<p>(function() {
var jQuery = { /* all my methods go here */ };
window.jQuery = jQuery.
})();</p>
<p>Wrapping everything in a function which is then immediately invoked means all the variables within that function are bound to the <em>local scope</em>. At the very end you can then expose all your methods by binding the <code>jQuery</code> object to the <code>window</code>, the <em>global object</em>. Although I've simplified it hugely, this is in essence how the jQuery source works. If you want to learn more, <a href="http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source/">Paul Irish's "10 Things I learned from the jQuery Source"</a> is a highly recommended watch.</p>
<p>Because local scope works through functions, any functions defined within another have access to variables defined in the outer function:</p>
<p>function outer() {
var x = 5;
function inner() {
console.log(x); //5
}
inner();
}</p>
<p>But the <code>outer()</code> function doesn't have access to any variables declared within <code>inner()</code>:</p>
<p>function outer() {
var x = 5;
function inner() {
console.log(x); //5
var y = 10;
}
inner();
console.log(y); //undefined
}</p>
<p>That's pretty much all there is too it at a basic level. Things get a bit more complex once we take a look at the <code>this</code> keyword in JavaScript and how it works. I'm sure we've all come across this issue:</p>
<p>$("myLink").on("click", function() {
console.log(this); //points to myLink (as expected)
$.ajax({
//ajax set up
success: function() {
console.log(this); //points to the global object. Huh?
}
});
});</p>
<p><code>this</code> is a variable that is automatically set for you when a function is invoked. The value it's given depends on how a function is invoked. In JavaScript we have a few main ways of invoking functions. I wont talk about them all today, but just the three ways most people use them; either when a function is called as a method, or on it's own, or as an event handler. Depending on how a function is invoked, <code>this</code> is set differently:</p>
<p>function foo() {
console.log(this); //global object
};</p>
<p>myapp = {};
myapp.foo = function() {
console.log(this); //points to myapp object
}</p>
<p>var link = document.getElementById("myId");
link.addEventListener("click", function() {
console.log(this); //points to link
}, false);</p>
<p>Those are all fairly obvious. The MDN has a <a href="https://developer.mozilla.org/en/DOM/element.addEventListener">nice explanation</a> for the third & why this happens:</p>
<blockquote>
<p>It is often desirable to reference the element from which the event handler was fired, such as when using a generic handler for a series of similar elements. When attaching a function using addEventListener() the value of this is changed—note that the value of this is passed to a function from the caller.</p>
</blockquote>
<p>So, now we know that, we are in a position to figure out why <code>var _this = this;</code> is required in the above code.</p>
<p>Doing <code>$("myLink").on("click", function() {})</code> means that when the element is clicked, the function is fired. But this function is bound as an event handler, so <code>this</code> is set to the reference to the DOM element <code>myLink</code>. The success method you define within the Ajax request is <em>just a regular function</em>, and as such when it's invoked, <code>this</code> is set to the global object, as it is when any function that's not an event handler or an object method is.</p>
<p>The above is precisely why you'll see a lot of people doing <code>var _this = this</code> or <code>var that = this</code> or similar, to store the current value. It's also seen by many as what the correct value should be, but that debate is for another day.</p>
<p>$("myLink").on("click", function() {
console.log(this); //points to myLink (as expected)
var _this = this; //store reference
$.ajax({
//ajax set up
success: function() {
console.log(this); //points to the global object. Huh?
console.log(_this); //better!
}
});
});</p>
<p>There are ways in which we can invoke functions by explicitly defining what the value of <code>this</code> should be, but as this has already ended up as a fairly long article, I'll leave those for another day. If you have any questions, please do leave a comment & I will get back to you.</p>
Grunt, a JS Command Line Tool2012-04-19T00:00:00+00:00http://www.jackfranklin.co.uk/blog/grunt-js-command-line-tutorial/<p>Grunt describes itself as:</p>
<blockquote>
<p>Grunt is a task-based command line build tool for JavaScript projects.</p>
</blockquote>
<p>It was released very recently and is authored by <a href="http://benalman.com/">Ben "Cowboy" Alman</a> and lives on the <a href="https://github.com/cowboy/grunt">Github Repository</a>. In this tutorial I'm going to be going through the basics of Grunt, how to install & use it. I will only cover basic usage today, with a follow up post planned for next week.</p>
<p><em>Please note that Grunt is currently in beta and changing fairly regularly, this tutorial was written with Grunt 0.3.9. I will link to newer versions of the tutorial when new versions of Grunt are released.</em></p>
<p>Grunt is installed as a NPM (Node Package Manager) module. If you've not got Node.js & NPM installed, you should do that before proceeding. You can install the package from the <a href="http://nodejs.org/">Node.js</a> website, or if you're on a Mac & have homebrew installed you can get it that way too. You should then <a href="http://npmjs.org/">install NPM</a>, which manages packages for Node. You could draw certain parallels between NPM & Ruby Gems, if you like. Please note that if you use a package install from the Node.js website, that <strong>comes with NPM already</strong>. Only install NPM if you installed from source or via a package manager like homebrew.</p>
<p>Once done, Grunt is installed with a simple <code>npm install -g grunt</code>. The <code>-g</code> flag installs Grunt globally, which means it will be available from anywhere in your terminal, as it's installed to the root <code>node_modules</code> directory. If you only want Grunt to be available when you're within a specific directory, navigate to that directory & run the above command, just without <code>-g</code>. Once that's done you'll get a whole load of terminal output as Grunt & its dependencies are installed. Once done you will see something like this:</p>
<p><img src="https://cl.ly/2G1z461139080p1S3K1g/Screen%20Shot%202012-04-18%20at%2020.15.02.png" alt=""></p>
<p>You can see here that I have installed Grunt and the list of dependencies. If you get a similar output, you're all set, so we can now set up a project.</p>
<p>The first step is to initialise a new project, through Grunt. There's a number of different types of projects we can initialise here as Grunt comes with some handy templates, including specific project set up for <code>commonjs</code>, <code>jquery</code>, and <code>node</code>. Lets create a jQuery project. Make a new directory to house your project and then enter <code>grunt init:jquery</code>. You'll be asked a few questions along the way. Grunt shows the current value set in brackets, and if you don't want to override it, just press enter. Here's what mine looks like:</p>
<p><img src="https://cl.ly/3X280k1h031O0l0Q1u2P/Screen%20Shot%202012-04-18%20at%2019.14.03.png" alt=""></p>
<p>The first file we will take a look in is the <code>grunt.js</code> file, also known as <code>gruntfile</code>. Some of this is a bit overwhelming and might look a bit alien, but don't worry for now. The key bits I'd like to point out is that Grunt has added sections for <code>qunit</code> here, and generated the <code>test</code> directory for us. It's also got instructions for concatenating files, watching files & running tasks on those files automatically when it detects a change in them:</p>
<p>watch: {
files: '<a href="config:lint.files">config:lint.files</a>',
tasks: 'lint qunit'
}</p>
<p>This takes the files from the <code>config:lint.files</code>, which means this part of our config:</p>
<p>lint: {
files: ['grunt.js', 'src/<strong>/*.js', 'test/</strong>/*.js']
}</p>
<p>That tells Grunt to automatically run the <code>lint</code> and <code>qunit</code> tasks (which do exactly what you'd think) whenever any of those files change. Pretty nifty! I will demonstrate this in a moment.</p>
<p>At the end you'll find this line:</p>
<p>grunt.registerTask('default', 'lint qunit concat min');</p>
<p>This tells grunt that if it's not specified a task when it's run, just to run <code>lint</code>, <code>qunit</code>, <code>concat</code> and <code>min</code>. Lets go to our terminal, and enter <code>grunt</code>.</p>
<p>Unfortunately for me, this didn't go to plan:</p>
<p>Running "lint:files" (lint) task
Lint free.</p>
<p>Running "qunit:files" (qunit) task
Testing jquery.jsplayground-demo.html
Running PhantomJS...ERROR</p>
<p>Installing PhantomJS is fairly straight forward, <a href="http://code.google.com/p/phantomjs/wiki/Installation">instructions can be found here</a>. PhantomJS is a headless Webkit, with a JavaScript API, which means we can run tests through it, including QUnit tests. Once you've got it installed, you should see the output look like this:</p>
<p><img src="https://cl.ly/0B0L1t2E273j1900223A/Screen%20Shot%202012-04-18%20at%2019.24.44.png" alt=""></p>
<p><em>(as an aside, I will be covering PhantomJS in more depth in the very near future)</em>.</p>
<p>So, what this script did:</p>
<ol>
<li>Ran JSLint on our code to check it for problems.</li>
<li>Automatically ran QUnit tests for us, without opening a browser.</li>
<li>Concatenated our files into one (although in this instance there is only one)</li>
<li>Minified that concatenated file into a minified JS file.</li>
</ol>
<p>Now, I don't know about you, but I think that's pretty awesome for just one command! Say I want to run those tasks every time, I could edit <code>grunt.js</code> to let me do that. Find the code for <code>watch</code>, which looks like this:</p>
<p>watch: {
files: '<a href="config:lint.files">config:lint.files</a>',
tasks: 'lint qunit'
},</p>
<p>Now, I could add the tasks <code>concat</code> and <code>min</code> to that, but if you remember we defined the <code>default</code> task to do all of this, so I can make the tasks to run on watch simply <code>default</code>:
watch: {
files: '<a href="config:lint.files">config:lint.files</a>',
tasks: 'default'
}
Of course, in reality running the concat & min tasks every time you save is a bit overkill, but I just want to demonstrate what you can do. You may decide to see up new tasks, one to run as default, one to run when you release your code, one to run whilst developing, and so on.</p>
<p>Now, lets take a look at the JS file it initially created for us, which is in <code>src/jquery.jsplayground-demo.js</code>. You will see it put in the license for us, the copyright and the URL to the Github repository - all of which we set up through <code>grunt init:jquery</code> earlier. Now, lets change this file so we can see <code>watch</code> in action. Grunt gives us a few bits of code to get us started, but I'm going to delete some of it, then save the file so I can demonstrate Grunt's watching abilities. First, get the <code>watch</code> task running by entering in the terminal <code>grunt watch</code>. Then, make an edit. I'm going to enter some invalid JS, so we can see JSLint fail. In my plugin file I've typed <code>some rubbish stuff</code>. I save it, and then my terminal automatically updates:</p>
<p><img src="https://cl.ly/2H363C2Y2z1x3B2t3B1U/Screen%20Shot%202012-04-18%20at%2019.52.40.png" alt=""></p>
<p>I'm going to fix that but remove all the jQuery code other than the code for <code>$.fn.awesome</code>. Grunt has tests written for us, so when I save this file, you'll see tests fail. They fail because we're testing code I've just removed.</p>
<p><img src="https://cl.ly/1L343g2G3E0n2x0X1V2F/Screen%20Shot%202012-04-18%20at%2019.56.24.png" alt=""></p>
<p>I remove those tests which are not not needed, and we pass:</p>
<p><img src="https://cl.ly/1I3g3H470i2K3G401h2l/Screen%20Shot%202012-04-18%20at%2019.58.04.png" alt="">.</p>
<p>Just imagine when working on a project, being able to run <code>grunt watch</code> and then happily working on your code, knowing it will be tested, checked & minified every time.</p>
<p>I hope this brief look at Grunt has inspired you to give it a go. I personally have used it in a few projects recently and have really enjoyed it. If you have any questions, please do leave a comment & I will answer them in the next tutorial on Grunt, which I expect will be published in the next week or two. We have only just scratched the surface of what Grunt can do and in the next tutorial we shall further explore everything Grunt has to offer.</p>
QUnit, PhantomJS and Mockjax2012-04-20T00:00:00+00:00http://www.jackfranklin.co.uk/blog/qunit-phantomjs-and-mockjax/<p>Following on from last week's <a href="http://javascriptplayground.com/blog/2012/04/javascript-testing-qunit-1">introduction to QUnit</a> today I want to talk less about how to use QUnit but ways to make it easier to use or integrate it into your development workflow.</p>
<p>A lot of people asked me how to avoid refreshing the QUnit tests page everytime you want to rerun the tests. I was actually using the Mac tool <a href="http://livereload.com/">LiveReload</a> which is currently on the App Store for £6.99. Fear not Windows users, it's coming to Windows too, and is currently in early testing stages, with users able to download & test it now, for free. You assign LiveReload a folder to watch and install the browser plugin. Once you've connected the browser to the app, when the app detects a file has changed it will refresh the browsers. This meant whenever I saved my source file, or my tests file, it would rerun the tests. It's a lovely solution & I would highly recommend it.</p>
<p>Now, being a developer something I immediately wondered was if I could run tests in the terminal. My answer came in the form of <a href="http://phantomjs.org/">PhantomJS</a>. There's a number of ways to install PhantomJS, the easiest if you're on a Mac and use homebrew is to simply run <code>brew install phantomjs</code>. It can be installed on Linux, OS X and Windows. Once you've got that done, you need to get the QUnit JS runner for Phantom, which can be found <a href="https://github.com/ariya/phantomjs/blob/1.2/examples/run-qunit.js">here on Github</a>. Save that into the root directory. You should then be able to run your tests in the command line by:</p>
<p>phantomjs run-qunit.js path/to/tests.html</p>
<p>In my case, I run the tests through a virtual host and you can see that right now it's failing:</p>
<p>phantomjs run-qunit.js http://instagram.jsp/tests.html
'waitFor()' finished in 401ms.
Tests completed in 266 milliseconds.
6 tests of 7 passed, 1 failed.</p>
<p>Why is it failing? Unfortunately you don't get shown the failing tests in the output, which is a shame, however it's nice for a quick test, as in reality you only need to know about a test if it fails. We can head over to the browser and see:</p>
<p><img src="https://cl.ly/1q0u1G1h0n0X1E313w0B/Screen%20Shot%202012-04-20%20at%2014.23.49.png" alt=""></p>
<p>So, it seems Instagram changed the URL where this image is stored that we get from our Ajax call. This is what I want to talk about now. When testing, you can't rely on making actual external Ajax calls. Why not? Imagine that you're on a train, and fancy developing. Without internet, you're stuck when it comes to testing. You also, as we've seen above, can't rely on certain values staying the same so you can test against them. Here you can see a test that worked fine last time round doesn't anymore, all because the URL changed. Our code hasn't, at all. What we need is a way to fake Ajax calls & returned data.</p>
<p>Enter <a href="https://github.com/appendto/jquery-mockjax/">jQuery Mockjax</a>. So, lets mock up a response for the current Ajax call we're making. What I'm going to do is make the API call & copy the data. We can define a new Mocked Ajax call like so (taken from the docs on the Github page):</p>
<p>$.mockjax({
url: '/restful/fortune',
responseTime: 750,
responseText: {
status: 'success',
fortune: 'Are you a turtle?'
}
});</p>
<p>Mockjax will then capture all Ajax requests to <code>/restful/fortune</code> and return the data within <code>responseText</code>. You can also define <code>responseTime</code> to simulate latency. As our response is a fair few lines, I'm actually going to save this in <code>tests/oembed.json</code> and then we'll tell Mockjax to use it shortly. So your <code>tests/oembed.json</code> should look like this:</p>
<p>{
provider_url: "http://instagram.com/",
media_id: "168887029519565501_138023",
title: "Drainpipe",
url: "http://distilleryimage5.s3.amazonaws.com/9436051c85b011e18cf91231380fd29b_7.jpg",
author_name: "joel_hughes",
height: 612,
width: 612,
version: "1.0",
author_url: "http://instagram.com/",
author_id: 138023,
type: "photo",
provider_name: "Instagram"
}</p>
<p>Now lets mock our Ajax call. Within the <code>asyncTest</code> call we created last time, at the top, add in this:</p>
<p>$.mockjax({
url: 'http://api.instagram.com/oembed?url=http://instagr.am/p/JYAdvJr0K9/',
contentType: 'text/json',
proxy: '/test/oembed.json'
});</p>
<p>The <code>url</code> property tells Mockjax to capture any Ajax calls to that URL. We then tell it that the response will be JSON, and then use the <code>proxy</code> pattern to define a response file. That means Mockjax will just send the contents of that file back to the app.</p>
<p>Before we run this, make sure you've downloaded the Mockjax source from Github and have included it in your <code>tests.html</code> file, <strong>before</strong> you include our QUnit tests. Now, if you run it, you'll still get the error in the test. This is expected because we haven't changed the URL to be the new URL Instagram now gives us. If you want to check it's working, head to your console. Mockjax logs to the console everytime it captures a request, which is a nice way to test. In my case I see this line:</p>
<p>MOCK GET: http://api.instagram.com/oembed?url=http://instagr.am/p/JYAdvJr0K9/</p>
<p>So I can be confident it works. Now head into the <code>oembed.json</code> file and copy the <code>url</code> property into our <code>equal()</code> call, so it now looks like this:</p>
<p>equal(res.url, "http://distilleryimage5.s3.amazonaws.com/9436051c85b011e18cf91231380fd29b_7.jpg", "URL returned is correct");</p>
<p>If you run the tests in the command line, you will see the Mockjax log & that all our tests pass:</p>
<p>phantomjs run-qunit.js http://instagram.jsp/tests.html
MOCK GET: http://api.instagram.com/oembed?url=http://instagr.am/p/JYAdvJr0K9/
'waitFor()' finished in 701ms.
Tests completed in 509 milliseconds.
7 tests of 7 passed, 0 failed.</p>
<p>And if you want to double check, you can load up the tests in your browser and see:</p>
<p><img src="https://cl.ly/2d2s103o352J030f0s1W/Screen%20Shot%202012-04-20%20at%2014.44.47.png" alt="">.</p>
<p>So, although we didn't write any more functionality in this post, we've now got Mockjax set up so we can work on it much easier and not rely on a 3rd party service or having an internet connection when we want to do some testing. I highly recommend using Mockjax for all your Ajax queries.</p>
<p>Files for this tutorial can be found on the <a href="https://github.com/jackfranklin/JS-Instagram-Wrapper/tree/tutorial2">tutorial2 branch of the repository</a>.</p>
<p>If you want to explore running JS tests in the command line further, I recommend the JS tool Grunt, <a href="http://javascriptplayground.com/blog/2012/04/grunt-js-command-line-tutorial">which I wrote a tutorial on yesterday</a>, so please do check that out.</p>
<p>As always, any questions, please leave a comment & I'll get back to you!</p>
Exploring Backbone: Part 12012-04-23T00:00:00+00:00http://www.jackfranklin.co.uk/blog/backbone-js-tutorial-1/<p><a href="http://documentcloud.github.com/backbone/">Backbone.js</a> is a framework that lets us structure our applications using a pattern similiar to MVC (technically Backbone is not pure MVC as the C stands for "Collection"). However, Backbone is a powerful system to use when creating apps that are beyond very basic. When passing & manipulating a lot of data, you should consider using something like Backbone.</p>
<p>Since launching this blog I've had a lot of people ask me about Backbone. Although there are a lot of very good resources out there, I have struggled to get to grips with it myself and from the requests I've had I'd suggest a lot of others have too. So, I sat down to create a sample application with Backbone, and in this tutorial - which will span at least 3 parts - we will create a very simplified shopping cart application, with Backbone. As always the source will be on Github and is linked to at the end of this post.</p>
<p>The first thing to do is set up our basic page and include our dependencies. Backbone relies on Underscore.js, a set of utility functions written by Backbone's creator, Jeremy Ashkenas (who also created CoffeeScript). You need to download Underscore.js, Backbone.js & include jQuery too, which I do from the Google CDN. The Backbone link can be found above at the beginning of this article, and <a href="http://documentcloud.github.com/underscore/">here's the link for Underscore.js</a>. I've also created a stylesheet & <code>cart.js</code>, which is where the majority of our code will go:</p>
<p><!DOCTYPE html>
<html>
<head>
<title>Shopping Cart with Backbone</title>
<link rel="stylesheet" type="text/css" href="http://www.jackfranklin.co.uk/blog/backbone-js-tutorial-1/css/style.css">
</head>
<body>
<div id="yourcart"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="http://www.jackfranklin.co.uk/blog/backbone-js-tutorial-1/js/underscore.js"></script>
<script src="http://www.jackfranklin.co.uk/blog/backbone-js-tutorial-1/js/backbone.js"></script>
<script src="http://www.jackfranklin.co.uk/blog/backbone-js-tutorial-1/js/cart.js"></script>
</body>
</html></p>
<p>The first thing we want to do is create a model. A model is a way we can represent data in an application, and the objects that we have in our application. We're going to have just one thing today, which is items, which sit in a shopping cart. The convention is to name a model as singular & capitalise it, so our model will be <code>Item</code>. To create a model we extend <code>Backbone.Model</code> like so:</p>
<p>var Item = Backbone.Model.extend({
defaults: {
price: 35,
photo: "http://www.placedog.com/100/100"
}
});</p>
<p>Here I set up the default values for my item. It's going to have three fields, a title, price & then a photo. Whilst I don't want to set a default title, I set the defaults for the other properties. <a href="http://documentcloud.github.com/backbone/#Model-extend">There's a lot you can do by extending models</a> which I will revist in a future tutorial. If you fancy reading some more now, check out that link to the documentation. Now new items can be created easily. Load up <code>index.html</code> in the browser & try this out in the command line:</p>
<p>var football = new Item({title: "Football"});
football.get("title"); //"Football"
football.get("price"); //35
football.get("photo"); //http://www.placedog…</p>
<p>However, this functionality on its own is not very good. We need some way of managing sets of data, and this is where Collections come in. We can create a new collection which will store data, and tell it which model to use:</p>
<p>var Cart = Backbone.Collection.extend({
model: Item
});</p>
<p>Now refresh the page, load up the console & try this:</p>
<p>var collection = new Cart({title: "football"});
collection.at(0).get("price"); //35</p>
<p>You can initialise a collection by passing it either a single object or an array of objects, all of which it will presume are instances of the model we specified above It will then use the values passed to create an instance of the model for each object passed in. The <code>at()</code> method gets an object at a specific index and returns it.</p>
<p>Now we have a collection & a model, we've done the "MC" bit of "MVC". So lets hook it up into a view to explore the basics of views in Backbone & then we'll wrap this up for today.</p>
<p>Firstly, we need some sample data to work with, so I'm going to create some sample items and initialise our <code>Cart</code> collection with them:</p>
<p>var items = [
{ title: "Macbook Air", price: 799 },
{ title: "Macbook Pro", price: 999 },
{ title: "The new iPad", price: 399 },
{ title: "Magic Mouse", price: 50 },
{ title: "Cinema Display", price: 799 }
];</p>
<p>var cartCollection = new Cart(items);</p>
<p>Each view you create should be responsible for a small part of your application. I want to end this tutorial by showing all the items we have on the page, laid out neatly. Rather than having 1 view & dealing with everything in there, I'm going to set up two. The first will be the template for an individual item, and the second will be for showing every single item. Before we write the JS, we need to make a quick HTML template for it, using the templating engine that comes with Underscore. These should go within script tags in <code>index.html</code>:</p>
<script id="itemTemplate" type="text/template">
<img src="<%= photo %>" alt="<%= title %>">
<div>
<h2><%= title %></h2>
<h4>£<%= price %></h4>
</div>
</script>
<p>You can see what will happen here. Where I've used <code><% = title %></code>, that will be replaced with the item's title, and so on. I've given it a type of <code>text/template</code>, if we used <code>text/javascript</code>, the browser would try (and fail) to parse it.</p>
<p>Now I can write the JS for the view for a <em>single item</em>:</p>
<p>var ItemView = Backbone.View.extend({
tagName: "div",
className: "item-wrap",
template: $("#itemTemplate").html(),</p>
<p>render: function() {
var templ = _.template(this.template);
this.$el.html(templ(this.model.toJSON()));
return this;
}
});</p>
<p><code>tagName</code> and <code>className</code> tells Backbone to wrap the template within a <code>div</code> with a class of <code>item-wrap</code>. We give it the template, grabbing the code from our <code>script</code> tag. The default for <code>tagName</code> is <code>div</code>, so I could haveb left it out, but I wanted to put it in to highlight the fact it exists. The <code>render</code> method just uses Underscore's <code>template()</code> method to parse the template. We then call it with a JSON representation of the current model - which for this view will be an individual item. <code>$el</code> is a variable automatically set for us which stores a jQuery reference to the current object. Backbone does this for us to save us a bit of time and it comes in very handy. Note that in the <code>render</code> method we return <code>this</code>. This is so we can call this method from another view, and get access to the returned data. Whenever a view is rendered, one of the properties it has is <code>el</code>, which is the fully compiled template, with every <code><%= title %></code> substituted for the correct value and so on. We will use this in our next view.</p>
<p>On its own however, this view doesn't serve a purpose. Right now it will render some HTMl for each individual item, but as I said earlier we want to write another view that shows all the items. This one is a bit more complex:</p>
<p>var CartCollectionView = Backbone.View.extend({
el: $("#yourcart"),
initialize: function() {
this.collection = cartCollection;
this.render();
},
render: function() {
this.collection.each(function(item) {
this.renderItem(item);
}, this);
},
renderItem: function(item) {
var itemView = new ItemView({ model: item });
this.$el.append(itemView.render().el);
}
});</p>
<p>Don't panic! We shall work through this line by line. Right at the beginning, you will see I hard coded into <code>index.html</code> the <code>div</code> with an id of "yourcart". Here I give Backbone a reference to it. From this Backbone will also create <code>this.$el</code>, a jQuery reference to the element. Of course, I've actually done this already by setting <code>el</code> to be <code>$("#yourcart")</code> but it's still handy to know.</p>
<p>The <code>initialize()</code> method tells the view which collection to use, which I set to <code>cartCollection</code>, which we set up earlier. I then make it call its own <code>render()</code> method. The <code>render</code> method takes the collection, and then uses <code>each</code> to loop through each item within the collection. The first argument is the iterator function, in which I just call <code>renderItem()</code>, passing the item in. The second argument is the context, which I pass in as <code>this</code>. This means the function is invoked with the value of <code>this</code> equal to whatever <code>this</code> was when it was invoked. In my case, this will mean <code>this</code> refers to the <code>CartCollectionView</code> object</p>
<p>Finally, <code>renderItem()</code> takes an item, creates a new <code>ItemView()</code> for that specific Item, passing in the <code>model</code> property. From there we append the compiled <code>ItemView</code> template (remember the discussion about returning <code>this</code> within <code>ItemView</code> earlier? This was why) to <code>this.$el</code>, which is <code>$("#yourcart")</code>.</p>
<p>That's it. Although the code looks pretty overwhelming on the surface, once you look into it it's not so bad. Finally, all we need to do is instantiate a new instance of our main view when the DOM is ready:</p>
<p>$(function() {
var cart = new CartCollectionView();
});</p>
<p>And then (after a quick bit of CSS) you'll see this:</p>
<p><img src="https://img.skitch.com/20120422-k2f196g9jeuw8578hxcsb591i8.jpg" alt=""></p>
<p>I'm not going to cover the CSS, as I'm no designer, but it's in the repository if you want to take a look. It's hardily design of the century, mind.</p>
<p>So, at this point we're done for today. We've done a lot of stuff, but I bet you've got a lot of questions, such as:</p>
<ul>
<li>How do I add to a collection after initialising it?</li>
<li>How can I show a filtered set of my objects?</li>
<li>How do I let a user add a new item?</li>
<li>How do I unit test my Backbone applications?</li>
<li>Can I use Backbone.js with CoffeeScript?</li>
</ul>
<p>And plenty more. I hope to answer all of the above & more in the future. Backbone is a big topic, there's lots of cool stuff it's capable of & today we've really barely scratched the surface. As always, any questions please leave a comment & I will answer them all in the next part, which will come soon. Code for this tutorial is <a href="https://github.com/jackfranklin/JS-Playground-Backbone">on the Github repository</a>.</p>
Beginning Node.js2012-04-25T00:00:00+00:00http://www.jackfranklin.co.uk/blog/beginning-node-js-express-tutorial/<p>Unless you've been living under a rock for the past 12 months or so, you've probably heard of <a href="http://nodejs.org/">Node.js</a>. Simply put, Node is JavaScript on the server.</p>
<p><em>Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.</em> (taken from the Node.js homepage).</p>
<p>Node takes JavaScript onto the server, which means it's possible to write your entire application in JavaScript, using it for both the server side, handling requests & rendering views, and then on the front-end as we always have done. Whilst this isn't going to be an official tutorial series, I'll be writing a fair bit on Node in the future.</p>
<p>Today we will look at installing Node & the package manager, NPM (really easy) and then the traditional "Hello World" tutorial. Once that's done we will take a look about other resources to make Node development easier, then in future tutorials we will use them.</p>
<p>There's two ways to install Node. You can download the official package from the <a href="http://nodejs.org/">website</a>. Node runs on Linux, OS X & Windows. A word of warning: I am a Mac user myself and throughout this tutorial I will be using it exclusively. Although everything should work independent of OS, I wont be checking it myself.</p>
<p>If you're a Homebrew user (a package manager for OS X) you can get Node with <code>brew install node</code> and then NPM with: <code>curl http://npmjs.org/install.sh | sh</code>. NPM is Node's package manager, similar to how Rubygems manages Gems. Despite its relative infancy, there are a lot of very useful packages out there. It's worth having Node & NPM installed just for convenience. A large amount of JS resources are installed via NPM, including CoffeeScript & Grunt.js.</p>
<p>Now we've got it installed, lets do the "Hello World" example. Create a new directory & within that create <code>helloworld.js</code>. The idea here is that we will create a simple server, that when we visit a page will give us a plain text page back with just the line "Hello World" in. To do this we want to use the <code>http</code> package, which is installed by default. In Node to load in a module or package you've installed, we use <code>require</code>:</p>
<p>var http = require('http');</p>
<p>Once we've done that we can then get at the methods within that module through the <code>http</code> variable.</p>
<p>The next step is to create a server, which is done through the <code>createServer</code> method, which takes a function as its argument. This function is passed in details on the request & the response:</p>
<p>http.createServer(function(req, res) {
});</p>
<p>Within this function all I wanted to do is return a plain text page with the line "Hello World". It's really easy:</p>
<p>res.writeHead(200, {'Content-Type' : 'text/plain'});
res.end('Hello World\n');</p>
<p>The first line writes the HTTP header, including the status & more importantly the content type, which in this instance is just plain text. I then end the response from the server with the line "Hello World".</p>
<p>Finally, we need to tell the server to listen on a specific URL & port. We can chain this onto the <code>createServer</code> method:</p>
<p>http.createServer(function(req, res) {}).listen(1337, '127.0.0.1');</p>
<p>Putting that all together, we get:
var http = require('http');
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type' : 'text/plain'});
res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
To run this, run <code>node helloworld.js</code> in your terminal, and then visit <code>http://127.0.0.1:1337</code> in your browser. You should see:</p>
<p><img src="https://cl.ly/3b2t2r1Z3y3o3W2u0x2O/Screen%20Shot%202012-04-25%20at%2000.03.12.png" alt=""></p>
<p>It's as easy as that. However, in most real world projects, people don't tend to just use Node. There's a few frameworks that have sprung up. The most popular at the moment is <a href="http://expressjs.com/">Express JS</a>. I will be covering Express in much more detail in future tutorials, however for now lets see how we'd achieve the "Hello World" demo in Express. Once you start writing an app that has a lot of dependencies, it's a good idea to keep track of them. In Rails you have a Gemfile, in Node & NPM you have <code>package.json</code>. Create this in the root directory and just give it a name & version:</p>
<p>{
"name" : "JS Playground Hello World",
"version" : "0.0.1"
}</p>
<p>To install express, in your terminal type <code>npm install express --save</code>. This will install express but also add it to your <code>package.json</code>. If you take a look at <code>package.json</code> now, you'll see:</p>
<p>{
"name": "JS Playground Hello World",
"version": "0.0.1",
"dependencies": {
"express": "~2.5.9"
}
}</p>
<p>This means if someone clones our project, for example, they can go into the directory & run <code>npm install</code>. NPM then looks at our <code>package.json</code> file and automatically installs the dependencies. This makes it easier all round. It's worth noting two things:</p>
<ul>
<li>NPM only updated our <code>package.json</code> because I passed it the <code>--save</code> flag. If I hadn't done that, it would not have touched the JSON file.</li>
<li>If your <code>package.json</code> is invalid, NPM will NOT update it & also will not show any error messages, so be careful. This had me stuck for a while (in my opinion they would be better off showing an error message).</li>
</ul>
<p>Right, so we now have Express installed, so lets take a look at that "Hello World". The first thing we do is require express. We can do this through <code>require()</code>. We can also immediately use Express' <code>createServer()</code> method to set it up. This returns an object with all the methods we need, so I save that to a variable <code>app</code>:</p>
<p>var app = require('express').createServer();</p>
<p>Then we need to tell it that when the user visits the index page, to just send back "Hello World". This is very straight forward:</p>
<p>app.get('/', function(req, res) {
res.send("Hello World");
});</p>
<p>This says that when we receive a <code>GET</code> request to <code>/</code> (the index / home page), to send back the text "Hello World". Easy as that. Finally, we need to give it a port to listen on:</p>
<p>app.listen(3000);</p>
<p>Putting that together gives us:</p>
<p>var app = require('express').createServer();
app.get('/', function(req, res) {
res.send("Hello World");
});</p>
<p>app.listen(3000);</p>
<p>Run it again like before:</p>
<p>node helloworld.js</p>
<p>And visit <code>http://127.0.0.1:3000</code>. You'll see exactly the same as last time. You can see hopefully that doing things with Express makes sense. It does a lot of the work for us. I'll be exploring Express in further tutorials.</p>
<p>With that it's time to round up this article. Hopefully this has served as a good introduction to Node.js & NPM. In future tutorials I'll be doing all sorts of things with Node & Express, as well as other things, including:</p>
<ul>
<li>Creating a Node module</li>
<li>Using CoffeeScript with Node</li>
<li>Unit testing Node applications</li>
</ul>
<p>And a whole lot more. As always, if you have any questions, feedback or requests for future tutorials, please do leave a comment.</p>
A jQuery Plugin with Grunt & QUnit2012-04-27T00:00:00+00:00http://www.jackfranklin.co.uk/blog/a-jquery-plugin-with-grunt-qunit/<p>Today we're going to take a look at writing a jQuery plugin. There's a number of different ways to go about structuring jQuery plugins & hence a lot of tutorials differ. I'll show you how I would do it but also show examples of how others would do it & link you to alternative views. Along with developing the plugin, we will test it with unit tests through QUnit (my new favourite thing <a href="http://javascriptplayground.com/blog/2012/04/javascript-testing-qunit-1">which I covered a couple of weeks back</a>) and build it all with Grunt.js, <a href="http://javascriptplayground.com/blog/2012/04/grunt-js-command-line-tutorial">which I covered last week</a>. I'll be presuming some basic knowledge of jQuery, QUnit & Grunt; if you're not familiar with either Grunt or QUnit, those links above to previous tutorials should get you going.</p>
<p>To write this tutorial, I wanted to come up with a proper idea for a plugin and I decided to take a look at the first jQuery plugin I ever wrote, which was called "jQuote". This plugin takes some text & creates a quote from it as a <code>blockquote</code> element, the idea being then it can be styled as a pull quote, much like you see in magazines. This plugin was written as my first and consequently I don't like it. Today I'm going to show you how I'd go about rewriting it, more effectively and with unit tests. In fact, I won't even test it in the browser until the very end, as all the development will be test driven.</p>
<p>So, the first thing I'm going to do is set up a new directory for my plugin, which this time round is going to be called jQuery PullQuote. I create a Git repository, and then run <code>grunt init:jquery</code> to set up a new jQuery plugin project. Grunt asks me questions about my project & after answering them I'm left with a project set up. I then add them all to Git and here's what Grunt's made for me:
create mode 100644 LICENSE-GPL
create mode 100644 LICENSE-MIT
create mode 100644 README.md
create mode 100644 grunt.js
create mode 100644 libs/jquery/jquery.js
create mode 100644 libs/qunit/qunit.css
create mode 100644 libs/qunit/qunit.js
create mode 100644 package.json
create mode 100644 src/jquery.pullquote.js
create mode 100644 test/jquery.pullquote.html
create mode 100644 test/jquery.pullquote_test.js
You can see it's given me everything I need. Making a jQuery plugin means we should use QUnit, as QUnit is the testing framework of choice for jQuery. Lets head into <code>src/jquery.pullquote.js</code> and get coding. Grunt gives us a bit of a framework:</p>
<p>/*
* jquery.pullquote
* https://github.com/jackfranklin/jquery.pullquote
*
* Copyright (c) 2012 Jack Franklin
* Licensed under the MIT, GPL licenses.
*/</p>
<p>(function($) {</p>
<p>// Collection method.
$.fn.awesome = function() {
return this.each(function() {
$(this).html('awesome');
});
};</p>
<p>// Static method.
$.awesome = function() {
return 'awesome';
};</p>
<p>// Custom selector.
$.expr[':'].awesome = function(elem) {
return elem.textContent.indexOf('awesome') >= 0;
};</p>
<p>}(jQuery));</p>
<p>I'm going to be using the first approach:</p>
<p>$.fn.pullQuote = function(opts) {
opts = $.extend({}, $.fn.pullQuote.options, opts);
};</p>
<p>$.fn.pullQuote.options = {
outputClass: "pullquote",
outputElem: "blockquote",
insertAfter: "elem"
};</p>
<p>In one step there a fair amount has happened, so lets take a moment to have a look. I've set up my function as <code>$.fn.pullQuote</code> which means it gets called on a jQuery collection, for example: <code>$("span").pullQuote();</code>. You can also pass in an optional object of options. The line:</p>
<p>opts = $.extend({}, $.fn.pullQuote.options, opts);</p>
<p>Takes anything I have in <code>opts</code>, overrides that property in <code>$.fn.pullQuote.options</code> and stores the formed object into <code>opts</code>, which overrides the <code>opts</code> passed into the function.</p>
<p>The reasoning for doing this is so people can override our defaults on a global level. If this plugin is being used 3-4 times, it's quicker to change <code>$.fn.pullQuote.options</code> than pass it into <code>$("span").pullQuote()</code> every time. However, I've written this code, but not tested it! Lets quickly write some tests:</p>
<p>test("defaults", function() {
ok($.fn.pullQuote.options, "options set up correctly");
equal($.fn.pullQuote.options.insertAfter, "elem", "default global options are set");
$.fn.pullQuote.options.insertAfter = "test";
equal($.fn.pullQuote.options.insertAfter, "test", "can change the defaults globally");
});</p>
<p>You can run them through grunt with <code>grunt qunit</code>. Alternatively, you can run <code>grunt watch</code> and it will run the tests for you when save a file. Those tests all pass, so we're on the right track.</p>
<p>From now on, I'll write the tests first, as I should. Because our plugin interacts with DOM elements, I need to create some test HTML for us to work with. QUnit lets us put this in a <code>div</code> with an id of <code>qunit-fixture</code>. We can then get at this HTML in our tests, so this is a useful way to test plugins that interact with & manipulate the DOM. I'm going to create <code>span</code> with some text. The plugin should take this text and add a new quote after the <code>h2</code>.</p>
<p><div id="qunit-fixture">
<p>this is some text <span>with a totally awesome quote</span></p>
<div><h2>Quote</h2></div>
</div></p>
<p>The first thing I want to ensure is that my plugin is chainable. People should be able to do <code>$("span").pullQuote().fadeOut().addClass("foo")</code>, as they can with all jQuery methods. Here's the test I use:</p>
<p>test("chainable", function() {
ok($("p span").pullQuote().addClass("testing"), "can be chained");
equal($("p span").attr("class"), "testing", "class was added correctly from chaining");
});</p>
<p>The logic here is to call PullQuote, then add a class, and then check that the element was indeed given that. Passing this test is easy. After our <code>opts = $.extend();</code> line, add in:</p>
<p>return this.each(function() {
});</p>
<p><code>this</code> refers to the collection the plugin was called on as a jQuery object, so by returning it we're returning the jQuery object which means we can chain. Within the <code>each</code> is where we'll add the code to make it work.</p>
<p>So now we've got the basics out the way, I want to write the tests in their entirity for the functionality. I've set up my test HTML in <code>#qunit-fixture</code> so I'll use that for the tests. I want to take the text within the <code>span</code> and create a new element after the <code>h2</code>.</p>
<p>test("functionality", function() {
$("p span").pullQuote({
insertAfter: "div h2"
});
ok($("div blockquote").length, "the blockquote has been created");
equal($("div blockquote").text(), "with a totally awesome quote", "it gets the right text");
ok($("div blockquote").hasClass("pullquote"), "applies class correctly");</p>
<p>});</p>
<p>This checks that <code>div blockquote</code> is now valid, because after <code>pullQuote</code> is called it should create that for us. It then makes sure the text matches, and that it has the class set in the options. I also want to write tests to check the defaults can be overwritten fine:</p>
<p>test("changing defaults", function() {
$("p span").pullQuote({
insertAfter: "div h2",
outputClass: "testQuote",
outputElem: "p"
});
ok($("div p.testQuote").length, "the blockquote has been created");
equal($("div p.testQuote").text(), "with a totally awesome quote", "it gets the right text");
});</p>
<p>That does much the same as the prior tests, but this time overriding the defaults & then checking the plugin took them into account. The actual code to implement this is really simple:</p>
<p>return this.each(function() {
var elem = $(this),
text = elem.text(),
newElem = $("<" + opts.outputElem + "/>", {
"class": opts.outputClass,
text: text
}).insertAfter(opts.insertAfter);
});</p>
<p>Line by line, we:</p>
<ol>
<li>Wrap the current item in a jQuery object,</li>
<li>Get the text & store it.</li>
<li>Create a new element of the type the option is set as,</li>
<li>Add the class set in options & the text we got earlier,</li>
<li>Insert it after whatever selector is in <code>insertAfter</code>.</li>
</ol>
<p>Running the tests now should give you a full passing suite of 10 assertions.</p>
<p>Now this plugin is very basic, and there's a lot more I want to expand on, but for now that will do, and I will revist this in the future. For now, lets imagine I want to release this onto Github. To do this, we'll harness the power of Grunt. Run <code>grunt</code> in the command line. This will execute grunt's default task, which by default will:</p>
<ol>
<li>Run the code through JSLint</li>
<li>Run the test suite</li>
<li>Concatenate all your JS src files into one.</li>
<li>Minify them.</li>
</ol>
<p>If at any stage there are errors (say your tests fail), it will stop. It's now created the files <code>dist/jquery.pullquote.js</code> and <code>dist.jquery.pullquote.min.js</code> for us. Just like that. After that all I have to do is commit them, and then <a href="https://github.com/jackfranklin/jquery.pullquote">push them to Github</a>.</p>
<p>I hope this article has shown you what I think is a good workflow for developing a jQuery Plugin, using Grunt to do a lot of the hard work for us (I absolutely love using Grunt) and writing Unit Tests. The functionality implemented here is very, very basic but I wanted this to serve as an introduction, I've got tutorials planned soon that attempt to implement much more complicated functionality. As always, please leave a comment & I will get back to you.</p>
Node.js: A Todo App with Express2012-04-30T00:00:00+00:00http://www.jackfranklin.co.uk/blog/node-js-a-todo-app-with-express/<p>So <a href="http://javascriptplayground.com/blog/2012/04/beginning-node-js-express-tutorial">last time</a> we installed Node & did the traditional "Hello World" example with Node & then using the Express framework. Today we're going to make a simple app using Express from the beginning. We will generate the app with Express & then explore Express further, including Unit testing. This will most likely be a multi-part tutorial. The app we're building is a very simple "To Do" application. I know it's boring, but it's simple enough that we can focus on Express & Node rather than the implementation of the app.</p>
<p>The first thing to do is install Express globally:</p>
<p>npm install express -g</p>
<p><em>I am presuming here basic knowledge of Node, NPM & Express. If you're not familiar, you might be best off <a href="http://javascriptplayground.com/blog/2012/04/beginning-node-js-express-tutorial">reading my tutorial from last week</a> before continuing</em>.</p>
<p>Installing Express globally will give us the <code>express</code> command in our command line & we can use this to generate our new app:</p>
<p>express new JSPlaygroundToDo</p>
<p>You should see something like this:
→ express new JSPlaygroundToDo
create : JSPlaygroundToDo
create : JSPlaygroundToDo/package.json
create : JSPlaygroundToDo/app.js
create : JSPlaygroundToDo/public
create : JSPlaygroundToDo/public/javascripts
create : JSPlaygroundToDo/public/images
create : JSPlaygroundToDo/public/stylesheets
create : JSPlaygroundToDo/public/stylesheets/style.css
create : JSPlaygroundToDo/routes
create : JSPlaygroundToDo/routes/index.js
create : JSPlaygroundToDo/views
create : JSPlaygroundToDo/views/layout.jade
create : JSPlaygroundToDo/views/index.jade
dont forget to install dependencies:
$ cd JSPlaygroundToDo && npm install</p>
<p>Express has set up the basic skeleton of our application for us. Lets make sure we've got all the dependencies, so cd into the folder & run <code>npm install</code>. This will check every package in <code>package.json</code> is indeed installed.</p>
<p>Once that's done, lets just run it & see what we have. In the command line type <code>node app.js</code> to run the app, and then head to <code>http://localhost:3000</code>. You should, if everything's working, see this:</p>
<p><img src="https://cl.ly/3P2u133L0v2C3J3M1A2Y/Screen%20Shot%202012-04-29%20at%2017.38.26.png" alt=""></p>
<p>One thing that confused me here is that many tutorials say that running <code>npm start</code> should run your server, but for me it didn't. This is because NPM looks for a file named server.js, and ours is called app.js. There's two choices here:</p>
<ul>
<li>Rename <code>app.js</code> to <code>server.js</code>.</li>
<li>Tell NPM to look for <code>app.js</code>.</li>
</ul>
<p>Either is fine, I'm going to do the latter. Bear in mind if you rename to <code>server.js</code>, from now on in this tutorial where I refer to <code>app.js</code>, you need to use server.js. To do this, add this to <code>package.json</code>:</p>
<p>, "scripts" : {
"start": "node app.js"
}</p>
<p>You will notice there the random comma at the start of that snippet. By default NPM structures its package.json file like that, to avoid you missing out commas:</p>
<p>{
"name": "application-name"
, "version": "0.0.1"
, "private": true
, "dependencies": {
"express": "2.5.8"
, "jade": ">= 0.0.1"
}
, "scripts" : {
"start": "node app.js"
}
}</p>
<p>Whilst I'm not a fan personally, I'll happily abide by it when working with Express. As I mentioned last time, if your JSON file is broken, you wont get any errors, it just wont work, so be careful when editing it.</p>
<p>Now, running <code>npm start</code> does indeed work:</p>
<p>→ npm start</p>
<p>> application-name@0.0.1 start /Users/JackFranklin/Dropbox/Sites/JSPlaygroundToDo
> node app.js</p>
<p>By default, Express uses the <a href="http://jade-lang.com/">Jade</a> templating engine. This is a bit odd at first, but actually I grew to like Jade quickly. In future tutorials I'll show you how to change from Jade if you'd rather, but for now we'll stick with it. Head to <code>views/index.jade</code> to see our index page:
h1= title
p Welcome to #{title}
<code>h1= title</code> just says that we should create a new <code>h1</code> element and put within it the contents of <code>title</code>, which is a variable we set when the template is called.</p>
<p><code>p Welcome to #{title}</code> creates a new paragraph and sets the text, where <code>#{title}</code> will be replaced with whatever we call the variable. So, lets see how we render a view. In <code>app.js</code>, you will see:</p>
<p>app.get('/', routes.index);</p>
<p>So, when a GET request is fired to <code>/</code>, it calls the method <code>routes.index</code>, which is defined in <code>routes/index.js</code>:</p>
<p>exports.index = function(req, res){
res.render('index', { title: 'Express' })
};</p>
<p>So you can see here all this function does is render the <code>index</code> view, setting the <code>title</code> variable to "Express". Lets see how we might create an about page, at the url <code>/about</code>. Head over to <code>routes/index.js</code> and add in:</p>
<p>exports.about = function(req, res){
res.render('index', { title: 'About' })
};</p>
<p>Here I'm still rendering the <code>index</code> view but passing in a title of <code>About</code>. Then, within <code>app.js</code>:</p>
<p>app.get('/about', routes.about);</p>
<p>You may be wondering how <code>app.js</code> knows about <code>routes.about</code> when we defined this as <code>exports.about</code> in our routes file. This is because right at the top of <code>app.js</code> we have:
var express = require('express')
, routes = require('./routes');</p>
<p>You can see here we set the variable <code>routes</code> to the result of loading in the <code>routes</code> folder. Then, within <code>routes/index.js</code>, when we define <code>exports.about</code>, <code>routes</code> gets set to the value of <code>exports</code>.</p>
<p>So, quit & start the server, and head to <code>http://localhost:3000/about</code>. You will see:</p>
<p><img src="https://cl.ly/1g2r340j3H0e0p160F1y/Screen%20Shot%202012-04-29%20at%2018.34.36.png" alt="">.</p>
<p>You might notice there we had to restart the server for these changes to take affect. This gets very annoying, very quickly. Having to stop & start the Node server whenever we make a single change is not what I want to be doing. Thankfully, others thought this too and there are solutions to stop us having to do this. One such person who thought this is Remy Sharp, who made <a href="http://remysharp.com/2010/10/12/nodejs-rapid-development-nodemon/">nodemon</a> to do this for us. Install it with <code>npm install nodemon -g</code> and then launch the server again with:</p>
<p>nodemon app.js 3000</p>
<p>You'll see everything now works. However, now head into <code>routes/index.js</code> and change anything. You will see in your terminal this output:</p>
<p>29 Apr 18:37:47 - [nodemon] restarting due to changes...
29 Apr 18:37:47 - [nodemon] /Users/JackFranklin/Dropbox/Sites/JSPlaygroundToDo/routes/index.js
29 Apr 18:37:47 - [nodemon] starting <code>node app.js 3000</code>
Express server listening on port 3000 in development mode</p>
<p>You see what just happened here? Nodemon detected a file change & restarted our server for us. Easy. I'll be using nodemon from now on to start our server, although the times we have to do it manually will be far less now, thanks to nodemon.</p>
<p>One thing that bugs me is that the routes file is called <code>index.js</code>. You might think differently, but for me that suggests that <code>index.js</code> deals just with the index route. I prefer mine to be called <code>routes.js</code>. If you'd like to do the same, rename <code>routes/index.js</code> to <code>routes/routes.js</code>:</p>
<p>→ mv routes/index.js routes/routes.js</p>
<p>Then in <code>app.js</code>, change the <code>require()</code> call to:</p>
<p>routes = require('./routes/routes');</p>
<p>And run the server again. You should see it all working, nothing should have changed. Feel free to change the routes file to whatever you like. In the future we will explore how to have multiple route files, if you prefer to set your app up like this.</p>
<p>To wrap this up, I want to talk briefly about Jade. You may have realised our template was very bare, we just have a <code>h1</code> and <code>p</code> right now. There's actually another template file, <code>views/layout.jade</code> which defines our general template:</p>
<p>!!!
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body!= body</p>
<p>The first line creates a Doctype, however the doctype it produces is an xHTML doctype. I prefer to use the HTML 5 doctype, which we can do just by replacing <code>!!!</code> with <code>doctype5</code>. Note that Jade files are compiled on request, so they do not require a server restart.</p>
<p>The next line creates the <code>html</code> tag. Instead of having opening & closing tags, we indent in to show the structure of our template. The other lines are fairly obvious. The most important line is:</p>
<p>body!= body</p>
<p>When you call <code>render</code> on a view, the contents of that view are placed into <code>layout.jade</code> as the <code>body</code> variable. <code>!=</code> is used here to tell Jade not to escape the contents of the body variable. By default Jade will use <code>=</code>, which tells it to escape the variable, but as we're passing in HTML to the <code>body</code> variable, we don't want Jade to escape it.</p>
<p>With that I think it's time to call it a day. If you'd like to check out the code, <a href="https://github.com/jackfranklin/node-todo">it's on Github</a>. Next time we will actually make steps towards making our Todo application and talk about unit testing in Node.</p>
A jQuery Plugin in CoffeeScript2012-05-04T00:00:00+00:00http://www.jackfranklin.co.uk/blog/a-jquery-plugin-in-coffeescript/<p>So <a href="http://javascriptplayground.com/blog/2012/04/a-jquery-plugin-with-grunt-qunit">last week</a> I showed you how to write a basic jQuery plugin and today I want to take that plugin & convert it into CoffeeScript.</p>
<p>The first thing to do is open up that project again, and within <code>src</code>, create <code>jquery.pullquote-coffee.coffee</code>. Then head into <code>tests/jquery.pullquote.html</code> and change the line that includes the plugin to reference <code>../src/jquery.pullquote-coffee.js</code>. I wont be using a browser at all to change this plugin over to CoffeeScript. I'll be using our QUnit tests.</p>
<p>For those who have not heard of <a href="http://www.coffeescript/">CoffeeScript</a>, it's a language created by Jeremy Ashkenas that gives us some nice syntax, abstracts common JavaScript problems away & makes it quicker to write JavaScript. The way it works is simple, you write CoffeeScript, compile it into JavaScript, and then include that file like you would any other JS file.</p>
<p>Seeing as CoffeeScript is pretty easy to pick up, I'll cover features as I go. We'll only look at the basics today, with more to come in the future.</p>
<p>The first thing you need to do is decide how you'll compile it. I like to use <a href="http://www.livereload.com/">LiveReload</a>, which is a Mac (and soon to be Windows) app that compiles automatically for you, if I have a lot of different compilations going on (perhaps CoffeeScript, SASS & HAML, for example).</p>
<p>The other option though is to install it through the terminal, done using Node & NPM. If you've not got those install, <a href="http://javascriptplayground.com/blog/2012/04/beginning-node-js-express-tutorial">I wrote about how to install them last week</a> so check that out & then come back here. Install CoffeeScript with:</p>
<p>npm install -g coffee-script</p>
<p><code>-g</code> installs CoffeeScript globally, so it's available from the command line. You can then compile a JS file with:</p>
<p>coffee --compile jquery.pullquote-coffee.coffee</p>
<p>However this gets boring quickly, running this every time you want to compile it. You can use <code>watch</code> to make CoffeeScript compile everytime you save your Coffee file:</p>
<p>coffe --compile --watch jquery.pullquote-coffee.coffee</p>
<p>That's how I'll be doing so today, however, there's one more thing to consider. By default, CoffeeScript wraps all your code within:</p>
<p>(function() {
//your code here
}).call(this);</p>
<p>Usually this is useful, it keeps our code contained & prevents us accidentally poluting the global namespace. In this instance however, we want to wrap our plugin within our own immediately invoked function:</p>
<p>(function($) {</p>
<p>})(jQuery);</p>
<p>We can tell CoffeeScript to not wrap our code in that function by passing the <code>--bare</code> option. So my final command for watching & compiling my coffee file is:</p>
<p>coffee --compile --watch --bare jquery.pullquote-coffee.coffee</p>
<p>So, now we've got the compiling working, lets write the code. Firstly, load up the <code>.coffee</code> file. Before we write code, run the QUnit tests in the terminal with <code>grunt qunit</code>. You should see them all fail. Now it's time to make them all pass by writing our implementation in CoffeeScript. The first thing we need to replicate is the wrapping function:</p>
<p>(function($) {</p>
<p>})(jQuery);</p>
<p>This looks like so in CoffeeScript:</p>
<p>( ($) -></p>
<p>) jQuery</p>
<p>Wow, what just happened there?</p>
<ol>
<li>
<p>CoffeeScript replaces the <code>function</code> keyword with just <code>-></code>.</p>
</li>
<li>
<p>Instead of passing in the variables after the <code>function</code> keyword, in CoffeeScript you pass them in before. For example, something like:</p>
<p>function(foo) {</p>
<p>};</p>
<p>Becomes:</p>
<p>(foo) -></p>
</li>
<li>
<p>There's also no need for braces in CoffeeScript, the language works on indentation. So where you would usually wrap some code in braces, in CoffeeScript you just indent by a tab. This can be a tab, 2 spaces, 4 spaces, whatever your preference. As long as you're consistent, CoffeeScript can deal with it.</p>
<p>You also don't need to wrap function arguments in brackets when you call it. So something like:
someFunc("hey", 2, 5);
Becomes:</p>
<p>someFunc "hey", 2, 5</p>
<p>If you want to add in brackets, you can. Sometimes I do it if a function takes lots of arguments, or if I'm calling a function and passing it in the result of another function. You also need to use brackets when you want to call a function or access a property on the result of a function.</p>
</li>
<li>
<p>You don't need to use semi colons.</p>
</li>
</ol>
<p>Now we've got the wrapping function sorted, it's time to declare our plugin function. This:</p>
<p>$.fn.pullQuote = function(opts) {}</p>
<p>Becomes:</p>
<p>$.fn.pullQuote = (opts) -></p>
<p>And the next line</p>
<p>opts = $.extend({}, $.fn.pullQuote.options, opts);</p>
<p>Stays almost identical, I just choose to drop the brackets:</p>
<p>opts = $.extend {}, $.fn.pullQuote.options, opts</p>
<p>The next large block of code to convert starts with <code>return this.each(function() {</code>. In CoffeeScript, <code>return</code> is added automatically for you, much like Ruby, if you've ever used that. So at the bottom of a function, instead of adding:</p>
<p>return foo;</p>
<p>I can just do:</p>
<p>foo</p>
<p>Some people find this not so clear and if you don't, you're fine to add in the <code>return</code> keyword, it's again up to you. Obviously if you need to return from a function before the end, you still can:</p>
<p>foo = ->
if x
return y</p>
<p>z</p>
<p>That function would return <code>y</code> if <code>x</code> exists, else it will return <code>z</code>. CoffeeScript is pretty clever about knowing when you want a return statement, and when you don't.
So, back to our plugin. We've got:</p>
<p>return this.each(function() {</p>
<p>But in CoffeeScript, we can do:</p>
<p>this.each -></p>
<p>As this is the last block of code in our function, CoffeeScript knows to return it for us. Within the loop we have:
var elem = $(this),
text = elem.text(),
newElem = $("<" + opts.outputElem + "/>", {
"class": opts.outputClass,
text: text
}).insertAfter(opts.insertAfter);</p>
<p>Another easy CoffeeScript rule, <code>var</code> is not needed. If you write:</p>
<p>x = 2</p>
<p>In CoffeeScript, the compiled JS will be:</p>
<p>var x;
x = 2;</p>
<p>Note the declaration will be hoisted to the top of its containing scope. In practise this is rarely an issue, but it's something to note. If you have:</p>
<p>x = 2
someFunc()
y = 5</p>
<p>That will compile to:</p>
<p>var x, y;
x = 2;
someFunc():
y = 5;</p>
<p>So, in our plugin we've got <code>var elem = $(this)</code>, I can replace this with:</p>
<p>elem = $(this)</p>
<p>I could also get rid of the brackets, but when using jQuery I tend to leave them in. For me it makes things clearer and I like to do it with jQuery because often you'll end up chaining things onto <code>$(this)</code>, so adding brackets in first will maybe save time later.</p>
<p>Now, previously we had:</p>
<p>var elem = $(this),
text = elem.text(),</p>
<p>(Note the commas), but because CoffeeScript sorts out <code>var</code> for us, we don't need the commas and can just declare a variable on each new line:
this.each ->
elem = $(this)
text = elem.text()</p>
<p>The next block we have to convert is:</p>
<p>newElem = $("<" + opts.outputElem + "/>", {
"class": opts.outputClass,
text: text
}).insertAfter(opts.insertAfter);</p>
<p>Rather than do this one line at a time, I'll show you the fully converted code & then walk through it:</p>
<p>newElem = $("<#{opts.outputElem}/>",
class: opts.outputClass
text: text
).insertAfter opts.insertAfter</p>
<p>Going line by line:</p>
<ol>
<li>
<p>CoffeeScript has a rather neat way of letting us put variables in the middle of strings. If you've ever written Ruby you'll recognise this, it's very much the same syntax. Any <code>#{}</code> that's within double quotes will be evaluated.
So:</p>
<p>str = "Two plus two is #{2+2}"</p>
<p>Will give:</p>
<p>str = "Two plus two is " + 2+2</p>
</li>
<li>
<p>Next, I pass in an object as the second argument. Except I don't have to use braces here, I can just indent by one tab. Also, I don't have to put quotes around the word "class". CoffeeScript sees that I've used a reserved word, and will automatically add quotes around it for me. How awesome is that? I also don't have to add a comma after the first property in my object, CoffeeScript does that for me too.</p>
</li>
<li>
<p>Finally, I call <code>insertAfter</code> and pass in the correct option. That bit is pretty straight forward, I've just dropped the brackets.</p>
</li>
</ol>
<p>The very last bit to convert is:</p>
<p>$.fn.pullQuote.options = {
outputClass: "pullquote",
outputElem: "blockquote",
insertAfter: "elem"
};</p>
<p>And that's written like so:
$.fn.pullQuote.options =
outputClass: "pullquote"
outputElem: "blockquote"
insertAfter: "elem"</p>
<p>No braces, just indent in, and no commas needed either. Putting that all together, we have:</p>
<p>( ($) -></p>
<p>$.fn.pullQuote = (opts) ->
opts = $.extend {}, $.fn.pullQuote.options, opts</p>
<p>this.each ->
elem = $(this)
text = elem.text()
newElem = $("<#{opts.outputElem}/>",
class: opts.outputClass
text: text
).insertAfter opts.insertAfter</p>
<p>$.fn.pullQuote.options =
outputClass: "pullquote"
outputElem: "blockquote"
insertAfter: "elem"
) jQuery</p>
<p>And now running our QUnit tests will show 10 passes, out of 10. Job well done.</p>
<p>In this rather quick paced tutorial, hopefully this has given you a glimse into why so many people are using CoffeeScript, and some of the advantages it will bring. In the future I'll look more in depth with CoffeeScript, and also show how you can use it when writing Node applications. As always, if you have a question, please do leave a comment.</p>
A Pub Sub implementation in CoffeeScript2012-05-06T00:00:00+00:00http://www.jackfranklin.co.uk/blog/a-pub-sub-implementation-in-coffeescript/<p>A while back I wrote about creating a <a href="http://javascriptplayground.com/blog/2012/04/a-jquery-pub-sub-implementation">Pub/Sub implementation in jQuery</a> and said that I'd revist the subject without relying on jQuery. Today I'm going to do that but once again use <a href="http://www.coffeescript.org/">CoffeeScript</a>. As always I will be Unit testing, this time with Mocha, the <a href="http://javascriptplayground.com/blog/2012/05/a-jquery-plugin-in-coffeescript">same library I covered in the last tutorial</a>. I will not be going over the very basics of using Mocha, so if you haven't used it before, please read that post first. Similarly, I will not be covering basic CoffeeScript, so please refer to that article if you're not familiar with the basics. For those not fans of CoffeeScript, in the future I'll be writing this from scratch with just JavaScript. The reason I use CoffeeScript today is that I've had a lot of requests for it, so I thought I'd merge a tutorial on "Advanced Coffeescript" into this Pub/Sub one.</p>
<p>The Pub/Sub pattern (also known as the Observer pattern) is simple:</p>
<ol>
<li>You can subscribe to an event, and add a function to execute when that event is called.</li>
<li>You can publish events, invoking the functions of all the items subscribed to that event.</li>
</ol>
<p>It's actually a very simple system to create. We'll be using CoffeeScript's class syntax to get this done. First however, I want to set up my testing. Create your <code>test/</code> and <code>src/</code> directories and add <code>pubsubtest.coffee</code> and <code>pubsub.coffee</code> to each of them respectively. Within your test file, add:
chai = require 'chai'
expect = chai.expect
{Pubsub} = require '../src/pubsub'
Remembering you need Mocha & Chai installed. Please see the previous tutorial I linked to above if you need to do this. Last time round I used Chai's <code>should</code> syntax to do tests, which are done more in the BDD style:</p>
<p>someVal.should.equal "foo"</p>
<p>Today however I'm using Chai's <code>expect</code> syntax, which gives me TDD style tests such as:</p>
<p>expect(someVal).to.equal "foo"</p>
<p>Personally I prefer the latter syntax, however use which ever one you prefer.
The last line includes my PubSub class, which we need to create before we do any more coding. Head into the source file and add:</p>
<p>class Pubsub</p>
<p>root = exports ? window
root.Pubsub = Pubsub</p>
<p>That code creates our new class & exports it as <code>root.Pubsub</code>, so we can then get at it in our tests using <code>{Pubsub} = require('../src/pubsub.coffee')</code>.</p>
<p>The way this will work, is that the subscribe method should take three parameters, which are:</p>
<ol>
<li>The id of the item subscribing to the event, such as "module_chat".</li>
<li>The event to subscribe to, such as "new_message".</li>
<li>The function to execute when that event is published.</li>
</ol>
<p>I will store these in an object and then store all items that are subscribed to an event in an array, so my object might look like this:</p>
<p>subs = {
event1: [
{ id: "module1", callback: function() {} },
{ id: "module2", callback: function() {} }
]
}</p>
<p>So the next step is to write tests for these:</p>
<p>describe 'a subscription', ->
myApp = new Pubsub
it 'should add subscriptions to the object', ->
sub1 = myApp.sub "elem1", "myEvent", someFn
expect(myApp.subs["myEvent"]).to.be.ok
expect(myApp.subs["myEvent"].length).to.equal 1
it 'it should add the id to the array for that event if the event already exists', ->
sub2 = myApp.sub "elem2", "myEvent", someFn
expect(myApp.subs["myEvent"].length).to.equal 2</p>
<p>The first spec says that when I add a new subscription, the object in <code>myApp</code>, called <code>subs</code>, should have a property in it called <code>myEvent</code>, and that should exist. The test <code>to.be.ok</code> checks it evaluates to true, which it will do unless it doesn't even exist. I then check the length of <code>subs["myEvent"]</code> to be one, which means there's just one item in the array, which should be correct, as we've only added one subscription for this event.</p>
<p>The second spec says that if we add another subscription for a new event, it should add the item to the array in <code>subs[myEvent]</code>, so the array should have a length of 2. I could write further tests which check the specific data within the array, but for now that will be okay. I'm actually going to follow this up looking at our tests & where we can improve them, but for now we will stick with some basic tests.</p>
<p>You can run these in the console with:</p>
<p>mocha --compilers coffee:coffee-script -R spec</p>
<p>I append <code>-R spec</code> on there to get an "RSpec" style output in the terminal. Right now they all fail. First steps is to set up a constructor to create our <code>subs</code> object. I use <code>@subs</code> here because in CoffeeScript, <code>@</code> is a shortcut for <code>this</code>. So <code>@subs</code> is <code>this.subs</code>:
class Pubsub
constructor: ->
@subs = {}
When I started implementing the <code>sub</code> method, I decided to write a function to check if an event has any subscriptions or not, as it made sense. I denote this as <code>_isSubscribed</code>, with the underscore denoting to me that it's not a method I expect anyone to use outside of the implementation. These are what I usually refer to as utility functions:</p>
<p>_isSubscribed: (evt) ->
@subs[evt]?</p>
<p>All we do is see if the key exists. Using CoffeeScript's existential operator <code>?</code> we can check if a variable is defined & not null. This is a really useful feature which I use a lot.</p>
<p>You may say you could just do <code>@subs[evt]?</code> wherever you need it, but I like to pull that out into a method as I'm sure I will need it lots. Perhaps you would rather not, but I like it, personally. But I don't like having methods - albeit very simple ones - without tests, so in this case I tend to retrospectively write tests to double check my implementation:
describe 'isSubscribed', ->
myApp = new Pubsub
it 'should return false if evt is not in subs', ->
expect(myApp._isSubscribed("event1")).to.equal false
myApp.sub "elem2", "myEvent", someFn
expect(myApp._isSubscribed("event1")).to.equal false
it 'should return true if evt is in subs', ->
sub1 = myApp.sub "elem1", "myEvent", someFn
expect(myApp._isSubscribed("myEvent")).to.equal true</p>
<p>It's pretty simple, I just add some subscriptions, and check that it returns true or false correctly. Of course, this is tough to test without the <code>sub</code> method being implemented, so here goes:
sub: (id, evt, cb) ->
if @_isSubscribed evt
sub = @subs[evt]
sub.push {id: id, callback: cb}
else
@subs[evt] = [{id: id, callback: cb}]</p>
<p>The implementation is pretty simple:</p>
<ol>
<li>If the event already has a subscription, then add a new object to the subscription array for that event.</li>
<li>Else, create a new object & add an array of just one object.</li>
</ol>
<p>If you run those tests now, we should be passing. The next thing I want to do is add a way to unsubscribe. Again, time for tests!
describe 'unsubscribing', ->
myApp = new Pubsub
it 'should not error if removing a non existant subscription', ->
myApp.unSub "elem1", "myEvent"
expect(myApp.subs).to.eql {}
it 'should remove subscription fine', ->
myApp.sub "elem1", "myEvent", someFn
myApp.sub "elem1", "myEvent2", someFn
expect(myApp.subs["myEvent"]).to.be.ok
myApp.unSub "elem1", "myEvent"
expect(myApp.subs["myEvent"]).to.not.be.ok
expect(myApp.subs["myEvent2"]).to.be.ok</p>
<p>The only line I want to highlight:</p>
<p>expect(myApp.subs).to.eql {}</p>
<p>You'll notice I use <code>eql</code> here rather than <code>equal</code>. This is because <code>equal</code> tests strict equality, whilst <code>eql</code> does not. In JavaScript:</p>
<p>{} === {} //false
{} == {} //true</p>
<p>So to check if my object is empty, I want to use <code>==</code>, which is what <code>eql</code> does. My implementation for <code>unSub</code> is:
unSub: (id, evt) ->
return false if not @_isSubscribed evt
newSubs = []
for sub in @subs[evt]
newSubs.push sub if sub.id isnt id
if newSubs.length is 0
delete @subs[evt]
else
@subs[evt] = newSubs</p>
<p>This works like so:</p>
<ol>
<li>If <code>subs[evt]</code> does not exist, we don't need to bother trying to unsubscribe as there cannot be something to unsubscribe from.</li>
<li>Else, we loop through all subscriptions for that event, and add any that are not the one we want to remove to the new array, <code>newSubs</code>. Then, if <code>newSubs</code> contains items, we set <code>@subs[evt]</code> to be the new array, else we remove it.</li>
</ol>
<p>Notice how I'm adding the conditional after the <code>return false</code>. You can do this with all conditionals in CoffeeScript. You see I do it again in the line <code>newSubs.push sub if sub.id isnt id</code>. I find for quick, one line conditionals, postfixing the conditional makes more sense to me. I also use <code>is</code>, which is compiled into <code>===</code>. If you try using <code>===</code> in your CoffeeScript, it wont compile, however if you use <code>==</code>, it will compile into <code>===</code>.</p>
<p>Now we pass the tests for that, lets write the tests for publishing events. I stumbled a bit here, as I wasn't sure how best to check events had been fired. I came up with a system for doing this:</p>
<p>Create my test functions to set a variable to true, and then create a function to check if that variable is true or false. If it's true, reset it to false, ready for the next test, and return true. If it's not true, return false.
fnDidFire = false
hasFired = ->
if fnDidFire
fnDidFire = false
return true
else
return false
someFn = ->
fnDidFire = true</p>
<p>I also want to be able to pass data to callbacks, so I need to write another test variable & function to check I'm passing in the extra information.</p>
<p>extraCallbackInfo = {}
someFnWithInfo = (info) ->
fnDidFire = true
extraCallbackInfo = info</p>
<p>When I want to test passing data, I will use the function which sets <code>extraCallbackInfo</code> and then I'll test on that.</p>
<p>So we can test the result of <code>hasFired()</code>, and if that's true, we can be confident the function fired. Using this, I can write my tests:</p>
<p>describe 'a publish', ->
myApp = new Pubsub
myApp.sub "elem1", "event1", someFn
it 'should fire the callback', ->
myApp.pub "event1"
expect(hasFired()).to.be.ok</p>
<p>it 'should send any extra data through with the callback', ->
myApp.sub "elem2", "event2", someFnWithInfo
myApp.pub "event2", foo: "bar"
expect(hasFired()).to.be.ok
expect(extraCallbackInfo.foo).to.equal "bar"</p>
<p>it 'should not fire for an event that does not exist', ->
myApp.pub "madeUpEvent"
expect(hasFired()).to.not.be.ok</p>
<p>The implementation for this is actually very, very simple:</p>
<p>pub: (evt, info) ->
for key, val of @subs
return false if not val?
if key is evt
for data in val
data.callback(info)</p>
<ol>
<li>If <code>val</code> does not exist, don't do anything.</li>
<li>Else, if <code>key</code> is <code>evt</code>, which means we have a match, loop through every item in the subscription array for that value.</li>
<li>Then, run the callback, passing in the extra data passed.</li>
</ol>
<p>With that, you should see a passing set of specs. It's only a very simple implementation, but there is certainly room for improvements, both in the tests & implementation. If you'd like to check it out, <a href="https://github.com/jackfranklin/CoffeePubSub">it's on Github</a> for you to play around with.</p>
A JS Playground Update2012-05-14T00:00:00+00:00http://www.jackfranklin.co.uk/blog/js-playground-update/<p>JavaScript Playground is now just over one month old, so I thought it would be a good time to write a quick post with some updates about the site.</p>
<p>Firstly, you will have noticed that the last post was a week ago, on the 7th. This can be attributed to the fact that for the next 3 weeks is exam period at University, and I've got 4 exams to take between now & the end of May. This unfortunately takes a lot of my time up which means I haven't been able to write at the usual pace. I hope to publish about once a week for the next few weeks before returning to the more frequent schedule from June onwards. If there's something you'd like to see me cover, I'm always on the look out for ideas.</p>
<p>I also wanted to say thank you to everyone who has tweeted, upvoted, retweeted & so on with links to the blog. In the first month JS Playground served over 50, 000 visits which for me personally is amazing, I never expected that to happen. If you're interested in sponsoring the blog, I'm still looking for someone, so please do get in touch to discuss further.</p>
<p>That's all I wanted to say, just a quick message to explain the slow down in content and also to say thank you to everyone who has helped, and I'm glad that the stuff I'm writing is proving beneficial to so many people.</p>
Your own jQuery Deferreds2012-05-16T00:00:00+00:00http://www.jackfranklin.co.uk/blog/your-own-jquery-deferreds/<p>One of the first and most well received posts on the JavaScript Playground <a href="http://javascriptplayground.com/blog/2012/04/jquery-deferreds-tutorial">introduced jQuery Deferreds</a>, a new feature in jQuery 1.5 to enable us to manage Ajax requests much easier. Today I want to build on that post by showing you how you can construct your own deferreds, enabling you to run callbacks much more efficiently on any piece of code.</p>
<p>Before Deferreds, if you wanted to run some code once you'd done something trivial, such as fading in a <code>div</code>, you'd do:</p>
<p>$("#myDiv").fadeIn(1000, function() {
//callback
});</p>
<p>That's great, but what if later down in your code you want to see if this div has indeed been faded in? One way round it might be:</p>
<p>var divFadedIn = false;
$("#myDiv").fadeIn(1000, function() {
divFadedIn = true;
//callback
});</p>
<p>But that's messy and you end up with a lot of variables you'd much rather avoid and then you get lots of irritating <code>if(divFadedIn)</code> which really irks me.</p>
<p>That's where Deferreds come in. In the past post I showed how they work with Ajax calls, but you can also integrate them into your own functions. Say we have a function fade in a div:</p>
<p>var showDiv = function() {
$("#fadeIn").fadeIn(1000);
});</p>
<p>Integrating Deferreds into this is easy:</p>
<ol>
<li>Create a new <code>$.Deferred()</code> object.</li>
<li>Resolve the deferred when the code has been executed.</li>
<li>Return the <code>promise()</code>.</li>
</ol>
<p>So the above code now looks like:</p>
<p>var showDiv = function() {
var def = $.Deferred();
$("#fadeIn").fadeIn(1000, def.resolve);
return def.promise();
});</p>
<p>We can then check this has executed like so:</p>
<p>$.when(showDiv()).then(function() {
console.log("div faded in");
});</p>
<p>Which is a pattern you'll recognise from the previous post. It's exactly how we checked an Ajax request was done.</p>
<p>We can go further though, by allowing our Deferred function to return data. The only change here is to call the method <code>def.resolve()</code>, and pass it an object:</p>
<p>var showDiv = function() {
var def = $.Deferred();
$("#fadeIn").fadeIn(1000, function() {
def.resolve({
elem: this.id
});
});
return def.promise();
});</p>
<p>We can then get at this data easily:</p>
<p>$.when(showDiv()).then(function(resp) {
console.log("div was faded in with response ", resp);
});</p>
<p>Remember, <code>$.when</code> can accept multiple arguments, so if you had 3-4 functions all along these lines, you could do:</p>
<p>$.when(showDiv(), hideOtherDiv(), foo(), bar()).then();</p>
<p>And if you need to check the state of the div later, you can save the promise to a variable to check:</p>
<p>var divFaded = showDiv();</p>
<p>Although this doesn't get rid of my complaint of having to create a few variables, this does tidy it up a bit; we don't have to manually set values. It's also rare in practice that you'll need to do this, at least I've found that for me.
There's a lot of power here to be used and there's a lot more Deferreds are capable of. In a future post, to be the final part of this 3-part series, I'll look at just what else we can use Deferreds for, and some common errors people make when using them.s</p>
Introduction to JavaScript Objects2012-06-04T00:00:00+00:00http://www.jackfranklin.co.uk/blog/introduction-to-javascript-objects/<p>Today I'd like to talk a little bit about Objects in JavaScript. When I first started using JavaScript (my first experience of it was through jQuery), I was initially confused with this whole idea of passing in objects to functions, in particular to jQuery functions like <code>animate()</code> or <code>css()</code>:</p>
<p>$(foo).css({
"border" : "1px solid black",
"color" : "red"
});</p>
<p>This always confused me, before I had a solid grasp on pure JavaScripts & in particular JavaScript objects. If you're writing lots of JavaScript, objects are going to be something you use frequently so it's important as a beginner you make sure you've got a firm understanding of them.</p>
<p>So, firstly, how do we create an object? We can do it two ways:</p>
<p>var x = new Object();
var y = {};</p>
<p>Both of these mean exactly the same thing & both simply instantiate an empty object. In reality, the vast majority of developers use the second method - it's a lot shorter whilst still being clear as to what it does.</p>
<p>As a side note, this is identical to how we might create new arrays, either through <code>var z = new Array();</code> or through simply <code>var z = []</code>.</p>
<p>Now we have this object, we can define properties (or keys) and values. This can be done in a number of ways. You can create an empty object & then add properties:</p>
<p>var x = {};
x.foo = "bar";
x["baz"] = 123;</p>
<p>You'll notice the two ways of assigning properties. You can either use the dot notation or the square brackets. The differences between the two are easily shown through this code snippet:</p>
<p>//x = some object
var bar = "foo"
x.bar //looks for "bar" property in object "x"
x[bar] //looks for "foo" property in object "x"</p>
<p>The first method will look for the property named whatever you place after the dot, whilst the square brackets will evaluate what's inside. Hence, the square bracket notation is useful when you have the property you want to access stored within a variable, whilst if you know which property you want to get at, you'll tend to use the dot notation.</p>
<p>However, you don't have to create an empty object first, you can create an object & define properties in one swoop:</p>
<p>var x = {
foo: "bar",
baz: 123
}</p>
<p>You do not need to put the properties of an object in quotes when declaring them <strong>except</strong> when using a reserved word in JavaScript. For example, you couldn't do:</p>
<p>var x = {
class: 123
}</p>
<p>If you wish to store a property that is also a reserved word, you need to quote it when declaring it:</p>
<p>var x = {
"class": 123
}</p>
<p>Note that from ECMAScript 5, reserved words <em>can</em> be used as properties without needing quotes, but that is only currently implemented in IE9, FF 3.5+ and Chrome 7+. If you wish to support prior versions of these browsers (and others, like Safari), quote your reserved word properties or, preferably, just don't use them.</p>
<p>When declaring properties like this, note the use of commas. After the value for each <em>but the last</em> property, you need to add a comma. Leaving a comma on the last one, or missing one out, will result in errors. That's why you'll sometimes see people declare objects like this:</p>
<p>var x = {
bar: 123
, foo: 456
, baz: "abc"
}</p>
<p>Whilst I'm not a fan, that method does make it much easier to see if you've missed a comma or put one where you don't need it. I personally prefer the more common approach that I use throughout this post, but if you prefer the other method, that's fine. As usual, it's down to personal preference.</p>
<p>To iterate over an object, we can use <code>for…in</code>:</p>
<p>var x = {
foo: "bar",
baz: 123
}
for (prop in x) {
console.log(prop, "=", x[prop]);
}</p>
<p>Which would output:</p>
<p>foo=bar
baz=123</p>
<p>Of course, properties of an object can contain functions (although functions inside an object are actually methods), too:</p>
<p>var x = {
add: function(a, b) {
return a+b;
}
};</p>
<p>Which is then called as <code>x.add(1,2)</code> as you'd expect. A good thing to know is when a method is invoked, its scope is set to the object. For example:</p>
<p>var x = {
add: function() { console.log(this); },
bar: 123
}
x.add();</p>
<p>Logs:</p>
<p>{ add: [Function], bar: 123 }</p>
<p>And of course, objects can have objects in them:</p>
<p>var x = {
y: {
add: function(a,b) { return a+b; },
self: function() { console.log(this); }
},
bar: "foo"
}</p>
<p>In this instance, <code>x.y.self()</code> would log <code>{ add: [Function], self: [Function] }</code>. Just to illustrate, I could call that method using the square bracket notation:</p>
<p>x["y"]<a href="http://www.jackfranklin.co.uk/blog/introduction-to-javascript-objects/">"self"</a>;</p>
<p>The reason you'll often see APIs of libraries take an object as an input to a function is that it's much easier than having multiple parameters and also allows you to only define those values you want to change. A jQuery plugin might have 5 options, with 5 defaults set. If you wanted to change just one of them but couldn't pass an object into the plugin, you would probably have to pass in every value, even those you don't want to change:</p>
<p>$(foo).plugin("defaultVal", "defaultVal", "changedVal", "defaultVal");</p>
<p>It's also unclear what each of those options are, whereas if you can pass in an object:</p>
<p>$(foo).plugin({
someProp: "changedVal"
});</p>
<p>The advantage is twofold: it's clear what option you're changing, and you don't have to specify the defaults again. All we do here is pass an object directly into a function. You could, if you wanted, create it first:</p>
<p>var opts = {
someProp: "changedVal"
}
$(foo).plugin(opts);</p>
<p>With that it's time to bring this tutorial to a close. There is a lot more to cover, but this is all planned in an article next week titled "Object Oriented Programming in JavaScript", which will pick up where this left off & go much further, to hopefully show some real life usage of objects & how powerful they can be. As always, if you have any questions please do leave a comment & I will get back to you. The next article will be on Wednesday, June 6th where I'll be demonstrating the use of Sockets with Node.js.</p>
Conditional Loading with YepNope2012-06-11T00:00:00+00:00http://www.jackfranklin.co.uk/blog/conditional-loading-yepnope-js-tutorial/<p>In today's tutorial I want to take a look at <a href="http://yepnopejs.com/">yepnope</a>, which is an asynchronous resource loader that works on conditions. That is, you give it a test, and depending on the result of that test, you can load in additional scripts.</p>
<p>This is used a lot when loading a Polyfill for a HTML5 feature, such as placeholders. You can detect if they are supported, and if they are not, bring in a JS script to add support. I used to think that was the only use for yepnope, but having used it on a client project recently I found a slightly different use, which I wanted to demonstrate today.</p>
<p>On the site in question, all scripts are loaded just before the closing <code></body></code>, but because we have a lot of static pages on this site, all the scripts are within an individual file, which is then included through PHP includes. Thus, the issue was every script was getting loaded on every page, even when we didn't need it to be. For example, two of the pages use NivoSlider, but every page was loading it in. I decided to see if Yepnope would be a good fit to solve this issue, and it turned out to work quite well.</p>
<p>The first thing I want to show is that yepnope can be used just to load in scripts, although that's not its main strength:</p>
<p>yepnope({
load: ['https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', '/js/nav.js'],
complete: function (url, res, key) {
//jQuery & nav.js is loaded
}
});</p>
<p>Those two scripts were the ones I needed on every page, so I chose to load them in. A key thing here that had me stuck is yepnope's callbacks. There are two you'll generally use after loading in files, <code>callback</code> and <code>complete</code>. There is a subtle but <em>very</em> important difference between them. When you're loading in multiple files, <code>callback</code> fires after <em>each one individually is loaded</em>, whereas <code>complete</code> fires after <em>all the files are loaded</em>.</p>
<p>From here, I want to test if we need to load in the NivoSlider plugin. All elements on the site with a slider have an ID of <code>slider</code>, so within the <code>complete</code> callback, it's an easy test:</p>
<p>$(function() {
yepnope({
test: $("#slider").length,
yep: '/js/jquery.nivo.slider.pack.js',
callback: function(url, res, key) {
$('#slider').nivoSlider();
}
});
});</p>
<p>I make sure the DOM is ready before running the tests, so we don't get a negative result purely because the DOM isn't ready. To evaluate conditionally you must pass a <code>test</code> property into yepnope. This can be any expression at all that will evaluate to give <code>true</code> or <code>false</code>. This means of course that you can load in a script based on more than one thing: <code>test: a && !b</code>.</p>
<p>The test is if we have any elements with an id of <code>slider</code> on the page. You have to test for <code>.length</code>, as an empty array actually evaluates to <code>true</code> in JavaScript. Obviously <code>length</code> will return 0 or higher, and 0 evaluates to <code>false</code>, which is what we want.</p>
<p>From there it's easy, if the test is true, I can load in my slider script. Note that you don't have to pass both <code>yep</code> and <code>nope</code> - you can do just one or the other if that's all you need.</p>
<p>I then use <code>callback</code> - I don't need to use <code>complete</code> here as it's only 1 script I'm loading, and execute the <code>nivoSlider()</code> on my slider.</p>
<p>That's one use for yepnope and one I've been using quite a lot recently, it really does make conditional script loading much easier to do. In terms of other use cases, it ties in very nicely with Modernizr. You can load in polyfills based on the results of Modernizr tests, which gives you a lot of power.</p>
Exploring Backbone.js - Part 22012-06-15T00:00:00+00:00http://www.jackfranklin.co.uk/blog/exploring-backbone-js-part-2/<p>A while ago I kicked off a planned series of Backbone.js tutorials with <a href="http://javascriptplayground.com/blog/2012/04/backbone-js-tutorial-1">Part 1</a>, which introduced Backbone as we set up a "shopping cart" - albeit an overly simplified one. Although it's been too long coming, today I've got part 2! I ended part 1 with some bullet points as things I wanted to cover:</p>
<ul>
<li>How do I add to a collection after initialising it?</li>
<li>How can I show a filtered set of my objects?</li>
<li>How do I let a user add a new item?</li>
<li>How do I unit test my Backbone applications?</li>
<li>Can I use Backbone.js with CoffeeScript?</li>
</ul>
<p>Whilst I wont be covering them all today, I want to take on the 1st and 3rd bullet point, as they go hand in hand. So today, we'll edit our code to include a very simple form that lets us add a new item. Whilst this isn't so much in keeping with the shopping cart idea, it's the easiest way to demonstrate how to make the changes. In the upcoming parts we will start to model this into the shopping cart application.</p>
<p><em>One thing that has become apparent is that in Backbone there a lot of different ways often to go about the same thing. I'm still learning Backbone too, so if you would have done anything that I do today differently, please let me know in the comments.</em></p>
<p>We need to make some changes to our existing code base. Firstly, in the comments of the prior article it was pointed out to me that setting <code>el</code> to be <code>$("#yourcart")</code> was bad. What I should do is set <code>el</code> to <code>"#yourcart"</code>, and then Backbone gives us <code>$el</code>, which is the same as <code>$(el)</code> which of course is <code>$("#yourcart")</code>.</p>
<p>Now, the way Backbone works in terms of events, is that you bind an event to an element using the form:</p>
<p>events: {
"event selector":"method"
}</p>
<p>This can be any element, however the element has to reside within the View's objects, which is all the elements in whatever you specified as <code>el</code> when declaring the view. <em>This had me stuck for ages!</em>.</p>
<p>There are many ways to get around this, but before I cover my solution, I've added this simple form just after the <code><body></code> tag:</p>
<form id="add">
<label>Title</label>
<input id="title" type="text">
<label>Price</label>
<input id="price" type="text">
<input type="submit" value="save">
</form>
My first solution was to update the `CartCollectionView` to just have `body` as its `el` and then save another for the wrapper around the items, like so:
var CartCollectionView = Backbone.View.extend({
el: "body",
$item_wrap: $("#yourcart"),
<p>However, this seemed not very modular. Each view should deal with just one thing. I either needed another view to deal with the individual item wrapper, or another view to deal with the app as an entity. In essence, both lead you to a similar solution. I chose the first, so <code>CartCollectionView</code> would become the view for the entire app, and I created <code>ItemCollectionView</code> to deal with the HTML for listing all the items.</p>
<p>From here, <code>CartCollectionView</code> became:</p>
<p>var CartCollectionView = Backbone.View.extend({
el: "body",
events: {
"submit #add": "addItem"
},
initialize: function() {
this.itemView = new ItemCollectionView();
},
addItem: function(e) {
e.preventDefault();
this.itemView.addItem();
}
});</p>
<p>As you can see, I set the <code>el</code> to just be <code>body</code>, so it encompasses everything. I then declare the events object. This simply states that when a <code>submit</code> event is triggered on <code>#add</code> (I gave the <code>form</code> that ID), call the <code>addItem</code> method. You can have as many of these as you want, in that format.</p>
<p>The <code>initialize</code> is also simplified, as all it does is create a new <code>ItemCollectionView</code>, which I'll show you shortly.</p>
<p>The main new piece of code is the <code>addItem</code> method, but all this does is use jQuery's <code>preventDefault()</code> to stop the form firing, and then call <code>addItem</code> on the <code>itemView</code>, which is what I stored the <code>new ItemCollectionView()</code> as.</p>
<p>Moving onto the <code>ItemCollectionView</code>, most of it you'll recognise, all I've done is move a lot of the code that was in the <code>CartCollectionView</code> over:</p>
<p>var ItemCollectionView = Backbone.View.extend({
el: '#yourcart',
initialize: function() {
this.collection = cartCollection;
this.render();
},
render: function() {
this.$el.html("");
this.collection.each(function(item) {
this.renderItem(item);
}, this);
},
renderItem: function(item) {
var itemView = new ItemView({model: item});
this.$el.append(itemView.render().el);
},
addItem: function() {
var data = {};
$("#add").children("input[type='text']").each(function(i, el) {
data[el.id] = $(el).val();
});
var newItem = new Item(data);
this.collection.add(newItem);
this.renderItem(newItem);
}
});</p>
<p>The only piece of code here that's new is the <code>addItem</code> method. The first thing it does it loop through all the text fields of the form and store the values to the new <code>data</code> object, using each input's <code>id</code> as the key (I set the <code>id</code> to "title" and "price" on the inputs). This builds us a simple object that we can now generate an Item from using <code>new Item(data)</code>. From there we add that item to the collection and then call <code>renderItem</code>, which creates the HTML for an item & then adds it to the <code>#yourcart</code> wrapper.</p>
<p>And that, as they say, is a wrap! At first I have to confess Backbone's way of doing this confused me, but after I managed to get my head around it it did begin to make sense. As always, you can find the code <a href="https://github.com/jackfranklin/JS-Playground-Backbone/tree/tutorial2">on Github</a>, and if you have any questions, please leave a comment. As I said earlier, if you'd have done this differently, I'd love to know, as there are a few different approaches. I will be amending the article with other solutions if they come up.</p>
Your First Polyfill2012-06-20T00:00:00+00:00http://www.jackfranklin.co.uk/blog/writing-javascript-polyfill/<p>In today's tutorial I want to introduce you to the concepts behind polyfills, a word you see used a lot in today's JS world. I'll demonstrate just what a polyfill is and then write one ourselves.</p>
<p>A polyfill is a piece of code that provides a fallback if a certain feature doesn't exist within that browser's JS engine. Polyfills usually follow a pattern. First, they check to see if the function they implement exists, and then we only write our fallback implementation if we have to.</p>
<p>There are multiple polyfills out there for mutliple functions. The website <a href="http://html5please.com/">HTML5 Please</a> is very useful for finding polyfills to do a particular job.</p>
<p>Now, lets get to our own implementation. I should note as this point that this implementation is by no means going to be a fully fledged, comprehensive one. At the end, I'll link you to the Mozilla Documentation Network (or MDN) page that contains a hugely comprehensive & fully featured polyfill, should you require it.</p>
<p>Today we'll be implementing <code>Array forEach</code>, which was introduced in JavaScript 1.6, ECMAScript 5th edition. In reality, this is actually a very well supported feature, but I've chosen it more for the fact that it's a fairly simple implementation.</p>
<p>The first thing we need to do is see if the method has been natively implemented. We do this by checking to see if <code>Array.prototype.forEach != undefined</code>. If it is indeed undefined, we can continue. What this function does is iterate through all items within an array and call a function on them. This function is passed 3 arguments: the item, the index & the array it's iterating on. It's also possible to pass in to <code>forEach</code> a second value, which will be used as the value for <code>this</code> within the callback.</p>
<p>With that in mind, lets implement it! At this point, I'm presuming the method is not natively supported, and we need to implement it. Our first line simply defines the function:</p>
<p>Array.prototype.forEach = function(callback, thisArg) {</p>
<p>Next, we need to check if <code>callback</code> is a function or not, and throw a <code>TypeError</code> if it's not:</p>
<p>if(typeof(callback) !== "function") {
throw new TypeError(callback + " is not a function!");
}</p>
<p>Once we've got this far, we know that the callback is a valid function, so now all that's left to do is loop through our array. Firstly, I save the length of the array:</p>
<p>var len = this.length;</p>
<p>Then we can loop through:</p>
<p>for(var i = 0; i < len; i++) {
//callback here
}</p>
<p>Remember, we have to pass three things into the callback. So we <em>could</em> do:</p>
<p>callback(this[i], i, this)</p>
<p>But how do we go about applying the value of <code>this</code> within the callback? We can use JavaScript's <code>call()</code> method (<a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call">MDN Link</a>).</p>
<p>The first argument of <code>call</code> is the value of <code>this</code> within the function, and then every argument following it will be passed to the function. So, we have to do:</p>
<p>for(var i = 0; i < len; i++) {
callback.call(thisArg, this[i], i, this)
}</p>
<p>Your next question might be, what if <code>thisArg</code> is undefined? In which case, the value of <code>this</code> will become the global object, which is what it would become anyway if we'd done <code>callback(this[i], i, this)</code>, so that's actually the implementation we want.</p>
<p>And with that, we're done! Here's the entire code:</p>
<p>Array.prototype.forEach = function(callback, thisArg) {
if(typeof(callback) !== "function") {
throw new TypeError(callback + " is not a function!");
}
var len = this.length;
for(var i = 0; i < len; i++) {
callback.call(thisArg, this[i], i, this)
}
}</p>
<p>As a quick test, try:</p>
<p>var arr = [1,2,3];
arr.forEach(function(item, index, th) {
console.log(item, index, th);
});</p>
<p>You should see this output:</p>
<p>1 0 [ 1, 2, 3 ]
2 1 [ 1, 2, 3 ]
3 2 [ 1, 2, 3 ]</p>
<p>We can also test setting the value of <code>this</code> within the callback:</p>
<p>arr.forEach(function(item, index, th) {
console.log(this);
}, {});</p>
<p>Here I set it to just an empty object, <code>{}</code>. In your console, you should see:</p>
<p>{}
{}
{}</p>
<p>Which is just what we're after. Hopefully this has helped clear up any confusion over just what a polyfill is, and the general methodology behind going about writing one. As always, any questions or feedback, please leave a comment or grab me on Twitter. If you're looking for a more complete <code>forEach</code> polyfill, I suggest reading the <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach">MDN Documentation</a>.</p>
Node & Express Todo App: Redis2012-06-24T00:00:00+00:00http://www.jackfranklin.co.uk/blog/node-express-todo-app-redis/<p>Today I'll pick off where <a href="http://javascriptplayground.com/blog/2012/04/node-js-a-todo-app-with-express">Part 1</a> left off, and start working on the to-do part of our application. This tutorial literally starts where Part 1 stops, so if you haven't read Part 1 or need a refresher, I highly recommend reading that before this.</p>
<p><em>Note: this tutorial uses Express 2.5.8. Currently Express V3 is in beta. Once Express 3 stable is released, I will run a post discussing updating to it and link to it here. In the mean time, if you're using Express 3, a few things might be different to this tutorial. None-the-less, there's still a lot here that you can learn from, I hope</em>.</p>
<p>The first thing I'm going to do is create a new view for our Todo screen. This will list our todos and also provide a form for adding new ones. Create the file <code>views/todo.jade</code> and add something like this:</p>
<p>h1 new todo list
form(action="/save", method="post")
p
label Enter a new todo item
input(type='text',placeholder='new todo', name='todo-text')
p
input(type='submit', value='Save')</p>
<p>And then we need to add the route for this, so the user sees this view when they go to <code>/todo</code>.</p>
<p>Head into <code>route/routes.js</code>:</p>
<p>exports.todo = function(req, res){
res.render('todo', {
title: 'New Todo List'
});
};</p>
<p>And finally we just need to link this route up to our URL, which is done at the bottom of <code>app.js</code> (which you may have renamed to <code>server.js</code>, as per the previous tutorial):</p>
<p>app.get('/todo', routes.todo);</p>
<p>If you're not already, run our server with <code>nodemon app.js</code>. If you haven't got nodemon installed, please see the previous tutorial.</p>
<p>Now, if you visit <code>http://localhost:3000/todo</code>, you should see something like this:</p>
<p><img src="https://cl.ly/2D1x3R1O0H3k0U3D0O0t/Screen%20Shot%202012-06-24%20at%2012.49.08.png" alt=""></p>
<p>Lets build in the functionality for listing some todo items. Obviously at the minute we don't have any of them, so I'll add some fake ones in. When you render a view, you can pass in variables, as we did above to set <code>title</code>. Lets pass in an array of objects into the view to represent our items. For now they will be pretty simple:</p>
<p>h1 new todo list
form(action="/save", method="post")
p
label Enter a new todo item
input(type='text',placeholder='new todo', name='todo-text')
p
input(type='submit', value='Save')
ul
each todo in todos
li #{todo.text}</p>
<p>Now we can make use of Jade's built in looping mechanism to loop through our array. It's really beautifully simple:</p>
<p>ul
each todo in todos
li #{todo.text}</p>
<p>All I do here is create a new unordered list, and for each item within the <code>todos</code> array (which I passed in above), just output the text.</p>
<p>And now our view looks like so:</p>
<p><img src="https://cl.ly/1F1l2o3h31320K2J2B3P/Screen%20Shot%202012-06-24%20at%2012.56.26.png" alt=""></p>
<p>It's now time to actually implement the adding of new todos.</p>
<p>The first question is how to store our items? I'm going to use <a href="http://redis.io/">Redis</a>. There's good documentation out there on how to install it, so I wont go through that here. One thing I will mention is if you're on Mac & use Homebrew, by far and away the easiest install is through this, using <code>brew install redis</code>.</p>
<p>Then we need the NPM Package for Redis, which you can install locally with:</p>
<p>npm install redis --save</p>
<p>Remember, doing <code>--save</code> will add it as a dependency to your <code>package.json</code> file.</p>
<p>Now, within the file where we're going to be using Redis, which for us will be exclusively <code>routes/routes.js</code>. You might be thinking it seems a bit messy to put it in here - and you'd be right. In a future tutorial I will show you how I'd tidy this up, but for now I want to concentrate purely on the Redis functionality.</p>
<p>So, within your routes file, add in this code:</p>
<p>var redis = require("redis"),
client = redis.createClient();</p>
<p>You'll also need to make sure a Redis instance is running on your machine. Try typing <code>redis-cli</code> in the command line to see if it's running. On the Mac, to run the server you can type:</p>
<p>redis-server /usr/local/etc/redis.conf</p>
<p>Redis is a key-value datastore that's lightening quick & perfect for our needs here. Redis can be used with lots of datatypes but the most common use is a hash, where we store objects.</p>
<p>Firstly, lets link up our form. Add this line to <code>app.js</code>:</p>
<p>app.post('/save', routes.saveTodo);</p>
<p>And add the function to handle this route (don't panic, I'll explain the code in a second):</p>
<p>exports.saveTodo = function(req, res) {
var newTodo = {};
newTodo.name = req.body['todo-text'];
newTodo.id = newTodo.name.replace(" ", "-");
client.hset("Todo", newTodo.id, newTodo.name);
res.redirect("back");
};</p>
<p>All I do here is create a new object to store our new todo. I can get at the post data through <code>req.body['todo-text']</code> - remember I gave our form field a name of that. Each item that is stored in Redis needs an id attached to it, which has to be unique. A simple way to do this in this instance is to generate the ID based on the name, but replacing spaces with <code>"-"</code>, which is what I do to generate the ID using <code>replace(" ", "-")</code>.</p>
<p>Finally, once I have my new Todo object, I use the <code>hset</code> method (because we're storing a hash, hence the "h"), passing in a key which acts as the name of the datastore, and then I pass in the id & name as new parameters.</p>
<p>Once that's done, I want to pass the user back to the main <code>todo</code> page, so I can redirect the user back to where they came from, which would have been the main todo page.</p>
<p>Once that's done, we need to edit <code>exports.todo</code> to get the todo items from the data store. To get data from Redis, I can use <code>hgetall</code> (again, the "h" denoting hash). This takes two arguments, the key (which for us is "Todo") and a function to process the data. All I do here is loop through & store the new items into an array.</p>
<p>exports.todo = function(req, res){
var todos = [];
client.hgetall("Todo", function(err, objs) {
for(var k in objs) {
var newTodo = {
text: objs[k]
};
todos.push(newTodo);
}
res.render('todo', {
title: 'New Todo List',
todos: todos
});
});
};</p>
<p>The key thing to note here is that the call to <code>res.render</code> is now <strong>inside</strong> the <code>hgetall</code> function. This is down to the asynchronous nature of Redis, you need to call the <code>render</code> only once you know you've got your data. It's much the same as when you're working with data fetched from an Ajax call. Once we do have our <code>todos</code> array, I can pass that into the view.</p>
<p>Now I can go in and add something, and then I'm immediately taken back to the same page, with that item added.</p>
<p>In summary, we've covered a lot today, the main focus being using Redis but we've also explored Jade further & done more with Express.</p>
<p>As always, if you have any questions please leave a comment & the code from this tutorial is <a href="https://github.com/jackfranklin/node-todo">available on Github</a>.</p>
<p>In the coming parts I'd like to look at tidying up this code - perhaps abstracing all the Todo functionality out into an individual file - and then look at testing that file.</p>
Package Management with Jam JS2012-07-01T00:00:00+00:00http://www.jackfranklin.co.uk/blog/package-management-with-jam-js/<p>Today we'll take a look at <a href="http://jamjs.org/">Jam JS</a>, a JavaScript Package Manager. This uses <a href="http://requirejs.org/">RequireJS</a> to load in your required packages and makes using JavaScript libraries much easier.</p>
<p>The first thing to do is install it. This is done through the Node Package Manager, which I'll presume you've got installed. If not, you need to install Node.js & NPM; there are plenty of resources online for helping you do this. To install simply run:</p>
<p>npm install -g jamjs</p>
<p>The <code>-g</code> makes it install globally, which gives you the <code>jam</code> command to run on the command line.</p>
<p>Lets create a new project, which will be a simple website with some jQuery written to change the background colour of the website. For this usually I'd pull in jQuery from Google's CDN, but Jam can download & set this up for us.</p>
<p>Head into your project's directory and run:</p>
<p>jam install jquery</p>
<p>This will download the latest version of jQuery and put it into <code>./jam/jquery/jquery.js</code>. By default all packages are installed to <code>./jam</code>. Now, we could just include that script manually, but Jam comes with RequireJS to manage this for us.</p>
<p>Firstly, here's my <code>index.html</code>:</p>
<pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Jam JS<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>jam/require.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>app.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h2</span><span class="token punctuation">></span></span>Using Jam JS<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h2</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre>
<p>The key here is including <code>jam/require.js</code>, which pulls in the RequireJS source, all configured to work with Jam's directory structure for packages.</p>
<p>The work is done in <code>app.js</code>:</p>
<p>require(['jquery'], function () {
var changeBg = function() {
var body = $("body");</p>
<p>var colours = ["red", "blue", "green", "yellow"];</p>
<p>body.css("background-color", colours[Math.floor(Math.random()*colours.length)]);</p>
<p>setTimeout(changeBg, 2000);</p>
<p>};</p>
<p>$(function() {
setTimeout(changeBg, 2000);
});
});</p>
<p>That code just changes the background colour every 2 seconds, but the important bit is in the top line:</p>
<p>require(['jquery'], function() {});</p>
<p>RequireJS takes in a list of modules to load, and then a callback function to run once they are all loaded.</p>
<p>So far, you might be wandering what the main advantage of Jam is. So far, it's been useful but nothing ground breaking. The main advantage for me is that you can update your scripts automatically. I don't know about you, but a lot of my projects still use old versions of libraries because I never got round to updating them. Well, with Jam it's as simple as:</p>
<p>jam upgrade</p>
<p>This checks all your libraries and will download new versions if required. You can also check for upgrades for an individual package:</p>
<p>jam upgrade jquery</p>
<p>However, sometimes you might want to stay at a specific version. Imagine jQuery 1.9 (not out yet, of course) introduces a change that breaks your application. You can tell Jam to lock jQuery at 1.8.x with:</p>
<p>jam lock jquery@1.8.x</p>
<p>This will allow it to upgrade jQuery all the way through 1.8 but not to 1.9. When the time comes for you to upgrade & fix those issues, you can unlock & upgrade it again:</p>
<p>jam unlock jquery
jam upgrade jquery</p>
<p>To view all your packages, you can do <code>jam ls</code>.</p>
<p>You can see the list of Jam's packages <a href="http://jamjs.org/packages/#/">on the Jam site</a>, and also search. Whilst Jam is relatively new and does not have a huge library, a lot of very popular tools are on Jam, including jQuery, Underscore, CoffeeScript, Backbone, Handlebars and more.</p>
<p>Once you've got all your packages installed and your website done, it's time to put it live. We all know it's bad practise to include all these scripts individually, so Jam provides a mechanism to pool all our scripts into one. This will compile every library and the RequireJS source into one file:</p>
<p>jam compile output.min.js</p>
<p>This will produce <code>output.min.js</code> which can then be included when putting your site into production.</p>
<p>That brings to an end this whirlwind tour of Jam JS. Tools like this are becoming all the more common for JavaScript development & that's a good thing. In the next couple of months I'll be taking a look at a few tools that attempt to improve the JavaScript workflow & make managing libraries and packages easier.</p>
<p>In a tutorial next week, I will show you how to make your own library a Jam package and publishing it for everyone to use.</p>
Watch me Code Screencasts2012-07-10T00:00:00+00:00http://www.jackfranklin.co.uk/blog/watch-me-code-screencasts/<p>I have had a lot of tweets recently asking about how I work, the tools I use, the workflow I've adopted and lots of related questions. I regularly tweet about tools and what I'm up to; some people get annoyed by it but to me one of the best things you can do is to see how other developers do things & integrate bits into a workflow that suits you.</p>
<p>Of course, there's no one definitive workflow for everyone, but I've been asked enough times to show mine that I'm going to do some screencasts titled "Watch me Code". In these I'll code up a simple JavaScript project as I would in real life, and show you just how I go about doing things. This will include things like:</p>
<ul>
<li>how I use Vim</li>
<li>command line JS tools (Grunt, etc)</li>
<li>Using Git</li>
<li>Debugging with the Chrome dev tools</li>
<li>TDD with Jasmine / Mocha / QUnit / others</li>
<li>CoffeeScript development</li>
</ul>
<p>As there's a lot to cover, these will be split over multiple screencasts. What I'm looking for from you lovely readers is two things:</p>
<ul>
<li>What should I code up? If there's a plugin you'd like to see created or a library made, then let me know! I'll do it for free, as long as you're happy that it gets put on Github in all its glory.</li>
<li>What specifically would you like me to talk about?</li>
</ul>
<p>In these screencasts I wont be explaining how every line of code works, I'll explain bits but I'll focus more on the tools I'm using, tricks & tips I've picked up, and so on.</p>
<p>So, the power is in your hands...</p>
A Site Update2012-07-16T00:00:00+00:00http://www.jackfranklin.co.uk/blog/a-site-update/<p>As some of you will have noticed unfortunately posting has slowed in the past few weeks, and I just wanted to write a quick post to explain why. It's largely been down to starting a new job and moving house to a new city, so everything's been a bit hectic. I am pleased to say it's all settled down now, so I hope to resume posting at least twice a week in the very near future. I've also been occupied with some other JS related projects which are very exciting, but unfortunately I can't say anything just yet.</p>
<p>In other news, I;m looking for your feedback as always on what to write. Some people have told me articles are too long so I will be making an effort to do smaller, more targeted posts alongside longer ones. The list of upcoming topics includes:</p>
<ul>
<li>Introduction to Spine.js</li>
<li>Creating your own NPM / Jam packages</li>
<li>Testing with Sinon.js</li>
<li>Watch Me Code Screencasts (working title)</li>
<li>Angular.js</li>
<li>Writing Node.js apps with CoffeeScript</li>
<li>Creating Chrome & Firefox extensions</li>
<li>Frisby.js</li>
</ul>
<p>And lots more. As always I'm always looking for suggestions on what you'd like to see written so please do let me know if you have any suggestions.</p>
Come and watch me speak2012-07-30T00:00:00+00:00http://www.jackfranklin.co.uk/blog/london-titanium-speaking/<p>This coming Tuesday, July 31st, I'm going to be talking at the <a href="http://www.meetup.com/London-Titanium/events/72065822/">London Titanium Meetup</a>. If you're not a Titanium developer please don't be put off, I'm doing a talk on an introduction to Node.js, that is not Titanium based at all. The event is free but spaces are limited so please do sign up on the above URL to register if you plan to attend. The event is free and if you're based in London and fancy an evening of JavaScript please do come along, it would be great to chat.</p>
<p>If you've any questions about the event, please do let me know and I'll either answer or put you in touch with the event organisers, who should be able to help out. It starts at 7PM on Tuesday and is being held close to Oxford Circus in the centre of London.</p>
Introduction to RequireJS2012-07-30T00:00:00+00:00http://www.jackfranklin.co.uk/blog/requirejs-amd-tutorial-introduction/<p>In this tutorial we are going to take a look at <a href="http://www.requirejs.org/">RequireJS</a>, an AMD compatible asynchronous script loader that is incredibly powerful. In my experiments with RequireJS I've hugely enjoyed working with it and will be using it heavily in my future development. This is a fairly heavy post as far as complexity goes, but please do stick with it. I struggled to get my head around RequireJS and AMD for a long time but once it "clicks" it is really awesome.</p>
<p>The basic use case for RequireJS is as a basic script loader, but in this tutorial I wont concentrate on that, but on its uses for modular development. RequireJS implements the AMD (Asynchronous Module Definition) spec, which means we can write our own modules and load them with RequireJS, allowing it to manage dependencies for us. Have you ever had multiple script tags and had to load them in a particular order as one relied on the other? I have, and it's a nightmare. Working in a modular fashion really eliminates this issue and in this tutorial I hope to demonstrate just how.</p>
<p>To do this, we are going to build an app (sort of - it's all very basic snippets of code) that has dependencies. It depends on both Underscore and jQuery. We could just include this as a whole host of <code><script></code> tags, but that's absolutely no fun and is also not efficient, when loading all those in a browser the rest of the page load will be blocked. We could minify them, but then we have to minify them and maintain order of the code, and it just becomes a nightmare. With RequireJS, we include the RequireJS source, and from there can get it to load in files.</p>
<p>Firstly, create your project directory and the structure within. Mine looks like this:</p>
<p>├── app.js
├── index.html
├── lib
│ ├── modules
│ │ └── template.js
│ ├── require.js
│ └── underscore.js</p>
<ul>
<li><code>app.js</code> is my main file, we will look into this shortly.</li>
<li><code>lib/modules</code> is where all my self-written modules will go. With RequireJS all our code gets split into modules. I'll explain further in a moment.</li>
<li>Files immediately within <code>lib</code> are external libraries, in this case the RequireJS source and also Underscore.</li>
</ul>
<p>To get started, head into your <code>index.html</code> file and add in this line:</p>
<p><script src="http://www.jackfranklin.co.uk/blog/requirejs-amd-tutorial-introduction/lib/require.js" data-main="app"></script></p>
<p>That line loads in the RequireJS source, but also tells RequireJS to automatically load in <code>app.js</code>. This is what I will refer to from now on as our "main" JS file, it's where we will put our configuration for RequireJS and load in code. This also sets the base path for loading in files, whenever we load in a file with RequireJS, it will treat the folder <code>app.js</code> is within as the base path and load all files relative to that. Now we've got that done, we can get going.</p>
<p>Before I get ahead of myself, let me show you how we load in dependencies. This is done through the <code>require</code> function. To load in some code to run after a script, you use it like so:</p>
<p>require(['myfile'], function(myFile) {
myFile.init();
});</p>
<p>That would look for <code>myfile.js</code> within the same directory as your main JS file, and whatever <code>myfile</code> returns will be referenced within the callback as <code>myFile</code>, as that's the variable name I passed into the callback. With libraries like jQuery and Underscore that register global objects, you don't need to do this.</p>
<p>What we are going to do is set up jQuery with RequireJS. As of jQuery 1.7, it comes with support for AMD as it implements the AMD spec, so we can use it. You can see this right at the bottom of the un-minified source:</p>
<p>if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
define( "jquery", [], function () { return jQuery; } );
}</p>
<p>The <code>define</code> function is implemented by RequireJS to allow us to define modules. This one defines a named module named "jquery". Usually when defining our own modules we don't explicitly name it (you'll see that later when we write our own) because the name is automatically generated by the file name, and we reference it based on that file name and the directory structure. Because jQuery has declared itself as a named module, we have to reference it as "jquery" when we load it in. This means, to make it work, we'd have to have the jQuery source within our main directory (alongside <code>app.js</code>) and name it <code>jquery.js</code>, so when we reference it within <code>require()</code> as <code>"jquery"</code>, it loads properly (remember that RequireJS doesn't care about .js on the end). However, I prefer to load my jQuery version in from the Google CDN, so I need some way of telling RequireJS that when I try to load "jquery", to fetch it from the CDN. Thankfully this is really easy:</p>
<p>require.config({
paths: {
"jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"
}
});</p>
<p>That line means whenever I do:</p>
<p>require(['jquery'], function() {
//some code
});</p>
<p>It will pull in jQuery from the Google CDN. Note that I've removed ".js" from the end of the URL. We'll also be using Underscore, and to save typing <code>lib/underscore</code> to load it in, I set up a path for that too (I tend to set up paths for most of my libraries I'm depending on. This means my config looks like:</p>
<p>require.config({
paths: {
"jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min",
"underscore": "lib/underscore",
}
});</p>
<p>Now we have our set up sorted, lets write our first AMD module, called <code>template.js</code>. This will provide a method that will compile a basic Underscore template and display it on the page. The functionality is very easy, as the idea here is to look more at the AMD side of things. To define a method, we use the <code>define()</code> function. As we saw, we can explicitly name our module, like jQuery did, or we can let it be done based on the filename, which is fine. We need to pass <code>define()</code> two things, an array of dependencies, and a function that will have our implementation in it. This module is going to depend on Underscore and jQuery:</p>
<p>define(['underscore', 'jquery'], function() {});</p>
<p>What we're going to do is write a function that will add a string to the body that says "Hello Name", but let the name be passed into the function. It's a really easy implementation:</p>
<p>var showName = function(n) {
var temp = _.template("Hello <%= name %>");
$("body").html(temp({name: n}));
};</p>
<p>All we do is create a basic Underscore template and compile it, passing in the <code>name</code> variable. I then use jQuery to add it to the <code>body</code> of the page. Nothing complex at all.</p>
<p>Now, to expose this method we simply need to return it. What we do is return an object containing properties that are the methods to expose. In our case:</p>
<p>return {
showName: showName
};</p>
<p>And with that, our entire module looks like so:</p>
<p>define(['underscore', 'jquery'], function() {
var showName = function(n) {
var temp = _.template("Hello <%= name %>");
$("body").html(temp({name: n}));
};
return {
showName: showName
};
});</p>
<p>The great thing about this is that you can have functions in your modules that are useful for internal use but avoid exposing them, and by dividing your app into multiple modules it's a great way to organise your code.</p>
<p>Finally, all that's left to do is require our module in <code>app.js</code> and then call <code>showName()</code> on it:</p>
<p>require(['lib/modules/template'], function(template) {
template.showName("Jack");
});</p>
<p>Here the module we're loading does not expose itself globally, so to get at whatever it returns, we pass in a variable to the callback function that will be bound to what our module returns. If you're loading multiple modules, add multiple variables. For example:</p>
<p>require(['moduleA', 'moduleB', 'moduleC'], function(a, b, c) {});</p>
<p>Once the module is loaded, I can call <code>showName</code> and sure enough, I get "Hello Jack" in the browser if I refresh my index page.</p>
<p>Although this is a simple example I hope it helps to show the power behind RequireJS and what it can do with its modular approach. I've really enjoyed using it and will no doubt be exploring it further in future tutorials as it does plenty more stuff I haven't covered here.</p>
<p>As always, please do feel free to leave feedback and ask questions, I will endeavour to respond to them.</p>
Speaking at WDC 20122012-08-09T00:00:00+00:00http://www.jackfranklin.co.uk/blog/speaking-at-wdc-2012/<p>I've attended <a href="http://www.webdevconf.com/">WDC</a> for the past two years so when Alex (@alexolder) gave me the chance to speak I couldn't say no. Having been at WDC the past two years I can tell you it's a great day out and the after party is always great fun too. If you're able to make it I'd highly recommend it. Tickets are only £60 or £40 if you're a student. As an extra bonus if you use the discount code "jackfollowers" you'll get a little bit of money off.</p>
<p>As of yet my talk title is not defined but it will be JavaScript based (obviously).</p>
<p>Hope to see you there!</p>
Writing a Command Line Node Tool2012-08-17T00:00:00+00:00http://www.jackfranklin.co.uk/blog/writing-a-command-line-node-tool/<p>Today we are going to combine a few different tools and create a simple Node package that will allow a user to search a directory for files. In this tutorial we will use Grunt to do a lot of the work for us, see how to to make a Node script executable on the command line, and finally see how we publish it to the Node Package Manager (npm) so anyone can install it.</p>
<p>The pre-requisites to this are:</p>
<ul>
<li>You have NodeJS installed (and preferably 0.10.32 up, this is <strong>not</strong> tested on Node < 0.10.32)</li>
<li>Have the Node Package Manager (npm) installed.</li>
<li>Have Grunt-init and and Grunt-cli installed, or if not, run <code>npm install -g grunt-init</code> and <code>npm install -g grunt-cli</code> (or sudo npm install -g grunt-cli ). Some basic familiarity is good too, <a href="http://javascriptplayground.com/blog/2012/04/grunt-js-command-line-tutorial">I've written an introduction to it</a> previously. If you've never used it, go read that and then return.</li>
</ul>
<p>So the first thing to do is create a new project. Create a directory for it and change to the directory you created.</p>
<ul>
<li>
<p>Install the current version of Grunt local to your project</p>
<p>npm install grunt --save</p>
</li>
</ul>
<p>This will mark grunt your project's package.json devDependencies section.</p>
<ul>
<li>
<p>Add the node grunt-init template</p>
<p>git clone https://github.com/gruntjs/grunt-init-node.git ~/.grunt-init/node</p>
</li>
</ul>
<p>(The current version on grunt-init doesn't come with any base templates. Additional information is avaliable at <a href="http://gruntjs.com/project-scaffolding">Project Scaffolding</a></p>
<ul>
<li>
<p>Use grunt-init to create a new node project</p>
<p>grunt-init node</p>
</li>
</ul>
<p>This will take us through set up to set up our new project. It will ask you some questions. Feel free to deviate, but here's how I answered them:</p>
<p>[?] Project name (playground-nodecmd) filesearch
[?] Description (The best project ever.) Awesome file search.
[?] Version (0.1.0)
[?] Project git repository (git://github.com/JackFranklin/filesearch.git)
[?] Project homepage (https://github.com/JackFranklin/filesearch)
[?] Project issues tracker (https://github.com/JackFranklin/filesearch/issues)
[?] Licenses (MIT)
[?] Author name (Jack Franklin)
[?] Author email (jack@jackfranklin.net)
[?] Author url (none)
[?] What versions of node does it run on? (>= 0.8.0) 0.10.32
[?] Main module/entry point (lib/filesearch)
[?] Npm test command (grunt nodeunit)
[?] Will this project be tested with Travis CI? (Y/n) n
[?] Do you need to make any changes to the above before continuing? (y/N) n</p>
<p>You will see Grunt has got us started:</p>
<pre><code>Writing .gitignore...OK
Writing .jshintrc...OK
Writing Gruntfile.js...OK
Writing README.md...OK
Writing lib/filesearch.js...OK
Writing test/filesearch_test.js...OK
Writing LICENSE-MIT...OK
Writing package.json...OK
Initialized from template "node".
You should now install project dependencies with npm install. After that, you
may execute project tasks with grunt. For more information about installing
and configuring Grunt, please see the Getting Started guide:
http://gruntjs.com/getting-started
Done, without errors.
</code></pre>
<p>We wont actually be writing tests for this package as it's very simple. To search for files in a directory, we're just going to execute the shell command:</p>
<p>ls -a | grep somefile</p>
<p>In the future I will write on creating more complex modules and testing them, but for this we'll focus on implementation.</p>
<p>Load up <code>package.json</code> in your editor. It should look like this:</p>
<p>{
"name": "filesearch",
"description": "Awesome file search.",
"version": "0.1.0",
"homepage": "https://github.com/JackFranklin/filesearch",
"author": {
"name": "Jack Franklin",
"email": "jack@jackfranklin.net"
},
"repository": {
"type": "git",
"url": "git://github.com/JackFranklin/filesearch.git"
},
"bugs": {
"url": "https://github.com/JackFranklin/filesearch/issues"
},
"licenses": [
{
"type": "MIT",
"url": "https://github.com/JackFranklin/filesearch/blob/master/LICENSE-MIT"
}
],
"main": "lib/filesearch",
"engines": {
"node": "0.10.32"
},
"scripts": {
"test": "grunt nodeunit"
},
"devDependencies": {
"grunt-contrib-jshint": "~0.6.4",
"grunt-contrib-nodeunit": "~0.2.0",
"grunt-contrib-watch": "~0.5.3",
"grunt": "~0.4.5"
},
"keywords": []
}</p>
<p>We need to add some properties to that. After the last property, as shown below:</p>
<p>"Keywords": []
<code> //Add here this here ,"preferGlobal": "true", "bin": { "filesearch" : "lib/filesearch.js" } </code>
}</p>
<p>The first line denotes that our package should be installed globally if possible. If the user installs it locally, they will see a message about how it should be done globally. The second object, <code>bin</code>, denotes files that should be executable on the command line, and how we should reference them. Here we are saying that when we hit <code>filesearch</code> in the command line, it should run <code>lib/filesearch.js</code>.</p>
<p>To make this happen, load up <code>lib/filesearch.js</code> in your editor, and add this line at the very top:</p>
<p>#! /usr/bin/env node</p>
<p>This says how the script should be executed, in this case through Node.</p>
<p>Add an additional line to the end of <code>lib/filesearch.js</code>:</p>
<p>console.log("Success");</p>
<p>Once that is done, we can run <code>npm link</code> to install our package locally so we can test it. Run <code>npm link</code> and then you should have access to the <code>filesearch</code> command. Of course, right now it only logs success to the console. To confirm it is working run <code>filesearch Grunt</code> and look for the output <code>success</code>.</p>
<p>Now, delete the rest of the code from <code>lib/filesearch</code>, which is:</p>
<p>'use strict';</p>
<p>exports.awesome = function() {
return 'awesome';
};</p>
<p>console.log("Success");</p>
<p><code>exports</code> is a way of exporting methods and variables from your script, that can be used in others. Say if this script was one other developers could use, <code>exports</code> is the object that will be returned when a developer includes our module through <code>var x = require("ourpackage");</code>. Because ours is a command line tool that's little use, so there's no need to include it. Now, lets implement this. I am envisaging that the use of this module is like so:</p>
<p>filesearch filename</p>
<p>So the parameter passed in is what we need to search for. All the arguments are stored in the array <code>process.argv</code>. To inspect them, add this line:</p>
<p>console.log(process.argv);</p>
<p>And then run <code>filesearch grunt</code> and check the result:
filesearch grunt
[ 'node', '/usr/local/bin/filesearch', 'grunt' ]
You can see that the first two arguments refer to how the script is executed and where the executable is. Hence, the actual arguments passed in start at the second index. Therefore we can get at the user supplied arguments by slicing the array at index 2:</p>
<p>var userArgs = process.argv.slice(2);</p>
<p>And then get our argument as the first argument of <code>userArgs</code>:</p>
<p>var searchParam = userArgs[0];</p>
<p>Rather than do the implementation step by step, as it's only six lines, I'll show you and then explain:</p>
<p>var userArgs = process.argv.slice(2);
var searchParam = userArgs[0];</p>
<p>var exec = require('child_process').exec;
var child = exec('ls -a | grep ' + searchParam, function(err, stdout, stderr) {
if (err) throw err;
console.log(stdout);
});</p>
<p>The first two lines get the search parameter, as I explained above.</p>
<p>Next up we use Node's <a href="http://nodejs.org/api/child_process.html">Child Process</a> library, more specifically the <a href="http://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback">exec module</a>, which runs a shell command and buffers the output. The command we need to run is:</p>
<p>ls -a | grep {searchParam}</p>
<p>For those unfamiliar with the shell, <code>ls -a</code> means list all files, and <code>grep something</code> searches for the term "something". By piping the result of <code>ls -a</code> through to <code>grep something</code>, it searches everything <code>ls -a</code> returned for <code>something</code>.</p>
<p>So once we have the <code>exec</code> variable, we can execute it. It takes two parameters, the string to execute and a callback. Exec is asynchronous, like most of Node in general, so any code to run after we have the result must go in the callback. Within the callback, all we do is throw an error if it exists, and if it doesn't just log the output.</p>
<p>The pattern of callback functions taking the error as the first parameter is very common within Node. You will often see:</p>
<p>function(err, stdout, stderr) {
if(err) throw err;
//rest of code
}</p>
<p>As a pattern. Now we've done that, running <code>filesearch Grunt</code> within our project directory should get you what we want:</p>
<p>filesearch Grunt
Gruntfile.js</p>
<p>Of course, this module in practice is useless, but hopefully it has demonstrated how to go about making simple command line tools in Node. If you'd like a more complex example, my <a href="https://github.com/jackfranklin/nodefetch">Nodefetch</a> tool might make interesting reading.</p>
<p>To publish this as an npm module, you need to do three things. Firstly, authenticate yourself with npm, or signup with npm. To do this, run <code>npm adduser</code>.</p>
<p>Secondly, you should make sure your project is a Git repository, and:</p>
<ul>
<li>
<p>Add <code>node_modules/</code> to your <code>.gitignore</code> file, to make sure only your module code is pushed, and not the modules you use. These are dealt with when the user installs your module.</p>
</li>
<li>
<p>Make sure your repository has a valid <code>package.json</code> (running <code>npm link</code> will verify this, if it works without error, you're fine).</p>
</li>
<li>
<p>Push your repository to Github (or elsewhere) and make sure in your <code>package.json</code>, the <code>repository</code> object looks like so:</p>
<p>"repository": {
"type": "git",
"url": "git://github.com/JackFranklin/filesearch.git"
}</p>
</li>
</ul>
<p>Then it's easy, just run <code>npm publish</code>, and you're done. It really is as easy as that. Users can then install your module through <code>npm install modulename</code>.</p>
<p>I hope this tutorial has been useful, and if you have any questions please leave a comment, or feel free to tweet or email me.</p>
nodefetch, a command line download tool2012-08-20T00:00:00+00:00http://www.jackfranklin.co.uk/blog/nodefetch-a-command-line-download-tool/<p>As part of me wanting to spend some time playing with command line Node.js tools, last week I sat down and wrote <a href="https://github.com/jackfranklin/nodefetch">nodefetch</a>. Whilst I don't usually blog about my projects on here, I thought this one might be of use to a few people, so thought I'd quickly write up about it. If you enjoyed last week's tutorial on <a href="http://javascriptplayground.com/blog/2012/08/writing-a-command-line-node-tool">creating a command line Node tool</a>, this is a great chance for you to dive into the source of a little more complex tool.</p>
<p>Once installed through NPM with <code>npm install nodefetch -g</code>, you are able to download the latest copy of jQuery into your present working directory as easily as:</p>
<p>nodefetch jquery</p>
<p>You could also download multiple files:</p>
<p>nodefetch jquery backbone underscore</p>
<p>Isn't that awesome? I think so and a few folks I shared it with liked it too.</p>
<p>It works by keeping a <code>.nodefetch.json</code> file in your home directory that links package names to their downloads. When you first run nodefetch it will download the default file from my own server, but you are then free to edit it to add your own packages to suit you.</p>
<p>There's more detailed instructions on Github involving how nodefetch is tested (I even wrote another npm package to help me test it) and how to contribute if you'd like to help out. I've got plenty more planned for nodefetch and if you do find it useful I'd love for you to let me know. Similarly, if you look through the source and see anything you don't understand, feel free to ask.</p>
Essential JavaScript Script Loaders2012-09-03T00:00:00+00:00http://www.jackfranklin.co.uk/blog/essential-javascript-script-loaders/<p>For those who don't follow me on Twitter or perhaps missed it, one of the reasons I've not been blogging on JSPlayground as much recently is down to writing for other sites too.</p>
<p>Last week .net magazine published my article on the <a href="http://www.netmagazine.com/features/essential-javascript-top-five-script-loaders">Top 5 JavaScript Script Loaders</a>. It covers Yepnope, Require and some others too so if you've been looking at script loaders or wanted to for a while, hopefully this article might be of use to you.</p>
<p>Another reason I've not been blogging as much is because I've signed a book deal with <a href="http://www.apress.com/">Apress</a> to write a new book titled "Beginning jQuery". This will hopefully take a developer from jQuery novice to someone who's comfortable entirely with the library and its more complex applications. At this stage three chapters have been written, although there's plenty more to be written. The book is going to be out in early 2013 and there will be a couple of copies on the JSPlayground to be won.</p>
<p>Finally don't forget that I'm speaking at <a href="http://2012.webdevconf.com/">WebDevConf</a> on October 19th. I'm going to be talking all about writing better jQuery, with a specific focus to not tying yourself so tightly to any DOM structure. Tickets are just £60 (£40 for students) and the discount code "jackfollowers" will get you an additional 10% off. It would be great to meet some new faces so please do come along.</p>
Cross Browser Testing with bunyip2012-09-17T00:00:00+00:00http://www.jackfranklin.co.uk/blog/cross-browser-testing-with-bunyip/<p>Today we're going to take a look at <a href="https://github.com/ryanseddon/bunyip">bunyip</a>, a tool from <a href="http://twitter.com/ryanseddon">Ryan Seddon</a> to make running your test specs in multiple browsers really easy.</p>
<p>Out of the box, bunyip only supports the YUI Test framework (this is due to the fact that Yeti, the tool bunyip uses, only supports YUI) but Ryan has written adapters for QUnit, Mocha and Jasmine. In this tutorial I'll take some Jasmine specs and run them through bunyip, using Ryan's Jasmine adapter. The specs are going to be from my <a href="https://efendibooks.com/minibooks/testing-with-coffeescript">Testing With CoffeeScript</a> ebook, which is free and if you haven't checked it out yet, I'd love it if you could give it a read and let me know your thoughts.</p>
<p>bunyip is easily installed through npm, as a global module:</p>
<p>npm install -g bunyip</p>
<p>To run bunyip locally, simply run:</p>
<p>bunyip -f yourspecs.html local</p>
<p>The file you point bunyip to should be your spec runner, so for Jasmine users it's the SpecRunner.html file. The <code>local</code> option tells bunyip to run local browsers. It's pretty smart about how it does this, and will look for the following browsers:</p>
<ul>
<li>Firefox and FF Nightly</li>
<li>Chrome and Canary</li>
<li>Opera and Opera Next</li>
<li>Safari</li>
<li>PhantomJS</li>
</ul>
<p>Before we run bunyip, lets use Ryan's Jasmine adapter for Yeti, which is what bunyip uses to run the tests.</p>
<p>In the top of the spec runner file, just below the line that sources Jasmine, add in a line below to include the Jasmine adapter, which you can <a href="https://github.com/ryanseddon/yeti-adaptors/blob/master/jasmine/jasmine-yeti-adaptor.js">find here</a>. I'd recommend downloading it and putting it into the same folder as the Jasmine source.</p>
<p><script type="text/javascript" src="http://www.jackfranklin.co.uk/blog/cross-browser-testing-with-bunyip/lib/jasmine-1.1.0/jasmine.js"></script>
<script type="text/javascript" src="http://www.jackfranklin.co.uk/blog/cross-browser-testing-with-bunyip/lib/jasmine-1.1.0/jasmine-yeti-adaptor.js"></script></p>
<p>If you take a look at your SpecRunner.html, you'll see this section of JavaScript that runs the tests:
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function(spec) {
return htmlReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
All you need to do is slot in this check that sorts bunyip out:
if (window.$yetify !== undefined) {
BUNYIP.hookup(jasmineEnv);
}
I decided to add this into the <code>execJasmine()</code> function:</p>
<p>function execJasmine() {
if (window.$yetify !== undefined) {
BUNYIP.hookup(jasmineEnv);
}
jasmineEnv.execute();
}</p>
<p>Now we've got that sorted, head into the folder where your SpecRunner.html resides and run:</p>
<p>bunyip -f SpecRunner.html local</p>
<p>You should get an output similar to this:
Creating a Hub at http://localhost:9000
Waiting for agents to connect at http://localhost:9000.
When ready, press Enter to begin testing.
Agent connected: Chrome (21.0.1180.89) / Mac OS
Agent connected: Firefox (14.0.1) / Mac OS
Agent connected: Safari (5.1.7) / Mac OS
Agent connected: Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.6.1 Safari/534.34</p>
<p>bunyip finds the browsers you have installed (for me, it's Chrome, Safari and Firefox), along with PhantomJS. Once all the browsers you want have loaded, you need to press enter to run the tests. When you're happy, hit enter.
Testing started on Chrome (21.0.1180.89) / Mac OS, Firefox (14.0.1) / Mac OS, Safari (5.1.7) / Mac OS, Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.6.1 Safari/534.34
Testing... \ 0% complete (0/4) 52.15 tests/sec
Agent completed: Firefox (14.0.1) / Mac OS
Agent completed: Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.6.1 Safari/534.34
Testing... / 50% complete (2/4) 35.58 tests/sec
Agent completed: Chrome (21.0.1180.89) / Mac OS
Agent completed: Safari (5.1.7) / Mac OS
Testing... | 100% complete (4/4) 20.47 tests/sec 92 tests passed! (1417ms)
You'll see each browser briefly flash your specs page and then close again as all tests run, and pass in my case. If you want to run specific browsers, you can:</p>
<p>bunyip -f SpecRunner.html local -l "firefox|phantomjs"</p>
<p>Which does indeed just run those browsers:
Agent connected: Firefox (14.0.1) / Mac OS
Agent connected: Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit/534.34 (KHTML, like Gecko) PhantomJS/1.6.1 Safari/534.34
This makes bunyip a great tool for quickly testing your specs cross-browser. I should also note that if you have a paid BrowserStack account, you can easily connect bunyip up to that which enables you to run your specs on all the devices Browser Stack supports, including IE and iOS devices. To find out more on that, I suggest checking out the <a href="https://github.com/ryanseddon/bunyip">bunyip repository</a>.</p>
Hosting a Node app on Heroku2012-10-07T00:00:00+00:00http://www.jackfranklin.co.uk/blog/hosting-a-node-app-on-heroku/<p><em>Note: I apologise for the lack of updates on JS Playground recently, but happy to announce the site is now returning to at least one post per week. Any requests for content, please get in touch.</em></p>
<p>Today I want to look at using the popular <a href="http://www.heroku.com/">Heroku</a> to host a simple Node app. I got asked recently if I had any suggestions on hosting a small Node app, and Heroku's free plan is usually more than enough for little side projects, or to show off something you're working on. It can be a bit daunting if you've never used it before, so I thought a step by step guide would be of use. This tutorial does require knowledge of Git and also you should be comfortable with the command line - if you're not then Heroku probably isn't for you.</p>
<p>Heroku is heavily used to run Ruby / Rails apps but recently added Node.js support and it's a really great way to quickly and easily get something running online.</p>
<p>If you haven't already, you'll need to <a href="https://api.heroku.com/signup/devcenter">sign up to Heroku</a>, which is completely free. You'll then need to install the <a href="https://toolbelt.heroku.com/">Heroku Toolbelt</a>, which will give you access to the <code>heroku</code> command line interface.</p>
<p>For the app, I'm going to use the small Express server example I introduced in my <a href="http://javascriptplayground.com/blog/2012/04/beginning-node-js-express-tutorial">Beginning Node</a> tutorial. This contains <code>helloworld.js</code>, which has the following:</p>
<p>var app = require('express').createServer();
app.get('/', function(req, res) {
res.send("Hello World");
});</p>
<p>app.listen(3000, function() {
console.log("listening on 3000");
});</p>
<p>We need to make one change to this though. Heroku will need us to run on a specific port, which we access through the <code>process</code> object, which is available to use. Make your app listen on the port number specified in <code>process.env.PORT</code>, or if it can't find one, revert to 3000. This way it will work both locally and on Heroku.</p>
<p>app.listen(process.env.PORT || 3000, function() {
console.log("listening on 3000");
});</p>
<p>And also <code>package.json</code>, which lists the dependencies we have. Heroku also recommend you list your engines in <code>package.json</code>, so add them in so your file looks like so:</p>
<p>{
"name": "jsphelloworld",
"version": "0.0.1",
"dependencies": {
"express": "~2.5.9"
},
"engines": {
"node": "0.8.x",
"npm": "1.1.x"
}
}</p>
<p><em>This is using an outdated version of Express but for this tutorial it's irrelevant - there's tutorials planned around Express V3 in the near future.</em></p>
<p>It's important to note that you have to be using NPM to manage your dependencies to host with Heroku. You also need to be using Git as your VCS too, as to update files on Heroku you do a <code>git push</code>. Run <code>npm install</code> to make sure your <code>package.json</code> file is valid, and that you've got all your dependencies sorted.</p>
<p>Next we need to tell the Heroku server how it should run our app. This is done through what Heroku call a <a href="https://devcenter.heroku.com/articles/procfile">Procfile</a>. It's a simple text file created in the project root and for this example, we simply need to tell it how to run our app, which is done like so:</p>
<p>web: node helloworld.js</p>
<p>That's <strong>all</strong> your Procfile should contain. Youc an test this by running it through Foreman, a way of running apps that uses a Procile to do it. Run <code>foreman start</code> (it's installed as part of the Heroku toolbelt) and you should see output somewhat like this:
-> foreman start
12:37:50 web.1 | started with pid 1890
12:37:51 web.1 | Listening on 3000
If you get that, everything's working fine. You can go to <code>localhost:3000</code> to check if you want to make sure.</p>
<p>Now it's time to get these files into Git. Initialise your Git repository if your code is not in Git already, and commit all the changes we've made. Now we're ready to run it on Heroku.</p>
<p>On the command line, run <code>heroku login</code>. This will authenticate you and set up any neccessary public keys required to allow you to push to Heroku. Now run <code>heroku create</code> to get Heroku to set up a site for you:
-> heroku create
Creating fathomless-cove-9338... done, stack is cedar
http://fathomless-cove-9338.herokuapp.com/ | git@heroku.com:fathomless-cove-9338.git
Git remote heroku added
Now it's time to deploy your app. Heroku sets up a git remote for you, so to deploy simply run:</p>
<p>git push heroku master</p>
<p>This will take a few moments, especially the first time. Your output should look something like:</p>
<p>-> git push heroku master
Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 629 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)</p>
<p>-----> Heroku receiving push
-----> Node.js app detected
-----> Resolving engine versions
Using Node.js version: 0.8.11
Using npm version: 1.1.49
-----> Fetching Node.js binaries
-----> Vendoring node into slug
-----> Installing dependencies with npm
[snip - NPM logging here is pretty verbose]
Dependencies installed
-----> Building runtime environment
-----> Discovering process types
Procfile declares types -> web
-----> Compiled slug size: 4.0MB
-----> Launching... done, v3
http://fathomless-cove-9338.herokuapp.com deployed to Heroku</p>
<p>Nearly there! You now need to tell Heroku to run 1 web process, which is done like so:</p>
<p>heroku ps:scale web=1</p>
<p>And finally, check out your app:</p>
<p>heroku open</p>
<p>This will open your site in the browser and if yours is like <a href="http://fathomless-cove-9338.herokuapp.com/">mine</a>, you should get the text "Hello World" right back at you.</p>
<p>Heroku can be a little daunting at first but hopefully this guide has shown that it's pretty straight forward once you get used to the way it works.</p>
Five JavaScript Testing Libraries2012-10-11T00:00:00+00:00http://www.jackfranklin.co.uk/blog/five-javascript-testing-libraries/<p><em>Jack Franklin explores five popular JavaScript testing libraries and provides examples of how to use them so you'll be able to choose the best one for the task in hand when your next JS project comes round.</em></p>
<p>The second article I've written on the .net website - this time looking at libraries that exist for testing your JavaScript. <a href="http://www.netmagazine.com/features/essential-javascript-top-five-testing-libraries">Go on, give it a read</a>.</p>
Making your library AMD compliant2012-10-15T00:00:00+00:00http://www.jackfranklin.co.uk/blog/making-your-library-amd-compliant/<p>Previously on this blog I've written about an AMD approach with <a href="http://javascriptplayground.com/blog/2012/07/requirejs-amd-tutorial-introduction">Require.js</a> and about package management with <a href="http://javascriptplayground.com/blog/2012/07/package-management-with-jam-js">Jam JS</a>. Jam uses Require.js so what I thought would be a nice way to tie these two posts together would be to write on how to make your JS library AMD compliant and how to publish it with Jam, for use in other projects.</p>
<p>The project I'm using is actually written in CoffeeScript, but it's so similar to JavaScript in this instance that it shouldn't be an issue. I've also included the same code in JavaScript, if CoffeeScript isn't your thing.</p>
<p>I discussed how to define a module in the previous RequireJS tutorial linked above, so if you're not sure how to do things, please read that and then return here. The way to define something is simple - check if <code>window.define</code> exists, and if it does, use it to define our module. To define a module we need to pass it a function that simply returns what we want a user of our library to access. Sometimes that's just one method, or it might be an object of multiple methods.</p>
<p>In my case, using my little <a href="https://github.com/jackfranklin/responsiveImages">Responsive Images</a> script, I just needed to expose the function <code>responsiveImage</code>, which I had already attached onto the window object at this stage. In CoffeeScript, it's written like so:</p>
<p>#expose globally
window.responsiveImage = responsiveImages</p>
<p># support AMD
if typeof window.define is "function" && window.define.amd
window.define "responsiveImages", [], -> window.responsiveImage</p>
<p>If I were to write that in JavaScript, it would be:</p>
<p>window.responsiveImage = responsiveImages;</p>
<p>if (typeof window.define === "function" && window.define.amd) {
window.define("responsiveImages", [], function() {
return window.responsiveImage;
});
}</p>
<p>Note that I use <code>window.define</code> rather than <code>define</code> because all my code is wrapped within an anonymous function, so I don't have access to the global scope through <code>this</code>.</p>
<p>The next thing to do is to create a <code>package.json</code> file so Jam knows about our package and how to run it. For my project, it looks like this:</p>
<p>{
"name": "responsiveImages",
"version": "0.0.2",
"description": "A quick script to provide a way of changing which image to use based on window dimensions.",
"main": "responsiveimages.js",
"repositories": [
{
"type": "git",
"url": "https://github.com/jackfranklin/responsiveImages.git"
}
],
"github": "https://github.com/jackfranklin/responsiveImages"
}</p>
<p>The only line there that isn't immediately obvious is the one declaring <code>main</code>. By default Jam will look for a file <code>main.js</code>, but if yours isn't called that you can tell it so in the JSON file. There's a lot more options you can set - <a href="http://jamjs.org/docs#Package_json">they are documented well on the Jam site</a>.</p>
<p>Now it's time to publish. Head to the <a href="http://jamjs.org/">Jam site</a> and sign up. Then head into your library's directory and run:</p>
<p>jam publish</p>
<p>If all goes well, you will see output similar to:</p>
<p>-> jam publish
Please provide credentials for: http://jamjs.org/repository
Username: jackfranklin
Password:
creating /Users/JackFranklin/.jam/cache/responsiveImages/0.0.2/responsiveImages-0.0.2.tar.gz
extracting /Users/JackFranklin/.jam/cache/responsiveImages/0.0.2/responsiveImages-0.0.2.tar.gz
OK</p>
<p>Now lets check this. Head into a project where you want to use the library (preferably this should be one which already uses Jam for package management) and run:</p>
<p>jam install responsiveImages</p>
<p>Changing the package name to yours. You'll see output that should include something like</p>
<p>installing responsiveImages@0.0.1</p>
<p>Once that's done, try it out. Head into your main JS file and change the <code>require</code> call to include your new package. Remember that the package return is passed into the function as a variable, so add that in too:</p>
<p>require(['jquery', 'responsiveImages'], function ($, RI) {});</p>
<p>And now you should be able to use your library! As a test, I ran a simple <code>console.log(RI)</code> and made sure it logged the function I return. If you want to upgrade your package, it's generally a 3 step process:</p>
<ol>
<li>Make your changes and commit them.</li>
<li>Boost the version number in your <code>package.json</code></li>
<li>Run <code>jam publish</code> again.</li>
</ol>
<p>If you're working on a lot of projects that use a lot of similar code, I highly recommend extracting them out into small AMD modules that can then be managed with a tool like Jam. I've been doing it recently and it really has made things a lot nicer when it comes to JS library versioning, upgrading and so on.</p>
A New JS Playground Update2012-11-25T00:00:00+00:00http://www.jackfranklin.co.uk/blog/a-new-js-playground-update/<p>Today I spent a bit of time updating the site, and as such it seemed like a good time to write a small blog post with some updates.</p>
<p><strong>Disqus</strong></p>
<p>I have now moved site comments over to Disqus. This does lose all previous comments (they are still in the DB, just not visible) which is a shame, but I was finding it hard to keep up with the old system. Disqus also offers a much nicer interface and tools to enable much better discussions to take place within the comments, so I think this will really help me keep up to date with comments and reply in a much more organised and clearer fashion.</p>
<p><strong>The Book</strong></p>
<p>I am still hard at work with my book! There are now just two chapters left, and the end is in sight. Once the book is done I hope to be able to return to my previous writing frequency on this site. You can also <a href="http://www.amazon.co.uk/Beginning-jQuery-Jack-Franklin/dp/1430249323/ref=sr_1_1?ie=UTF8&qid=1353848521&sr=8-1">preorder the book now!</a> from Amazon. It's out on February 6th, 2013.</p>
<p><strong>Open Source</strong></p>
<p>I've been working ons ome open source libraries that some readers might find interesting: <a href="https://github.com/jackfranklin/jQuery-Form-Validator">jQuery Form Validator</a>, <a href="http://github.com/jackfranklin/nodefetch">Nodefetch</a> and <a href="https://github.com/alphagov/magna-charta">Magna Charta</a>.</p>
<p><strong>Content is coming</strong></p>
<p>Tomorrow I'm excited to post the second screencast I've recorded. I've been practicing screencasts and I'm feeling more confident now, so hopefully in the future the split of screencast vs article will be a bit more even.</p>
<p><strong>Feedback Welcome</strong></p>
<p>As always, if you have any feedback, or requests, or would like to write for the site, please do just get in touch. I'd be happy to chat.</p>
JavaScript MV* Frameworks2012-12-03T00:00:00+00:00http://www.jackfranklin.co.uk/blog/javascript-mv-frameworks/<blockquote>
<p>"The massive growth in rich, JavaScript-heavy web applications has lead to a huge array of frameworks designed to help you build apps. There are so many that it can often be difficult to choose which best suits your needs, so in this article I'll discuss five of the most popular, and look at where each of their strengths lie. You shouldn't base your decision entirely on this article - I encourage you to play further with a framework before committing - but I hope this sets you off in the right direction."</p>
</blockquote>
<p>Another article I wrote for .net magazine went live last week: <a href="http://www.netmagazine.com/features/essential-javascript-top-five-mvc-frameworks">Five JavaScript MV* Frameworks</a>. In it I take a look at Backbone, Ember, Angular, Batman and Knockout. It's a high level summary of each so if you've been wondering which may suit your needs best, or what the differences are, I hope it may be of use.</p>
The new keyword in JavaScript2012-12-28T00:00:00+00:00http://www.jackfranklin.co.uk/blog/the-new-keyword-in-javascript/<p>The <code>new</code> keyword in JavaScript was an enigma to me for a long while, and only recently have I really begun to grasp it. In this article I'm going to attempt to succintly summarise the <code>new</code> keyword in JavaScript and the use cases.</p>
<p>First, let me pose a question. What will be logged to the console in this example?</p>
<p>function foo() {
this.x = 2;
return this;
}</p>
<p>var y = foo();
var g = foo();
g.x = 3;
console.log("y", y.x);
console.log("g", g.x);
console.log("this", this.x);</p>
<p>You might expect <code>y.x</code> to be <code>2</code>, as that's what it set to. However, you'll get the value <code>3</code> for every single logged output.</p>
<p>Within <code>foo()</code>, we set <code>this.x</code> to equal 2. <code>this</code> refers to the context in which the function was called.</p>
<p><strong>Update</strong>: Thanks to some folks in the comments for correcting me on the value of <code>this</code> within <code>foo()</code>. My original explanation wasn't quite correct. Here's a better explanation that I've pulled together from the contributions of Mike McNally and others.</p>
<p>The value of <code>this</code> has nothing at all to do with the calling scope. If there's no explicit receiver in the expression from which is derived the function object reference, and neither <code>call</code> nor <code>apply</code> are involved, then the value of <code>this</code> in the called function will always be the global scope (or, in "strict" mode, undefined).</p>
<p>Hence here when we invoke <code>foo()</code>, <code>this</code> within <code>foo()</code> is the global object. So we're setting <code>x</code> on the global object - which would be <code>window</code> within a browser.</p>
<p>So although <code>y</code> and <code>g</code> point at separate invocations of <code>foo()</code>, the returned object is the global object. So when <code>g.x</code> gets set to three, this changes the global <code>x</code>, which is what <code>y.x</code> points at. <a href="http://jsbin.com/welcome/67131/">You can see this working on JSBin</a>.</p>
<p>So, how would we keep <code>y.x</code> and <code>g.x</code> separate? This is where the <code>new</code> keyword comes into play. If we change these lines:</p>
<p>var y = foo();
var g = foo();</p>
<p>To:</p>
<p>var y = new foo();
var g = new foo();</p>
<p>We will then get the right results. <code>y.x</code> will be 2, <code>g.x</code> will be 3, and <code>this.x</code> is undefined. There's one more change we should make to stick with convention - change the function from <code>foo()</code> to <code>Foo()</code>. Any function that should be invoked with the <code>new</code> keyword, should have a capital at the beginning. Here's the new example:
function Foo() {
this.x = 2;
}
var y = new Foo();
var g = new Foo();</p>
<p>g.x = 3;
console.log("y", y.x);
console.log("g", g.x);
console.log("this", this.x);
You can <a href="http://jsbin.com/ekiqif/2/">see this working on JSBin</a>. So lets explore how and why this works.</p>
<p><code>new Foo()</code> creates and instantiates a new instance of <code>Foo</code>, and the scope that comes with it. <code>Foo()</code> is known as a <em>constructor function</em>. <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/constructor">This MDN article gives a very brief but useful overview of constructors.</a>.</p>
<p><a href="http://www.2ality.com/2012/01/js-inheritance-by-example.html">Dr. Axel Rauschmayer's post on inheritance</a> explains the job of a constructor:</p>
<blockquote>
<p>The constructor’s job is to set up the fresh object passed to it via the implicit parameter <code>this</code>. The fresh object is (implicitly) returned by the constructor and considered its instance.</p>
</blockquote>
<p>Hence, <code>var y = new Foo()</code> creates and returns a new instance of the <code>Foo</code> class. Notice that in the <code>Foo()</code> method, we don't have to explicitly <code>return this</code>. Because <code>Foo()</code> is a constructor, <code>this</code> (the new object) is returned implictly.</p>
<p>The <code>new</code> keyword is not as dangerous or confusing as it can first appear. Although it can be confusing, and certainly is a little odd on first look, once you can grasp the basics and understand the use cases, it has its place.</p>
<p>If you'd like to read further, <a href="http://pivotallabs.com/users/pjaros/blog/articles/1368-javascript-constructors-prototypes-and-the-new-keyword">this article on the Pivotal Labs blog</a> goes into good detail and a bit more in depth on the inner workings of the <code>new</code> keyword and prototypes. <a href="http://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript">This StackOverflow Question (and Answers)</a> also explores the <code>new</code> keyword in a lot of detail.</p>
JS Command Line Tooling2012-12-30T00:00:00+00:00http://www.jackfranklin.co.uk/blog/js-command-line-tooling/<p>My <a href="http://12devsofxmas.co.uk/post/2012-12-30-day-5-javascript-command-line-tooling">JS Tooling post</a> listed 5 of my favourite command line tools that I use every day when I'm doing some JS development. If you've any more to recommend, please do let me know!</p>
2012 in Review2013-01-02T00:00:00+00:00http://www.jackfranklin.co.uk/blog/2012-in-review/<p>Chris Coyier over at CSS Tricks does a yearly post documenting stats on the blog from the past 12 months, and it inspired me to do the same, as much as anything to have an easy way to compare year on year how the blog has done. Obviously this post wont quite be 12 months as the site has only existed for 9 months, having started in early April.</p>
<p>So, I set the Analytics to show me from April 8th (Day One) through to December 31st, and here are the results.</p>
<h5>Visitors</h5>
<p>The site had 104,280 unique visitors, with 246,878 pageviews. Of the visits, 63% were new visitors, with 37% returning visitors.</p>
<h5>Browsers</h5>
<p>I was delighted to see that the most popular browser was Google Chrome, accounting for over 60% of the visits. Mozilla Firefox was second, with 19% of visits, then Apple Safari with 9% was third. Internet Explorer (that's all IEs combined) is just 2.17%, which accounts for roughly 3,500 visits.</p>
<p>If you break IE down, 52.55% of IE hits were from IE9, with 33% of hits coming from IE8. IE10 was responsible for 6.6% of IE hits, and IE7 responsible for 5.5%, about 200 hits. IE6 had just 1.12%, which works out as just 40 visits. I guess with this blog being very much developer focused, there was always going to be a bias towards "modern" browsers. When I redesign the site next - whenever that might be - I will continue to support IE8+ but not look below that.</p>
<h5>Operating Systems</h5>
<p>No surprise that Windows is the top OS used, with 42% of visits. However, I was surprised to see that Mac was 34% and Linux 12%, meaning between them the Unix OS's outnumber Windows. Again, this is perhaps down to the audience of the blog. iOS had 3.74% of views, Android 2.73%.</p>
<p>Of the Windows hits, 79% were from Windows 7, with 14% from XP and 3% from Vista. Just 0.52% came from Windows 8. On the Mac front, 58% were from 10.7 (Lion), 21% from 10.8 (Mountain Lion) and 18.6% from 10.6 (Snow Leopard).</p>
<h5>Blog Stats</h5>
<p>Lets leave the Analytics behind and move on to post statistics. I wrote a total of 44 blog posts in the 9 months of the site being in existance, which is just under 5 per month. It wasn't steady though, a lot of those posts were in the first 3 months, before I was approached to write a book. With the book taking up a lot of time, at times it was months between posts going live, which is a shame. With the book now out of the way, I'm hoping in 2013 to average at least 4 posts per month, and hopefully do a few more as well. 4 per month is my baseline though.</p>
<p>In terms of commenting, I recently swapped from the in-built commenting system to Disqus. This did lose a lot of comments, but Disqus is a much nicer system and allows discussions to form easier.</p>
<h5>Thanks and Goals</h5>
<p>A few thanks are required here before I end. Firstly to <a href="http://tobyhowarth.co.uk/">Toby Howarth</a>, who provided me with the design you see right now when I was starting out. He's now available for hire, so if you're looking for a designer I'd recommend giving him a shout. I also want to thank the number of people who have posted links to blog posts on Twitter, Hacker News and so on, in particular <a href="http://twitter.com/elijahmanor">Elijah Manor</a>, who has tweeted most of my articles.</p>
<p>In terms of goals for next year, I've got a few:</p>
<ul>
<li>Average 4 posts per month minimum.</li>
<li>Get better at posting code from blog posts - set up a JSPlayground account on Github for it all to go in.</li>
<li>Make sure I reply to any questions in the comments as they come in.</li>
<li>Look into a "pro" area, or some form of members area, to try and bring in a small amount of money in from the site (it's unlikely this will happen this year though to be honest).</li>
<li>Continue to grow the blog, and aim to hit 500,000 page views in the year 2013 alone (essentially double what I managed in the past 9 months).</li>
<li>Release more screencasts. I like doing them a lot, but I've only found the time to do two so far. Out of the 4 posts per month, I hope one of them can be a screencast.</li>
</ul>
<p>Bring on 2013!</p>
Node.js workshops, March, London2013-01-04T00:00:00+00:00http://www.jackfranklin.co.uk/blog/node-js-workshops-march-london/<p>I've teamed up with the lovely folks at Event Handler, who run an array of events in London, to run two JavaScript workshops in March 2013 which I'm really excited about.</p>
<p>The first is on March 6th and is titled <a href="http://www.eventhandler.co.uk/events/ldnjsnightclass-toolingcli">Modern Tooling on the Command Line</a>. This workshop will run you through some of the powerful command line tools available to us that can really help speed up JavaScript development. We'll start with a brief introduction to the command line and then move on to trying out some of the tools, such as Yeoman, Grunt, Bower and so on.</p>
<p>The second is on March 27th and is titled <a href="http://www.eventhandler.co.uk/events/ldnjsnightclass-buildingcli">Building Command Line tools with Node</a>. In this workshop I want to demonstrate how you can use small tools like Node.js to piece together your own command line tools. Often I will write my own little tools to speed things up, and I think it's something more people should do. We'll build a few small tools, along with some bigger ones, and then also look at how we might publish our libraries to the Node Package Manager (npm).</p>
<p>To come along you'll need a Mac of some sort or a machine running Linux. I simply don't have the knowledge of Windos to be able to guarantee I can help with how to install things on Windows, unfortunately. Tickets cost £40 and are available at the above links. Both events are based at the Google Campus in London.</p>
<p>If you're interested but would like to clarify something or ask me questions, please leave a comment and I'll get back to you.</p>
Talking RequireJS at TakeOff Conf2013-01-19T00:00:00+00:00http://www.jackfranklin.co.uk/blog/talking-requirejs-at-takeoff-conf/<p>So this week I attended my first conference outside of the UK and travelled to a freezing Lille, in Northern France (it's been below freezing every day!) and spoke on <a href="http://requirejs.org/">RequireJS</a>, something I have <a href="http://javascriptplayground.com/blog/category/requirejs">written about before</a>.</p>
<p>In the future I will be doing a screencast on RequireJS in detail but for now I wanted to post up the slides and talk about the talk a little. <a href="https://speakerdeck.com/jackfranklin/requirejs-take-off-conf">You can view my slides on SpeakerDeck</a>.</p>
<p>The main thing I said in my talk with RequireJS that I wanted to reiterate is that when you first start it, you'll probably get frustrated. I know I did. The tipping point for me was when I figured out how to shim. When you first use Require it's tempting to just ditch it when you encounter a non-AMD compliant library (such as Underscore), but shimming it is so simple:</p>
<p>require.config({
shim: {
'lib/underscore': {
'exports': '_'
}
}
});</p>
<p>Something <a href="http://twitter.com/mheap">@mheap</a> pointed out to me that once you have an optimised JS file, you can swap out the RequireJS source for <a href="https://github.com/jrburke/almond">Almond</a>, a much more minimal AMD API that you can include into your build file - check the Github link for instructions on how to use.</p>
<p>I'm a huge fan of RequireJS and it's now very rare that I start a new JS project without utilising it.</p>
ECMAScript 5 Array Methods2013-01-27T00:00:00+00:00http://www.jackfranklin.co.uk/blog/ecmascript-5-array-methods/<p>Something I've not covered much so far is some of the newer parts of JavaScript. That is, methods in ECMASscript 5 that are not so commonly used due to browser support, and of course the new features in ECMAScript 6. Today I want to take a look at the new Array methods in ES5, such as <code>map</code> and <code>filter</code>.</p>
<p>If you'd like to know the browser support for these methods, it's actually pretty good. <a href="http://kangax.github.com/es5-compat-table/">This site shows the support</a>, and for most the only blip is IE 8 and lower. And if you do need to support older browsers, <a href="https://github.com/kriskowal/es5-shim">shims are available</a>. Let's have a look at the Array methods introduced in ES5. This wont be an in-depth look exploring the ins and outs of every method, but more a quick summary over them.</p>
<p>The first is <code>indexOf</code>. As you might suspect, it searches the array to find the index of the passed in element:</p>
<p>var arr = [1, 2, 3 ,4];
console.log(arr.indexOf(2)); // 1
console.log(arr.indexOf(5)); // -1</p>
<p>If the element doesn't exist, <code>-1</code> is returned. Be aware that <code>indexOf</code> finds the <strong>first</strong> index, if the element is in the array more than once:</p>
<p>var arr = [1, 2, 3 ,4, 2];
console.log(arr.indexOf(2)); // 1</p>
<p>There is also <code>lastIndexOf</code> that finds the last index:</p>
<p>var arr = [1, 2, 3 ,4, 2];
console.log(arr.lastIndexOf(2)); // 4</p>
<p>Next is <code>every</code>. The <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/every">mdn documentation</a> sums it up best:</p>
<blockquote>
<p>"<code>every</code> executes the provided callback function once for each element present in the array until it finds one where callback returns a false value. If such an element is found, the <code>every</code> method immediately returns <code>false</code>. Otherwise, if callback returned a <code>true</code> value for all elements, <code>every</code> will return <code>true</code>."</p>
</blockquote>
<p>Lets take a look at an example:</p>
<p>var arr = [1, 2, 3, 4];
console.log(arr.every(function(x) {
console.log(x);
}));</p>
<p>// 1
// false</p>
<p>Here the callback function logs one, but then doesn't return a truthy value, so <code>every</code> exists and returns false. It will loop over every element if our callback function returns true:</p>
<p>var arr = [1, 2, 3, 4];
console.log(arr.every(function(x) {
console.log(x);
return true;
}));</p>
<p>// 1
// 2
// 3
// 4
// true</p>
<p>Next we have <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/some"><code>some</code></a>. <code>some</code> executes a callback function once for every element present in the array until it finds a value for which the callback returns true, at which point <code>some</code> returns <code>true</code>. If no value is found, <code>some</code> returns <code>false</code>. Here I use <code>some</code> to test if any elements in the array are even:</p>
<p>var arr = [1, 2, 3 ,4];
console.log(arr.some(function(x) {
return x % 2 == 0
}));</p>
<p>// true</p>
<p>It returns <code>true</code> because at least one element made the callback function return <code>true</code>. If none of them do, it returns <code>false</code>:</p>
<p>var arr = [1, 3, 5, 7];
console.log(arr.some(function(x) {
return x % 2 == 0
}));</p>
<p>Next is <code>forEach</code>, which is very straight forward. It takes a function and calls that function for each element in the array:</p>
<p>var arr = [1, 2, 3, 4];
arr.forEach(function(x) {
console.log(x);
});
// 1
// 2
// 3
// 4</p>
<p><code>map</code> is similar to <code>forEach</code> in that in loops over all elements in the set and calls the callback function on them, however <code>map</code> will return an array which is the result of the callback function for each element. For example:</p>
<p>var arr = [1, 2, 3, 4];
var newArr = arr.map(function(x) {
return x * x;
});
console.log(newArr);
// [1, 4, 9, 16]</p>
<p>Here I use <code>map</code> to square each number in the array, and it then returns that new array.</p>
<p>We can use <code>filter</code> to trim down our arrays to elements that only match specific criteria. <code>filter</code> executes the callback function on each element, and will only add that element to the new array if the callback function returns <code>true</code>. Below I filter out any numbers that are not even:</p>
<p>var arr = [1, 2, 3, 4];
var newArr = arr.filter(function(x) {
return x % 2 == 0;
});
console.log(newArr);
// [2, 4]</p>
<p>The callback function only returns true for the even numbers, so the array <code>filter</code> returns contains just those.</p>
<p>Next is the slightly more complex <code>reduce</code>.</p>
<blockquote>
<p>"Apply a function against an accumulator and each value of the array (from left-to-right) as to reduce it to a single value."</p>
</blockquote>
<p>Taken from <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/Reduce">the MDN</a>.</p>
<p>The callback function for <code>reduce</code> is usually used with two arguments. The first is the previous value in the array, and the second is the next value. I find I understand this best with an example, so here is how we would use <code>reduce</code> to sum all the elements in an array:</p>
<p>var arr = [1, 2, 3, 4];
console.log(arr.reduce(function(x, y) {
return x + y;
}));
// 10</p>
<p>And the arguments are passed through like so:</p>
<p>(0, 1), (1, 2), (3, 3), (6, 4)</p>
<p>To give us an answer of ten. The MDN article on <code>reduce</code> is very thorough, so I highly recommend giving that a read if you're slightly confused.</p>
<p>Finally there is <code>reduceRight</code>, which is the same as <code>reduce</code> but starts on the right hand side, not the left.</p>
<p>var arr = [1, 2, 3, 4];
console.log(arr.reduceRight(function(x, y) {
return x + y;
}));
// 10</p>
<p>Here the arguments are processed from right to left:</p>
<p>(0, 4), (4, 3), (7, 2), (9, 1)</p>
<p>I hope this article has helped, if like me you'd not taken the time to explore some of these newer features, or perhaps had mistakenly dismissed them because you didn't realise how comprehensive the browser support is (other than our old friend IE8, of course).</p>
Exploring Backbone.js - Part 32013-02-03T00:00:00+00:00http://www.jackfranklin.co.uk/blog/exploring-backbone-js-part-3/<p>Way back in June last year I published <a href="http://javascriptplayground.com/blog/2012/06/exploring-backbone-js-part-2">part two of my Backbone series</a> and today, at long last, it's time to pick up the pieces. I apologise for such a lull between articles and hopefully it wont be quite so long between this and the next episode! I recommend you go back and skim <a href="http://javascriptplayground.com/blog/2012/04/backbone-js-tutorial-1">Part 1</a> and <a href="http://javascriptplayground.com/blog/2012/06/exploring-backbone-js-part-2">Part 2</a> first just to get up to speed.</p>
<p>Last time I left off we had just written the code to add a new item to our collection. What I'd like to do today is look at how we might filter down items in a collection. This will set us up nicely for the next article, which will look at Backbone's Router in more detail.</p>
<p>Firstly, lets set up the HTML needed to allow a user to filter down by price.</p>
<p><form id="filter">
<label>Less Than</label>
<input type="text" id="less-than">
<input type="submit" value="Filter">
</form>
<a href="#" id="clear-filter">Clear Filter</a></p>
<p>For now we will keep it simple and just let the user search for items less than a particular price.</p>
<p>Next we need to set up some events on our <code>CartCollectionView</code>. If you remember, this view encompasses the entire of our application (its <code>el</code> property is set to <code>"body"</code>), so this is where a lot of our events are set up. If you're thinking perhaps this isn't the best way, you're right. In a future episode when we add a couple more views, we will tidy this up. Add two more events to the <code>events</code> property:</p>
<p>events: {
"submit #add": "addItem",
"submit #filter": "filterItems",
"click #clear-filter": "clearFilter"
}</p>
<p>The methods we need to add to the cart collection view are very straight forward. All they will do is cancel the default action and then call methods on <code>itemView</code>, which is the view that all our items sit within.</p>
<p>filterItems: function(e) {
e.preventDefault();
this.itemView.filterByPrice();
},
clearFilter: function(e) {
e.preventDefault();
this.itemView.clearFilter();
}</p>
<p>To filter the items down to those lower than a specific price, here's what we need to do:</p>
<ol>
<li>Loop through every element in the collection and see if it matches the filter.</li>
<li>Re-render the item collection view with just those items in.</li>
</ol>
<p>Here's the entire code. Give it a read, and I'll explain it in depth below.</p>
<p>filterByPrice: function() {
// first reset the collection
// but do it silently so the event doesn't trigger
this.collection.reset(items, { silent: true });
var max = parseFloat($("#less-than").val(), 10);
var filtered = _.filter(this.collection.models, function(item) {
return item.get("price") < max;
});
// trigger reset again
// but this time trigger the event so the collection view is rerendered
this.collection.reset(filtered);
},</p>
<p>The first thing we do is <code>this.collection.reset(items, { silent: true })</code>. This will reset the collection, which is a way of completely changing the items in a collection. Here I reset it to the original array of items, which was stored in <code>items</code>. By passing in <code>{ silent: true }</code>, it means it wont trigger the <code>reset</code> event on the collection. We'll use this event later, and then you'll see why it's important not to trigger it there.</p>
<p>After that we grab the value from the input. I'm not doing any validation here which is obviously not sensible - but for the purposes of demonstrating Backbone it will do just fine. Then we can use Underscore's <code>filter</code> method. This takes an array of items, in this case all the models in the collection, and loops over them. Any that return <code>true</code> from the callback are returned. Therefore after running <code>filter</code>, only elements with a price less than the maximum will be returned. Then we can reset the collection again, but this time to just the filtered items.</p>
<p>Head up to the <code>initialize</code> method of the <code>ItemCollectionView</code> and at the bottom add a binding to the <code>reset</code> method that's called on the collection.</p>
<p>initialize: function() {
this.collection = cartCollection;
this.render();
this.collection.on("reset", this.render, this);
},</p>
<p>This means when a "reset" event is triggered on this view's collection, it will call the <code>render</code> method, with the context bound to <code>this</code>, which is the <code>ItemCollectionView</code>. Therefore when we detect the collection has been reset, we can re-render the view. This is why when we reset the collection to contain all elements, we passed in <code>{ silent: true }</code>. Else, we would re-render the item view to all elements just before we filtered it again, which wouldn't be very efficient.</p>
<p>Finally, we need to add the code for clearing the filter. The <code>clearFilter</code> method on the <code>ItemCollectionView</code> is very straight forward:</p>
<p>clearFilter: function() {
$("#less-than").val("");
this.collection.reset(items);
}</p>
<p>All it does is clear the input, and reset the collection back to all items.</p>
<p>With that, filtering and clearing the filter should work! There is a pretty big bug though. If you add a new item, and then do some filtering, that new item will not appear. This is because we reset the controller to contain <code>items</code>, which is our original set of items, and doesn't include any new items the user added. What we need to do is keep track of when we add a new item, and update our <code>items</code> array to contain those new items. When a collection's <code>add</code> method is called, it triggers an <code>add</code> event. Lets use this to solve our bug. Head to where we set up <code>var Cart</code> as our collection of items, and edit it so it looks like so:</p>
<p>var Cart = Backbone.Collection.extend({
model: Item,
initialize: function() {
this.on("add", this.updateSet, this);
},
updateSet: function() {
items = this.models;
}
});</p>
<p>It's just a case of updating the original set of items when a new one is added. Now new items that are added can be filtered, and are not lost when we filter and then clear the filter.</p>
<p>The code for this tutorial and the entire series is available <a href="https://github.com/javascript-playground/backbone-beginners/tree/tutorial3">on Github</a>. Please note that this repository is no longer on my personal account but on the <a href="https://github.com/javascript-playground">JavaScript Playground</a> organisation, which is where all future code will live.</p>
The .net Awards2013-03-29T00:00:00+00:00http://www.jackfranklin.co.uk/blog/the-net-awards/<p>Recently I found out that I had been nominated for two of <a href="http://www.thenetawards.com/">.net awards</a>. I've been nominated for "Young Developer of the Year" and "Brilliant Newcomer of the Year".</p>
<p>Firstly, you have to be nominated by people to be involved in the first place, so thanks to anyone who put my name forward. It means a lot that people would take the time to do that.</p>
<p>However, that's only half the battle! I'm up against some incredibly clever people and need all the votes I can get! If you can find a spare moment to navigate <a href="http://thenetawards.com/">to the awards site</a>, locate my face and click "vote", that would be awesome.</p>
<p>Finally, I know content has been slow recently, but that's not for much longer. Next weekend, on April 6th, the JS Playground turns 1 year old and I've plenty planned to celebrate. There will be lots of new content hitting your screens very soon.</p>
<p>Thanks,</p>
<p>Jack.</p>
Custom jQuery Builds with Grunt2013-04-02T00:00:00+00:00http://www.jackfranklin.co.uk/blog/custom-jquery-builds-with-grunt/<p>A lot has been made of how, in the future versions of jQuery, it will be possible to easily build your own version of jQuery, without the parts you know you're not going to use.</p>
<p>What a lot of people don't realise is that you can do this today, if you're prepared to install Grunt and grab the raw jQuery repository from Github. This quick tip will show you how.</p>
<p>First you're going to need Node and npm installed. Then get Grunt installed too. Note that since Grunt 0.4.0 the way of doing this has changed slightly. In the future I'll be covering Grunt in more detail but for now, follow the below instructions to get it going:</p>
<ul>
<li>If you've ever previously installed Grunt 0.3.0, get rid of it: <code>npm uninstall -g grunt</code>.</li>
<li>Now install the Grunt-CLI tool globally: <code>npm install -g grunt-cli</code>.</li>
</ul>
<p>This means each project on your machine can use a different version of Grunt, if it so desires. The Grunt CLI tool will use the first local version of Grunt it can find, so you can have specific version numbers on a project by project basis.</p>
<p>Next, lets clone the jQuery repository:</p>
<p>git clone git@github.com:jquery/jquery.git</p>
<p>Now navigate into that directory and install all dependencies:</p>
<p>cd jquery
npm install</p>
<p>The first time you clone the repository, you need to run Grunt once. This includes a number of tasks that update sub modules before running the tests and building jQuery:</p>
<p>grunt</p>
<p>That will give you the full jQuery source minified into the <code>dist/</code> folder. But say you wanted to build jQuery without any of the Ajax built in, as your current project is not going to need it. Try:</p>
<p>grunt custom:-ajax</p>
<p>You should get an output similar to this:</p>
<p>Running "custom:-ajax" (custom) task
Creating custom build...</p>
<p>Running "build:all:*:-ajax" (build) task
Excluding ajax (src/ajax.js)
Excluding ajax/script (src/ajax/script.js)
Excluding ajax/jsonp (src/ajax/jsonp.js)
Excluding ajax/xhr (src/ajax/xhr.js)
File 'dist/jquery.js' created.</p>
<p>Running "uglify:all" (uglify) task
Source Map "dist/jquery.min.map" created.
File "dist/jquery.min.js" created.
Uncompressed size: 209152 bytes.
Compressed size: 16767 bytes gzipped (73066 bytes minified).</p>
<p>Running "dist" task</p>
<p>Done, without errors.</p>
<p>And there you go! It's not only the Ajax module you can remove, <a href="https://github.com/jquery/jquery#modules">The jQuery Repository documents all of them</a>. If you're going to be working on a project where file size is important, and you know there's parts of jQuery you wont use, it's certainly worth doing a custom build this way to save a few bytes.</p>
jQuery CSS Hooks2013-04-08T00:00:00+00:00http://www.jackfranklin.co.uk/blog/jquery-css-hooks/<p>Did you know that jQuery gives you a way to write your own custom CSS methods? I didn't until recently and I'd like to show you why they are useful in this short tutorial.</p>
<p>How many times have you wanted to do this:</p>
<p>$("div").css("margin", "1px 2px 3px 4px");</p>
<p>But have to set each individual direction value separately? I know I have. Using CSS Hooks, we can easily add the above functionality to jQuery.</p>
<p><strong>A word of warning: CSS Hooks were added in jQuery 1.4.3, so if you're stuck on an older version (you really shouldn't be by now) then this wont work.</strong></p>
<p>Lets set up the wrapper for our new margin CSS hook. What we'll need to do is split the user's input into 4 values, one for each direction. First, I can set up an array containing the four directions. You'll see why this is important shortly:</p>
<p>var directions = ["Top", "Right", "Bottom", "Left"];</p>
<p>Next, lets define our new "margin" hook. The hooks are stored as objects with two methods, <code>get</code> and <code>set</code>:</p>
<p>$.cssHooks.margin = {
get: function(elem) {
},
set: function(elem, value) {
}
};</p>
<p>Note that the <code>get</code> method does take more arguments, including the computed value of the specific CSS property it's being asked for. <a href="http://api.jquery.com/jQuery.cssHooks/">The jQuery documentation discusses this in more detail</a>.</p>
<p>Let's write the <code>set</code> method first. This take two arguments, the element to set the CSS properties on, and the value the user passed. In our case this will be a string of values, eg "1px 2px 3px 4px".</p>
<p>set: function(elem, value) {
$.each(value.split(" "), function(i, val) {
elem.style["margin + directions[i]"] = val;
});
}</p>
<p>Here we split the values at a space, and loop over them. We use the directions array so for each value the relevant direction property is set. So here we loop over, first setting <code>marginTop</code>, then <code>marginRight</code>, and so on.</p>
<p>The <code>get</code> method will essentially do the reverse, getting each of the individual values and then joining them together into a string:</p>
<p>get: function(elem, value) {
var res = [];
$.each(directions, function(i, dir) {
res.push($.css(elem, "margin" + dir));
});
return res.join(" ");
}</p>
<p>We can use <code>$.css</code> to pull out a CSS setting. All this method does is grab the four individual values and add them to an array, which I then join at the end to return a string.</p>
<p>Now there's obviously some problems. In CSS we can do <code>margin: 5px 10px</code> to set top/bottom to 5px and left/right to 10px. Currently our implementation doesn't do this. Thankfully someone else has already done this. Brandon Aaron's <a href="https://github.com/brandonaaron/jquery-cssHooks">CSS Hooks project</a> has a number of hooks, including a more feature-complete margin implementation.</p>
<p>As I said in the opening, this was a jQuery feature I'd managed to completely miss, and I bet I'm not the only one, hence writing this post. <a href="http://jsbin.com/enixej/2/edit">My margin implementation is up on JSBin</a> if you'd like to have a play with it, and if you write any interesting CSS Hooks yourself, do let me know in the comments. I can think of a number of scenarios in which they could be very useful.</p>
Moving to Jekyll2013-06-02T00:00:00+00:00http://www.jackfranklin.co.uk/blog/jekyll/<p>Yesterday I finally sat down and properly ported the site over to Jekyll, the static site generator. Before I used <a href="http://pyrocms.com/">PyroCMS</a>. I've nothing against Pyro, it's great, but it was a bit over kill in this instance.</p>
<p>You'll also notice there wasn't a single blog post in May, which is frustrating from my point of view. I will soon be able to commit more time to the JS Playground and have already started work on some up-coming tutorials:</p>
<ul>
<li>Express and Backbone Series: Parts 4 and 5</li>
<li>JavaScript Refactoring</li>
<li>Modular Backbone Development</li>
<li>Review of <a href="http://discovermeteor.com/">Discover Meteor</a></li>
<li>Handlebars Templating</li>
<li>A look at the new Yeoman</li>
<li>Developing for Firefox OS</li>
</ul>
<p>Additionally, now that the site is <a href="https://github.com/jackfranklin/javascriptplayground.com/tree/gh-pages">hosted on Github</a>, it means anyone can contribute through a pull request. If you have something you'd like to write, please feel free to. All posts from guests are clearly credited to them.</p>
<p>In moving the site over to Jekyll I took care to make sure that no URLs broke - Jekyll's slugs have been configured to exactly match those of the old site so no posts or Disqus comments should have been lost. I'm also working on tweaking the design and there's still some rough patches there. Those of you who subscribe to RSS may need to update your subscription. <a href="http://feeds.feedburner.com/TheJavascriptPlayground">The new RSS feed is here</a>.</p>
<p>I'm excited to have JS Playground on Jekyll, and hopefully it will reduce the friction of writing, allow you all to contribute should you wish and mark the beginning of me being able to post much more frequently.</p>
Refactoring DOM Heavy JS2013-06-03T00:00:00+00:00http://www.jackfranklin.co.uk/blog/refactoring-js/<p>One of the things I've been getting more into recently is refactoring. It's something that is heavily talked about in the Ruby world, but seems to be a bit less so in the JS world. In this post what I've done is write some of my own (crappy) JavaScript for some simple JS tabs, using bad habits and code smells. I'll then look at how, if I was new to this code, I might start refactoring.</p>
<h3>Bad beginnings</h3>
<p>You can view the "bad" code I started with <a href="https://github.com/javascript-playground/refactoring-js/commit/3e0fd4f55daa77557044569b55397622d68c50d1">on Github</a>.</p>
<p>Here is our starting point:</p>
<p>var tabularize = function() {
var active = location.hash;
if(active) {
$(".tabs").children("div").hide();
$(active).show();
$(".active").removeClass("active");
$(".tab-link").each(function() {
if($(this).attr("href") === active) {
$(this).parent().addClass("active");
}
});
}
$(".tabs").find(".tab-link").click(function() {
$(".tabs").children("div").hide();
$($(this).attr("href")).show();
$(".active").removeClass("active");
$(this).parent().addClass("active");
return false;
});
};</p>
<p>The corresponding HTML looks like this:</p>
<p><div class="tabs">
<ul>
<li class="active"><a href="#tab1" class="tab-link">Tab 1</a></li>
<li><a href="#tab2" class="tab-link">Tab 2</a></li>
<li><a href="#tab3" class="tab-link">Tab 3</a></li>
</ul>
<div id="tab1">
<h3>Tab 1</h3>
<p>Lorem ipsum dolor sit amet</p>
</div>
<div id="tab2">
<h3>Tab 2</h3>
<p>Lorem ipsum dolor sit amet</p>
</div>
<div id="tab3">
<h3>Tab 3</h3>
<p>Lorem ipsum dolor sit amet</p>
</div>
</div></p>
<p>Hopefully you're already starting to spot problems here. Here's a list of things I found that I'd like to change:</p>
<ul>
<li><strong>Selector reuse</strong>. Notice how the code is full of <code>$(".tab")</code> or similar. This is bad, not just for efficiency, but just for the pain of having to update all these references if the class changes.</li>
<li><strong>Not very DRY (Don't repeat yourself)</strong>. There's plenty of duplication here across the two parts.</li>
<li>Use of <code>click()</code>, rather than the preferred <code>on()</code>.</li>
<li>Using <code>return false</code> rather than <code>e.preventDefault()</code>.</li>
<li>It's very much tied to a specific DOM Structure. Often it's best to try to generalize your jQuery selectors and DOM traversal so small HTML changes (renaming a class, etc) don't break all your behaviour.</li>
</ul>
<p>Something that I won't cover here is changing this code into a jQuery plugin. In reality I probably would do this, but in this instance I'd rather discuss specific refactorings within this system, so the moving to a plugin is just an abstraction too many.</p>
<h3>Breaking code down</h3>
<p>This code is largely split into two parts. The first activates a specific tab if it is in the URL. For example, if <code>http://foo.com/#tab2</code> is hit, the second tab will be activated. The second part adds click handlers to all the tab links so we can click to swap between them.</p>
<p>The first thing I like to do in this case is write some tests. I decided to use QUnit to do so. I won't go into great detail on QUnit (<a href="http://javascriptplayground.com/blog/2012/04/javascript-testing-qunit-1/">I've written an intro to it before</a>), but you can <a href="https://github.com/javascript-playground/refactoring-js/blob/master/test/tests.js">see the test JS on Github</a>. I won't paste it in here as it's pretty long. Essentially I wrote tests that test:</p>
<ul>
<li>When we visit the page, the 1st tab is visible.</li>
<li>When I click the link for tab 2, the 2nd tab is activated.</li>
<li>When the URL has <code>#tab2</code> in it, the 2nd tab is activated when the page loads.</li>
</ul>
<p>I am a big fan of having these tests as it means I can refactor with confidence that I'm not breaking things. Of course, I'll always manually test too, but having tests to back me up is great.</p>
<h3>Selector Reuse</h3>
<p>First we should tackle the reusing of selectors. This one is easy to fix, just scan through the code and find any selectors, or DOM traversal methods, that are used lots. I've pulled out three, for now:</p>
<p>var tabsWrapper = $(".tabs");
var tabs = tabsWrapper.children("div");
var tabLinks = tabsWrapper.find(".tab-link");</p>
<p>Now you've done that, you can go through and replace all instances of <code>$(".tabs")</code> with <code>tabsWrapper</code>, and so on. Rerunning my tests after <a href="https://github.com/javascript-playground/refactoring-js/commit/6db02d7847330bc6bbd861cc7757806fb7d16205">that commit</a> shows us as all green. Great! The secret to refactoring is lots of little steps. No big steps at once.</p>
<h3>Spotting Duplication</h3>
<p>Now lets look at the duplication. We're doing the same work in more than one place right now and this can be tidied up. The first is the process for marking the tab link as active. There's two bits to this:</p>
<ol>
<li>Remove the <code>active</code> class from the current link.</li>
<li>Add the <code>active</code> class to the new link.</li>
</ol>
<p>And we have to do this in two places, once within the code for checking hashes (we'll refactor that in a bit, but remember, small steps) and also in the click handler. This is where I'd typically make a method to do this for me:</p>
<p>var activateLink = function(elem) {
$(".active").removeClass("active");
elem.addClass("active");
};</p>
<p>And then use that in both places:</p>
<p>if(active) {
tabs.hide();
$(active).show();
$(".tab-link").each(function() {
if($(this).attr("href") === active) {
activateLink($(this).parent());
}
});
}
tabLinks.click(function() {
tabs.hide();
$($(this).attr("href")).show();
activateLink($(this).parent());
return false;
});</p>
<p>Don't worry if right now you're spotting some code that doesn't look right (I know I am). Refactoring is all about going slowly, even if you end up undoing some of your work later on. Once again, the tests are green. <a href="https://github.com/javascript-playground/refactoring-js/commit/eeab097e8070673fd8f39c5bfb1db69e43d8d0de">You can see the commit on Github</a>.</p>
<h3>Quick wins</h3>
<p>Now I want to do a couple of quick fixes in the event handler for the links. I'm going to swap out <code>click</code> for an <code>on</code> call, and swap <code>return false</code> for <code>e.preventDefault()</code>:</p>
<p>tabLinks.on("click", function(e) {
e.preventDefault();
tabs.hide();
$($(this).attr("href")).show();
activateLink($(this).parent());
});</p>
<p>If you're wondering why <code>return false</code> is bad, <a href="http://fuelyourcoding.com/jquery-events-stop-misusing-return-false/">give this post by Doug Neiner a read</a>. I've also moved the <code>preventDefault</code> call to the top, as I like for it to be immediately apparent that the default action is cancelled. Once again, we're green and <a href="https://github.com/javascript-playground/refactoring-js/commit/29d9db8ab6d5604c8a20a0f45b8ff2d43de8b3c1">you can see the commit here</a>.</p>
<h3>More duplication</h3>
<p>There's some more duplication across the two parts of the code here. Similarly to before, the code for activating a new tab is in two places. It can be summed up as:</p>
<ol>
<li>Hide all the tabs</li>
<li>Show the one tab</li>
</ol>
<p>That's easy to write, and use:</p>
<p>var activateTab = function(tabHash) {
tabs.hide();
$(tabHash).show();
};
...
if(active) {
activateTab(active);
...
}
tabLinks.on("click", function(e) {
e.preventDefault();
activateTab($(this).attr("href"));
...
});</p>
<p>And sure enough, we're green. <a href="https://github.com/javascript-playground/refactoring-js/commit/9ae8424b4cf99a097f6ef545e88bf578ee450450">Here's that commit</a>.</p>
<h3>Finding the active link</h3>
<p>Now you can see the code for the URL hash and the event handler are very similar. In fact, the only difference is that the first has to search through all the links to find the one that should be active:</p>
<p>$(".tab-link").each(function() {
if($(this).attr("href") === active) {
activateLink($(this).parent());
}
});</p>
<p>We can write this shorter though, using jQuery's <code>filter</code> method and selecting by attribute:</p>
<p>if(active) {
activateTab(active);
activateLink($(".tab-link").filter("[href='" + active + "']").parent());
}</p>
<p>That's a nicer way of doing things, even if it is quite a long line. I'd be tempted here to create a variable first:</p>
<p>var link = $(".tab-link").filter("[href='" + active + "']").parent();
activateLink(link);</p>
<p>Although it adds a line, it makes it cleaner, in my opinion. Remember, line count is not a measure of a good or bad refactoring. Our tests are green, and <a href="https://github.com/javascript-playground/refactoring-js/commit/3caea006cef342269981e9ae2fabb205064fcfdb">here's that commit</a>.</p>
<p><strong>Update</strong>. As <a href="http://twitter.com/mheap">Michael</a> pointed out, there's no need to use <code>filter</code> here, we can just simply attach the attribute selector to the class selector:</p>
<p>var link = $(".tab-link[href='" + active + "']").parent();</p>
<p>With that being shorter, you could then miss out the temporary variable:</p>
<p>activateLink($(".tab-link[href='" + active + "']").parent());</p>
<p>This change isn't reflected in the Git commits as it was made after I made them, but feel free to make this change yourself.</p>
<p><strong>Update 2</strong>. <a href="http://twitter.com/rodneyrehm">Rodney</a> makes a good point that you might prefer to use <code>filter</code>, but pass it a function, which may also bring speed benefits:</p>
<p>$(".tab-link").filter(function() { return this.href.hash === active });</p>
<p>As Rodney explains: "I'd expect (not tested) <code>filter(function(){ return this.href === active; })</code> to be just as fast (if not faster, as no parsing)"</p>
<p><strong>Update 3</strong>. What we should be doing here is using our <code>tabLinks</code> variable. We can combine that with the <code>filter</code> method and use it like Rodney suggests, passing it a function:</p>
<p>var transition = function(hash) {
activateTab(hash);
activateLink(tabLinks.filter(function() {
return $(this).attr("href") === hash;
}).parent());
};</p>
<p>We have to use <code>$(this).attr("href")</code> instead of the shorter <code>this.href</code> as <code>this.href</code> gives us the full URL, including the domain, even though the link is just <code>#tab1</code>. jQuery normalises this, returning just the link within the anchor tag.</p>
<h3>The <code>transition</code> method</h3>
<p>Now our two parts look identical. Both call <code>activateTab</code> and <code>activateLink</code>. Seems like that could become a method too:</p>
<p>var transition = function(hash) {
activateTab(hash);
activateLink(tabLinks.filter(function() {
return $(this).attr("href") === hash;
}).parent());
};</p>
<p>Now all we have to do is pass a hash, like <code>"#tab1"</code> to <code>transition</code>, and everything is taken care of. I can update the code to reflect this:</p>
<p>var active = location.hash;
if(active) {
transition(active);
}
tabLinks.on("click", function(e) {
e.preventDefault();
transition(this.href.hash);
});</p>
<p>Now, in my opinion, that's much nicer than when we started. <a href="https://github.com/javascript-playground/refactoring-js/commit/07e063a4ceddca8aa4093c3bad9a4aecf4a088b6">Here's that commit</a>.</p>
<h3>Two more quick wins</h3>
<p><a href="http://twitter.com/elijahmanor">Elijah</a> was kind enough to point out a couple of enhancements. The first is to limit the scope when we search for <code>.active</code> to within the <code>tabWrapper</code>, which makes sense. Simply swap out:</p>
<p>$(".active")</p>
<p>for:</p>
<p>tabWrapper.find(".active");</p>
<p>Similarly, using <code>parent()</code> to find the link's <code>li</code> is more brittle to simple HTML changes. What if an extra <code>span</code> tag is wrapped round a link? Better to use <code>closest("li")</code>, which will still work even if the HTML changes slightly.</p>
<p>var transition = function(hash) {
activateTab(hash);
activateLink($(".tab-link[href='" + hash + "']").closest("li"));
};</p>
<p>Those commits are documented <a href="https://github.com/javascript-playground/refactoring-js/commits/master">on the master branch</a>.</p>
<h3>Post Refactor</h3>
<p>As a recap, here's what the JS looks like now:</p>
<p>var tabularize = function() {</p>
<p>var tabsWrapper = $(".tabs");
var tabs = tabsWrapper.children("div");
var tabLinks = tabsWrapper.find(".tab-link");</p>
<p>var activateLink = function(elem) {
tabsWrapper.find(".active").removeClass("active");
elem.addClass("active");
};</p>
<p>var activateTab = function(tabHash) {
tabs.hide();
$(tabHash).show();
};</p>
<p>var transition = function(hash) {
activateTab(hash);
activateLink(tabLinks.filter(function() {
return $(this).attr("href") === hash;
}).closest("li"));
};</p>
<p>var active = location.hash;
if(active) {
transition(active);
}
tabLinks.on("click", function(e) {
e.preventDefault();
transition($(this).attr("href"));
});
};</p>
<p>Is it longer? <strong>Yes</strong>. Is it cleaner, more DRY and easier to follow? In my opinion, <strong>Yes it is</strong>. We've gone from a mess of spaghetti JavaScript with ugly selectors being reused, code being duplicated and the meaning obfuscated to a easier to follow, more organised structure.</p>
<h3>Better Structure</h3>
<p>There's a bit more to be done here. There's also a big bug in the way tabs are activated based on the hash in the URL, but I'm going to leave that one to you to fix. At this point, I would consider moving the tab code into a more structured form, such as an object. Doing it this way also makes it easier to move into a jQuery plugin, as the plugin can just call the object. It's also <strong>bad practice to have functions contained within functions</strong>, which is why my next step would be refactoring into an object (or what you might call a JS "class").</p>
<p>I'm not going to go through it here, as this tutorial is long enough already, but have written and committed a new version to <a href="https://github.com/javascript-playground/refactoring-js/tree/class-version">a branch on Github</a> for you to fully dive into. I will also try to write about it in a future post.</p>
<h3>To conclude</h3>
<p>Refactoring is fun! It's probably my favourite part of being a developer. Things that I try to do as typical refactorings are:</p>
<ol>
<li>Put things in variables if you reference them often.</li>
<li>Remove temporary variables, or variables that are only used once (some exceptions to this).</li>
<li>Don't be afraid to make more functions. The best functions are small functions.</li>
<li>Don't be afraid to add a bit more structure at the expense of line count (which is very rarely a good measure of code).</li>
<li>Have some tests to back up if your refactoring is going well and hasn't broken functionality.</li>
<li>Take lots of small steps. Move very slowly, and resist the urge to immediately refactor everything at once. Be methodical.</li>
</ol>
<p>I hope this was a useful post. If you've any queries or questions, leave a comment and I'll endeavour to get back to you. Alternatively, you can drop me a tweet (@Jack_Franklin) or feel free to email me too.</p>
<p><em>Some of the links to Git commits have become slightly out of sync with the code, mainly due to tweaks following great feedback from folks on Twitter. You can see all the commits and the process I took <a href="https://github.com/javascript-playground/refactoring-js/commits/master">here</a>.</em></p>
Meet pulldown2013-06-10T00:00:00+00:00http://www.jackfranklin.co.uk/blog/pulldown/<p>A good couple of months ago, I sat down with fellow JavaScripter <a href="http://twitter.com/phuunet">Tom Ashworth</a> to rewrite my JS tool <a href="https://github.com/jackfranklin/pulldown">pulldown</a>. I thought it would be of interest to readers, both as a useful tool, and an example of developing relatively complex CLI tools.</p>
<p>Pulldown will help you quickly and easily download libraries. For example, running:</p>
<p>$ pulldown jquery</p>
<p>Will instantly download you the latest minified source of the jQuery library. We use <a href="http://cdnjs.com/">cdnjs</a> to search for what you looked for. It can also do versioning:</p>
<p>$ pulldown jquery@1.8.2</p>
<p>It's <strong>not supposed</strong> to be a replacement for Bower, nor is it meant to replicate the features, but it's designed to sit right in the middle. If you need a quick CLI way to download a library, this might just be of use.</p>
<p>It's fully documented <a href="https://github.com/jackfranklin/pulldown">in the Github repo</a> and you can install it right now through npm:</p>
<p>$ npm install -g pulldown</p>
<p>If you do use it, please get in touch if you have any (good or bad) feedback. Would love to hear it.</p>
More Refactoring2013-06-12T00:00:00+00:00http://www.jackfranklin.co.uk/blog/refactoring-part-2/<p>Last week's <a href="http://javascriptplayground.com/blog/2013/06/refactoring-js/">refactoring post</a> turned out more popular than expected and I wasn't going to revisit it. However, it got so much interest that I'd like to.</p>
<p>Here's the code we ended up with at the end:</p>
<p>var tabularize = function() {</p>
<p>var tabsWrapper = $(".tabs");
var tabs = tabsWrapper.children("div");
var tabLinks = tabsWrapper.find(".tab-link");</p>
<p>var activateLink = function(elem) {
tabsWrapper.find(".active").removeClass("active");
elem.addClass("active");
};</p>
<p>var activateTab = function(tabHash) {
tabs.hide();
$(tabHash).show();
};</p>
<p>var transition = function(hash) {
activateTab(hash);
activateLink(tabLinks.filter(function() {
return $(this).attr("href") === hash;
}).closest("li"));
};</p>
<p>var active = location.hash;
if(active) {
transition(active);
}
tabLinks.on("click", function(e) {
e.preventDefault();
transition($(this).attr("href"));
});
};</p>
<p><em>(If you haven't already, I recommend reading <a href="http://javascriptplayground.com/blog/2013/06/refactoring-js/">the first post</a>. This won't make much sense on its own)</em></p>
<p>At that point, I ended the post with:</p>
<blockquote>
<p>"At this point, I would consider moving the tab code into a more structured form, such as an object. Doing it this way also makes it easier to move into a jQuery plugin, as the plugin can just call the object."</p>
</blockquote>
<h3>The Further Refactoring</h3>
<p>And I'd like to talk a bit about that here, as I had a lot of questions about it. Here's my final class version of the tabs code:</p>
<p>var Tabularize = function(elem) {
this.tabsWrapper = $(elem);
this.tabs = this.tabsWrapper.children("div");
this.tabLinks = this.tabsWrapper.find(".tab-link");
this.checkHash();
this.bind();
};</p>
<p>Tabularize.prototype = {
bind: function() {
var self = this;
this.tabLinks.on("click", function(e) {
e.preventDefault();
self.transition($(this).attr("href"));
});
},
checkHash: function() {
var active = location.hash;
if(active) {
this.transition(active);
}
},
transition: function(hash) {
this._activateTab(hash);
var link = tabLinks.filter("[href='" + hash + "']").closest("li");
this._activateLink(link);
},
_activateLink: function(elem) {
tabWrapper.find(".active").removeClass("active");
elem.addClass("active");
},
_activateTab: function(hash) {
this.tabs.hide();
$(hash).show();
}
}</p>
<p>I have become a massive fan of abstracting things into objects like this in JavaScript. It forces you to structure your code better and positively influences the readability of your code (once you get used to this way of doing things).</p>
<h3>jQuery Plugin</h3>
<p>The beauty of this is how easy it would be to turn into a jQuery Plugin. Rather than write a messy jQuery plugin to do all this tabbing code, all we have to do is create a jQuery plugin that instantiates a new version of the <code>Tabularize</code> object, passing in the element. Something like this should suffice:</p>
<p>$.fn.tabularize = function() {
return this.each(function() {
new Tabularize(this);
});
}</p>
<p>I really like moving code out of jQuery plugins and making the jQuery plugin just call code that's contained elsewhere.</p>
<h3>Cleaner</h3>
<p>Comparing the first refactoring to the second, in my opinion the second is definitely cleaner. The first has functions within function (a bad thing to do), and it's also unclear what methods are available. At a glance, it's difficult to quickly decipher. The second is much clearer. At a glance, I could tell you the main method names. I could also suggest that methods that start with an underscore are not designed to be used publically.</p>
<h3>Short Methods</h3>
<p>Notice also that every method is very short. In <a href="http://www.youtube.com/watch?v=DC-pQPq0acs">Ben Orenstein's Refactoring talk</a> at Aloha Ruby, Ben says that shorter methods are far superior, and he's coming round to the idea that every public method should be one line. The talk is on Ruby, but I still think some of the ideas are relevant. Whilst one line per method is perhaps ambitious, I am absolutely with Ben in terms of keeping methods short and this Tabularize object achieves that.</p>
<p>There's a lot of different ways to refactor and restructure, and you should by no means take what I've discussed in these posts as the only way to do things. If you'd have gone about this differently, please leave a comment, I enjoy seeing how others go about this.</p>
The Firefox OS Hello World2013-07-03T00:00:00+00:00http://www.jackfranklin.co.uk/blog/firefoxos1/<p>I recently got my hands on a <a href="http://www.geeksphone.com/">Firefox OS preview device, a Keon</a> and today I'm going to show you how to get a simple Hello World app running on the phone. Note that you don't need a phone to follow through - we will also use the Firefox OS simulator which can run on any machine (it's a Firefox browser plugin) and you can easily run your application through that. The phone is just the extra bonus bit at the end!</p>
<p>To install the simulator just load up Firefox and <a href="https://addons.mozilla.org/en-US/firefox/addon/firefox-os-simulator/">head to the simulator download page</a>. From there you can install it to Firefox OS. Hit the button on the left of the simulator dashboard to run the simulator and you should see the "device" appear:</p>
<p><img src="https://cl.ly/image/2k2T2X3E3S1f/Screen%20Shot%202013-07-01%20at%2011.42.08.png" alt=""></p>
<p>Now lets make an app. Apps are almost deceptively simple to create. It really is just HTML, CSS and JavaScript! As always, <a href="https://github.com/javascript-playground/firefoxos-helloworld">you can find all the code on Github</a>.</p>
<p>The first thing to do is create an <code>index.html</code> page. This just links to a couple of JS files, one of which is jQuery, and contains an empty <code>div</code>:</p>
<p><!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
<script src="http://www.jackfranklin.co.uk/blog/firefoxos1/js/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<script src="http://www.jackfranklin.co.uk/blog/firefoxos1/js/app.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div></div>
</body>
</html></p>
<p>Create a <code>js</code> directory and grab the latest version of jQuery into it. Then create <code>app.js</code> and put this within:</p>
<p>$(function() {
$("div").text("Hello World!");
});</p>
<p>When the app loads we should see the text "Hello World" appear in the empty <code>div</code>.</p>
<p>Finally, we need to create a <code>manifest.webapp</code> file. This is similar to how <code>package.json</code> works with Node and npm apps in that it tells the system about the app and how to run it. Inside the application manifest goes some simple JSON:</p>
<p>{
"name": "Hello World",
"description": "Jack's test Hello World app",
"version": "1.0",
"launch_path": "/index.html",
"developer": {
"name": "Jack Franklin",
"url": "http://jackfranklin.co.uk"
}
}</p>
<p>The main property there to note is <code>launch_path</code>. This is the file that the app will load up first when it is run by the user.</p>
<p>Now we have our app, we can try running it through the simulator. On the simulator dashboard, click the "Add Directory" button and then navigate to the folder which contains the manifest file. Double click on that manifest file to select it. You'll see the device boot and run your app, complete with the "Hello World" text we inserted.</p>
<p><img src="https://cl.ly/image/3E2Y2s2S1c2u/Screen%20Shot%202013-07-01%20at%2011.52.30.png" alt=""></p>
<p>Finally, lets install it on the device itself. The instructions on how to do this vary depending on your OS, so rather than type them all here, I suggest <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox_OS/Debugging/Connecting_a_Firefox_OS_device_to_the_desktop">reading the MDN documentation</a>. Once you've done that, and enabled remote debugging on the device, connect it to your computer via the USB lead.</p>
<p>You should see a new "Push" icon appear:</p>
<p><img src="https://cl.ly/image/1D0g0R0J0p0b/Screen%20Shot%202013-07-03%20at%2014.23.08.png" alt=""></p>
<p>Hit that, and your app should be installed on the phone.</p>
<p><img src="https://cl.ly/image/3I3i0j0s1o0C/2013-07-03%2014.23.57.jpg" alt=""></p>
<p>I hope this quick tutorial helps. The aim here wasn't to go into any huge depth, but provide a very quick "Getting started" app. In the future I'll delve into more of the APIs available and what can be done with them. In the mean time, <a href="https://developer.mozilla.org/en-US/docs/Tools/Firefox_OS_Simulator">The MDN page</a> has a huge amount of documentation.</p>
Announcing 'Confident jQuery'2013-07-16T00:00:00+00:00http://www.jackfranklin.co.uk/blog/confident-jquery/<p>At the weekend I annouced my latest project, "Confident jQuery". It's going to be a book, self-published through Leanpub aimed at those who are confident enough using the jQuery API and its methods, but want to take that next step. From the book's about page:</p>
<p>Confident jQuery is for those who feel comfortable writing jQuery but want to improve their ability to structure their JavaScript better. If you have ever found yourself with messy JavaScript that is heavily tied to the structure of your HTML, or had your entire jQuery carousel refuse to start-up because you changed just one tiny class name in your HTML code, this book will help.</p>
<p>Through the course of this book we'll study and discuss:</p>
<ul>
<li>how to make your code more structured and maintainable so you don't revisit it 6 months down the line and shudder.</li>
<li>how you can write cleverer, more contextual selectors to avoid your jQuery being quite so tightly tied to the HTML structure.</li>
<li>why not all your code should live within that one $(document).ready() call</li>
<li>how we can leverage plain JavaScript objects to clean our code up considerably</li>
<li>discuss refactoring methods to tackle old code and improve it</li>
<li>how in certain situations at all using jQuery is actually harder than using plain JavaScript</li>
<li>how to write tests for your jQuery</li>
<li>and much more.</li>
</ul>
<p>###What the book isn't</p>
<p>This book will not look at any additional libraries. We'll just be using jQuery all the way through (with the exception of QUnit for the testing chapter). This is not a book about telling you how to use RequireJS to load in your code in a modular fashion and nor will it tell you that you should use an additional library like Backbone or Angular.</p>
<p>This book is also not aimed at those who have never written jQuery before. You should have a good grasp of jQuery before tackling this book.</p>
<h3>Sign up for updates</h3>
<p>If this sounds interesting, please <a href="https://leanpub.com/confidentjquery">register your interest on Leanpub</a>. It's my hope that the first "beta" version will be available in 3-4 weeks.</p>
A new look2013-08-14T00:00:00+00:00http://www.jackfranklin.co.uk/blog/new-design/<p>Today I'm happy to go live with the new design of the JavaScript Playground! My thanks go hugely to <a href="http://twitter.com/benhowdle">Ben Howdle</a> and <a href="http://twitter.com/martinbean">Martin Bean</a>. The beautiful new design is the work of Ben, and Martin did a lot of the hard work turning it into HTML and CSS. I just added some final touches and moved it into Jekyll. This is also a good point to once again thank <a href="http://twitter.com/tobyhowarth">Toby Howarth</a> who's original design lasted 16 months. Toby came up with the yellow which is now pretty much the most recognisable trait of the website.</p>
<p>To celebrate the launch of the new design there's a number of tutorials coming your way very soon. On Friday I'll give you an introduction to working with maps using <a href="http://leafletjs.com/">LeafletJS</a>, and next week I'll be looking at testing Node modules that make API calls, and how to mock those requests. The popular Express & Backbone series will also have another episode out early next week too. I'm also chatting to lots of lovely folk who will be writing articles in the future, with lots of great topics on the way.</p>
<p>If you find any bugs with the new site (there are always), please <a href="https://github.com/jackfranklin/javascriptplayground.com/issues/new">report it on GitHub</a>.</p>
Mocking API Requests in Node tests2013-08-19T00:00:00+00:00http://www.jackfranklin.co.uk/blog/mocking-web-requests/<p>Recently I sat down with my <a href="https://github.com/jackfranklin/pulldown">Pulldown Project</a>, aiming to rewrite the tests. The problem with them was that they were network dependent. Each test would hit the real API and download the real file. This was not good for a number of reasons:</p>
<ul>
<li>I couldn't run the tests without an internet connection</li>
<li>the tests were slow</li>
<li>the tests were unreliable, they would sometimes pass, and other times not</li>
</ul>
<p>Unreliable tests are worse than no tests, so I ripped them out and started again.</p>
<h3>Meet Nock</h3>
<p>The solution to this is <a href="https://github.com/flatiron/nock">Nock</a>, a Node module for mocking HTTP requests. With Nock you can mock a HTTP request and make it always return a specific result. Here's an example:</p>
<p>var nock = require("nock");
var http = require("http");</p>
<p>var api = nock("http://javascriptplayground.com")
.get("/test/")
.reply(200, "Hello World");</p>
<p>http.get("http://javascriptplayground.com/test/", function(resp) {
var str = "";
resp.on("data", function(data) { str += data; });
resp.on("end", function() {
console.log("Got Result: ", str);
});
});</p>
<p>In that code we do two things. First, we mock a request to <code>http://javascriptplayground.com/test/</code> and make it return the string "Hello World" with a 200 status code. Then we use Node's http library to make a request and log it out. We then get "Got Result: Hello World" outputted when we run the above.</p>
<p>What's so great about this is that <code>http.get</code> is none-the-wiser about what just happened. You don't have to change any code to make this work, just mock the request.</p>
<p>There's no requirement to return a string, either. You can return an object, an array, whatever you'd like.</p>
<h3>A Gotcha</h3>
<p>When you mock something using nock, <em>it only works once</em>. Once a URL you've mocked is hit, the mock is then destroyed. To fix this, you can make a specific mocked URL persist:</p>
<p>var api = nock("http://javascriptplayground.com")
.persist()
.get("/test/")
.reply(200, "Hello World");</p>
<p>Now it will last forever, until you call <code>cleanUp</code>, which I'll cover shortly.</p>
<h3>Asserting</h3>
<p>If you need to test thaat a specific URL is called, you can mock that URL and then call <code>isDone()</code> to see if it got called:</p>
<p>var api = nock("http://javascriptplayground.com")
.get("/test/")
.reply(200, "Hello World");</p>
<p>// http.get code here
api.isDone(); // => true</p>
<h3>Clean Up</h3>
<p>When you have lots of tests that do this, it's important to make sure they tidy up after themselves. The best way I've found of doing this is calling <code>nock.cleanAll()</code> after each test. <code>cleanAll()</code> removes all mocks completely. If you were using something like Mocha to do your tests, you might like to do this in the <code>afterEach</code> method.</p>
<h3>Further Reading</h3>
<p>The best place to start is the <a href="https://github.com/flatiron/nock">nock README</a>. There's a huge amount of documentation and a lot more nock can do that I've not covered.</p>
<p>If you'd like to see a real project that uses nock, we use it extensively in the <a href="https://github.com/jackfranklin/pulldown/tree/master/test">Pulldown tests</a>.</p>
<p>If you've ever used an alternative to Nock, or use other tools with it that you think I should mention here, please leave a comment.</p>
Dependency Management with Browserify2013-09-08T00:00:00+00:00http://www.jackfranklin.co.uk/blog/browserify/<p>If you've been a long time reader of this blog you'll know that I'm a fan of RequireJS, and have written about it before. This past weekend I was doing a JS workshop and someone mentioned Browserify to me as a potential alternative. I'd not used it, so thought it was a good excuse to learn more and write up my experience.</p>
<p><a href="https://github.com/substack/node-browserify">Browserify</a> aims to bring Node's <code>require("module")</code> syntax to the browser. Node's syntax itself is taken from the <a href="http://wiki.commonjs.org/wiki/CommonJS">CommonJS Spec</a>, so in essence Browserify enables you to use your CommonJS style modules in the browser. It even allows you to require Node modules in the browser, although we won't look at that today. If you're comfortable requiring and defining modules in Node, Browserify should be easy to pick up. If not, don't worry, I'll explain how.</p>
<p>Defining a module is easy. Here I've created a file called <code>foo.js</code>, which exports just one method:</p>
<p>module.exports = function(x) {
console.log(x);
};</p>
<p>The <code>module.exports</code> here will be picked up by Browserify, and tells it that when we require this file, to return this function.</p>
<p>Now let's write a file that uses our new module. I've called this <code>main.js</code>:</p>
<p>var foo = require("./foo");
foo("Hey");</p>
<p>The first line loads in the file <code>foo.js</code>, with the <code>./</code> at the beginning indicating it's in the same directory as <code>main.js</code>. Note that we can leave off the <code>.js</code> extension. That will return us the function we defined earlier, which we can then call by passing it an argument.</p>
<p>Right now, if we were to include <code>main.js</code> in our HTML, this wouldn't work. This is the downside of Browserify. To use it, we have to first generate a JS file using the Browserify command line tool, which you can install with npm:</p>
<p>npm install -g browserify</p>
<p>Now run this command:</p>
<p>browserify main.js > compiled.js</p>
<p>This instructs Browserify to start at <code>main.js</code>, and bundle up all our files and dependencies. Browserify will see that <code>main.js</code> requires <code>foo.js</code>, and pull that in for us. What we get is one JS file, <code>compiled.js</code>, which has everything we need. You can then add that into your HTML:</p>
<p><script src="http://www.jackfranklin.co.uk/blog/browserify/compiled.js"></script></p>
<p>Load it up in your browser, and you will see "Hey" logged to the screen.</p>
<p>Browserify's command line tool is clever, and is able to deal with just about anything you can throw about it. The <a href="https://github.com/substack/node-browserify">README</a> goes through this in detail.</p>
<p>The benefit over RequireJS, at least for me, is that you don't need to worry about callbacks, or anything similar. In RequireJS, you have to do :</p>
<p>require(["foo"], function(foo) {
// foo is loaded
});</p>
<p>But in Browserify we can just put <code>require</code> calls, and they are made synchronously.</p>
<p>The disadvantage is that you have to run Browsify after every single change. There are ways to automate this, of course, but it's still something you'll have to set up - there are plenty of things like this <a href="https://github.com/jmreidy/grunt-browserify">Grunt plugin</a> that can help with the automation.</p>
<p>I advise you to have a look at Browserify - I admit that I didn't expect to like it or find it worthwhile, but having played with it a bit, I think I'll be using it in the future.</p>
Using Browserify with npm modules2013-11-22T00:00:00+00:00http://www.jackfranklin.co.uk/blog/backbone-browserify/<p>Recently I covered <a href="http://javascriptplayground.com/blog/2013/09/browserify/">Browserify</a> in another post, but did not go into much detail. I discussed how to use Browserify with your own modules, but what I didn't discuss was how Browserify can work with modules that have been published to npm too. In short: you can use Node modules on the client side.</p>
<p>In this tutorial, using a Backbone app as the example, I'll show you how to use Browserify to use npm modules, meaning you can use npm to manage your front end dependencies. This example uses Backbone, but you could use this with anything you like. Backbone just happens to be a good example in this case.</p>
<h3>A Basic Server</h3>
<p>Firstly, let's get a basic server running. To do this I like to use the <a href="http://www.senchalabs.org/connect/">Connect Module</a>. First, install it:</p>
<p>$ npm install --save connect</p>
<p>Then create <code>index.js</code> which looks like this:</p>
<p>var connect = require("connect");</p>
<p>connect.createServer(
connect.static("app")
).listen(8080);</p>
<p>This just creates a very simple server that will serve static assets from the <code>app</code> directory. Perfect for what we need. You can run it like so:</p>
<p>node index.js</p>
<h3>Installing Backbone</h3>
<p>Now we need to install our front-end libraries. Firstly, Backbone:</p>
<p>$ npm install --save backbone</p>
<p>We don't need to install Underscore, because Backbone has that set as a dependency. If we wanted to use Underscore ourselves, outside of Backbone's internal usage of the library, we'd have to install it then.</p>
<h3>Installing jQuery</h3>
<p>Next, jQuery. In the near future, jQuery will be fully published to npm, but right now the version that is on npm is very out of date. Thankfully the new beta version of jQuery 2.1.0 has just been published, so for now we can install the beta from npm:</p>
<p>$ npm install jquery@2.1.0-beta2 --save</p>
<p>In the near future, this will become <code>npm install jquery</code>.</p>
<h3>Browserify</h3>
<p>First, make sure you've got Browserify installed:</p>
<p>$ npm install -g browserify</p>
<p>Browserify works by taking in a file and walking through all the <code>require</code> calls within to bundle all your code up into a file that can be used on the front end. Create <code>app/app.js</code> and put this within:</p>
<p>var Backbone = require("backbone");
var $ = require('jquery/dist/jquery');</p>
<p>Backbone.$ = $;
console.log(Backbone);</p>
<p>The first thing we do is load in Backbone and jQuery. The odd path to jQuery is due to a <a href="http://bugs.jquery.com/ticket/14548">bug in the beta release</a>, which will be fixed soon. Once it is fixed, you'll be able to just use <code>require("jquery")</code>. Because Backbone usually sets its <code>$</code> based on the global environment, we need to set it up ourselves, so we simply set Backbone's <code>$</code> property to be jQuery. Then, to prove it's working, we'll log out Backbone to the console.</p>
<p>Create a basic HTML structure to hold our app (<code>app/index.html</code>):</p>
<p><!DOCTYPE html>
<html>
<head>
<title>Backbone App</title>
<script src="http://www.jackfranklin.co.uk/bundle.js"></script>
</head>
<body>
Hello World
</body>
</html></p>
<p>Notice that we link to <code>bundle.js</code> in the HTML. It's time to generate that. Let's run Browserify:</p>
<p>$ browserify app/app.js -o app/bundle.js</p>
<p>Browserify will create <code>app/bundle.js</code> with all our dependencies concatenated into one file.</p>
<h3>Running the app</h3>
<p>You should now be able to run <code>node index.js</code>, visit <code>localhost:8080</code> and see the Backbone object logged to the console. Congratulations! We've just made a client-side JS app using npm modules and Browserify.</p>
<h3>Creating Modules</h3>
<p>Of course, in a real Backbone app you'll want to split everything out into its own file, and Browserify can handle that just fine. For example, say I have a simple Book model in <code>app/models/book.js</code>:</p>
<p>var Backbone = require("backbone");</p>
<p>var Book = Backbone.Model.extend({
defaults: {
title: "A Book"
}
});</p>
<p>module.exports = Book;</p>
<p>The key here is the last line, which is used by Node (and consequently, Browserify) to know what to return where another file requires this one. That sets up that our <code>Book</code> variable should be returned. We can now use this file in <code>app/app.js</code>:</p>
<p>var Backbone = require("backbone");
var $ = require('jquery/dist/jquery');
Backbone.$ = $;</p>
<p>var Book = require("./models/book");</p>
<p>console.log(new Book().get("title"));</p>
<p>If you rerun Browserify and start up the server once more, you should see the line "A Book" logged to your console.</p>
<h3>Minifying Browserify's Output</h3>
<p>Browserify by default doesn't minify the source code. We can get around this by using Uglify JS to do it. First, ensure you've got that installed:</p>
<p>$ npm install uglify-js -g</p>
<p>Then we can run Browserify, piping the resulting JS through Uglify:</p>
<p>$ browserify app/app.js | uglifyjs > app/bundle.js</p>
<p>This takes Browserify's output and runs it through Uglify before storing that output into <code>bundle.js</code>. During development, you may not want to do this, but of course on a production environment code should always be minified.</p>
<h3>Automating Browserify</h3>
<p>Something you probably noticed is the need to always run Browserify. This is where you might use something like Grunt, or another build mechanism, to watch for file changes and run it for you. I'll be covering this in the future, but for now I'll leave that as an exercise for you.</p>
<h3>The Code</h3>
<p>The code for this tutorial is available in full <a href="https://github.com/javascript-playground/backbone-browserify">on Github</a>.</p>
<p>I hope you enjoyed this tutorial, and any questions please do leave a comment.</p>
JavaScript Getters and Setters2013-12-23T00:00:00+00:00http://www.jackfranklin.co.uk/blog/es5-getters-setters/<p>For the most part, in JavaScript, what you see is what you get. A value's a value; there are no tricks. Sometimes however, you want a value that's based on some other values: someone's full name, for example, is a concatenation of their first and last names. If you have a <code>person</code> object, and you want the users of that object to be able to set the full, first or last name, and see that change immediately reflected in the other values, you'd conventionally build it with functions:</p>
<p>person.setLastName('Smith');
person.setFirstName('Jimmy');
person.getFullName(); // Jimmy Smith</p>
<p>But this is ugly, and requires the users of your object to care that the properties are related; in a more complex example, that might not be as obvious as with names. Luckily, there's a better way, added in ECMAScript 5.</p>
<p>Meet getters and setters.</p>
<h3>How</h3>
<p>Let's make that person object. We want to be able to set the first name, last name or full name, and have it update the other two automagically.</p>
<p>var person = {
firstName: 'Jimmy',
lastName: 'Smith',
get fullName() {
return this.firstName + ' ' + this.lastName;
},
set fullName (name) {
var words = name.toString().split(' ');
this.firstName = words[0] || '';
this.lastName = words[1] || '';
}
}</p>
<p>person.fullName = 'Jack Franklin';
console.log(person.firstName); // Jack
console.log(person.lastName) // Franklin</p>
<p>So what's going on here?</p>
<p>The get and set keywords are important. Following them is the property they relate to (<code>fullName</code>) and a function body that defines the behaviour when the property is accessed (<code>name = person.fullName</code>) or modified (<code>person.fullName = 'Some Name'</code>).</p>
<p>These two keywords define accessor functions: a getter and a setter for the <code>fullName</code> property. When the property is accessed, the return value from the getter is used. When a value is set, the setter is called and passed the value that was set. It's up to you what you do with that value, but what is returned from the setter is the value that was passed in – so you don't need to return anything.</p>
<h3>The official way: <code>Object.defineProperty</code></h3>
<p>Along with the inline method of declaring getters and setters, it can also be done more explicitly via <code>Object.defineProperty</code> (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty">MDN Documentation</a>). This method takes three arguments. The first is the object to add the property to, the second is the name of the property, and the third is an object that describes the property (known as the property's <em>descriptor</em>). Here's an example that replicates the above example:</p>
<p>var person = {
firstName: 'Jimmy',
lastName: 'Smith'
};</p>
<p>Object.defineProperty(person, 'fullName', {
get: function() {
return firstName + ' ' + lastName;
},
set: function(name) {
var words = name.split(' ');
this.firstName = words[0] || '';
this.lastName = words[1] || '';
}
});</p>
<p>The advantage here isn't immediately apparent. Other than being able to add properties after creating the initial object, is there a real benefit?</p>
<p>When you define a property this way, you can do much more than just define a setter or getter. You may also pass following keys:</p>
<ul>
<li><code>configurable</code> (<code>false</code> by default): if this is true, the property's configuration will be modifiable in future.</li>
<li><code>enumerable</code> (<code>false</code> by default): if true, the property will appear when looping over the object (<code>for (var key in obj)</code>).</li>
</ul>
<p>We can also define properties that don't have explicit getters or setters:</p>
<p>Object.defineProperty(person, 'age', {
value: 42
});</p>
<p>This will create <code>person.age</code>, and set it to the value 42. It's important to note that this property isn't writable. Calling <code>person.age = 99</code> will <strong>have no effect</strong>. In this way you can create read-only properties. If a property has a <code>value</code> key set, it <strong>cannot</strong> have a getter or setter. Properties can have values or accessors, not both.</p>
<p>Not only that, but because the <code>enumerable</code> property defaults to <code>false</code>, this property will not appear when we loop over the object's keys.</p>
<p>If we wanted to make a property writable, we would need to set the <code>writable</code> property:</p>
<p>Object.defineProperty(person, 'age', {
value: 42,
writable: true
});</p>
<p>Now, <code>person.age = 99;</code> will have the desired effect.</p>
<h3>Overuse</h3>
<p>Remember: just because a feature exists, it doesn't need to be used all the time. Getters and Setters have their use cases, but don't go over the top, or you'll most likely end up with a design that's confusing for those interacting with your objects. Used carefully, they're very powerful. But with great power comes great responsibility.</p>
<h3>Browser support?</h3>
<p>IE9 and above have full support for <code>Object.defineProperty</code>, along with Safari 5+, Firefox 4+, Chrome 5+ and Opera 12+. If you’re working with Node.js, there's full support. Don't you just love Node?!</p>
<p>This article was co-authored with <a href="http://twitter.com/phuunet">Tom Ashworth</a>. Thanks to Tom for all his help putting this together.</p>
2013 in Review2014-01-01T00:00:00+00:00http://www.jackfranklin.co.uk/blog/2013-in-review/<p>Last year <a href="http://www.jackfranklin.co.uk/blog/2013/01/2012-in-review/">I wrote a post about the JS Playground in 2012</a>, and I thought it would be nice to write a similar one reviewing 2013.</p>
<p>So, I delved into Google Analytics and did some snooping.</p>
<h3>Visitors</h3>
<p>The site had 153,771 visits, from 109,282 unique visitors. This is slightly more than in 2012, which had 104,280 uniques, but then again the site only existed from April 2012, so it's not exactly fair to compare.</p>
<p>There were 221,217 pageviews, which is actually <em>less</em> than the 246,878 achieved in the 9 months of 2012. This reflects the fact that the posting rate has dropped significantly in 2013, for reasons I'll discuss later. 70.25% of the visits were new visits.</p>
<h3>Browsers</h3>
<p>Unsurprisingly given its content, Chrome was the most popular browser by some way. Of the 153,771 visits, Chrome made up a huge 104,169 of them. Second was Firefox with 25,654, then Safari with 13,927. Internet Explorer accounted for just 3,886 visits.</p>
<h3>Blogging</h3>
<p>There were <strong>31</strong> new blog posts in 2013. This is down hugely from <strong>44</strong> in 2012, and is a large reason in my mind that the site hasn't quite continued to grow as I would have liked. I put this down partly to writing a book, although that was finished by February 2013, and down to transitioning at work into doing a lot more Ruby work (I was primarily a Ruby developer), and doing little JavaScript daily. This didn't give me tonnes of ideas for content. In the second half of 2013, my University studies really took over any time I would usually dedicate to JavaScript Playground.</p>
<p>Back in 2012 I said I was hoping for 4 posts per month in 2013, which I fell well short of. I am hoping that 2014 should be a bit calmer, but given that the first 6 months will be spent finishing a Computer Science degree, we'll see.</p>
<h3>Thanks and Goals</h3>
<p>As always, a huge thanks to everyone who shares the articles online, it's hugely appreciated. I've also managed to get some other people to contribute to the post, so thanks to <a href="http://twitter.com/phuu">Tom Ashworth</a> and <a href="http://twitter.com/javorszky">Gabor Javorszky</a> for their contributions. I would like to have more guests writing in 2014 (partly to try to up that blog post rate!), so if you'd like to contribute, please drop me a line.</p>
<p>Thanks also to the duo of <a href="http://twitter.com/benhowdle">Ben Howdle</a> and <a href="http://twitter.com/martinbean">Martin Bean</a>, who were responsible for the lovely new design. Ben did the design, and Martin converted it into HTML and CSS. Many thanks to the both of you :)</p>
<p>As for goals, the main one is to hit 500,000 visits before the JavaScript Playground turns 2 years old, which is on April 8th. The site currently sits on 460k, so I hope that if I can get a few posts out we can hit 500k+.</p>
<h3>Most Popular Posts</h3>
<p>The posts that got the most visits in 2013 were:</p>
<ul>
<li><a href="http://www.jackfranklin.co.uk/blog/2012/07/requirejs-amd-tutorial-introduction/">An introduction to RequireJS</a></li>
<li><a href="http://www.jackfranklin.co.uk/blog/2013/06/refactoring-js/">Refactoring DOM Heavy JS</a></li>
<li><a href="http://www.jackfranklin.co.uk/blog/2012/05/javascript-templating-handlebars-tutorial/">Templating with Handlebars</a></li>
<li><a href="http://www.jackfranklin.co.uk/blog/2012/04/javascript-variable-scope-this/">Scope and this in JS</a></li>
<li><a href="http://www.jackfranklin.co.uk/blog/2013/02/express-backbone-application-part1/">ExpressJS and Backbone: Part 1</a></li>
</ul>
<h3>Topics</h3>
<p>As always, I am always more than welcome to suggestions for topics, a particular library you'd like me to write about, anything that you're struggling with or something you'd like to see clarified. Please get in touch, and here's to 2014! Thanks as always for reading.</p>
An introduction to Gulp2014-02-07T00:00:00+00:00http://www.jackfranklin.co.uk/blog/an-intro-to-gulp/<p><a href="https://github.com/wearefractal/gulp">Gulp</a> has been doing the rounds recently online through Twitter as an alternative to Grunt in the JS build tooling space. Whilst I am a huge fan of Grunt, looking at other options never hurts, so I thought a quick introduction to Gulp might be fun to do.</p>
<p>Gulp works with Node streams. Whereas Gruntfiles can often become very difficult to maintain and large, Gulp tries to avoid too much configuration and keep things simple. The base idea is that you glob for some files, and pipe them through a plugin, changing the output in some way or another. If you need a refresher on streams, the <a href="https://github.com/substack/stream-handbook">Streams handbook</a> is the best place to go.</p>
<p>You install Gulp just like you'd expect, through npm:</p>
<p>$ npm install -g gulp</p>
<p>Much like Grunt looks for a Gruntfile, Gulp will look for a file called <code>Gulpfile.js</code>. You'll also need to install Gulp locally in the project too:</p>
<p>$ npm install --save-dev gulp</p>
<p>Gulp comes with a very minimal set of tools, and everything else comes in the form of plugins. We're going to use the <a href="https://github.com/wearefractal/gulp-jshint">JSHint plugin</a>, so let's install that too:</p>
<p>$ npm install --save-dev gulp-jshint</p>
<p>Now we're ready to write our <code>Gulpfile.js</code>. It starts off by requiring gulp and jshint:</p>
<p>var gulp = require("gulp");
var jshint = require("gulp-jshint");</p>
<p>Whereas with Grunt we have to call <code>initConfig</code>, passing in a huge object full of configuration, in Gulp we define tasks by calling <code>gulp.task</code>. This takes two arguments, the name of a task, and a function which will be run when you call that task. In the case of Grunt, most plugins will define a task for you (For example, the Grunt JSHint plugin defines the <code>grunt jshint</code> task for you), but in gulp plugins just provide methods to hook into. The tasks are all defined by you.</p>
<p>Let's look at an example of a task. Here I've written a "lint" task that will run JSHint against all files in the root of the <code>src/</code> directory:</p>
<p>gulp.task("lint", function() {
gulp.src("./src/*.js")
.pipe(jshint())
.pipe(jshint.reporter("default"));
});</p>
<p>Firstly, <code>gulp.src</code> will return a representation of files that match the glob, that can be piped directly into plugins. Hence, we can take all those files and pipe them directly into <code>jshint()</code>, which is the function made available by the <code>gulp-jshint</code> plugin. This runs each file one by one through JSHint, and we then pipe the result of that through to the JSHint reporter, which is responsible for showing us the results.</p>
<p>We can now run <code>gulp lint</code> to see the result of this:</p>
<p>git/jsplayground/gulp-intro gulp lint
[gulp] Using file /Users/jackfranklin/git/jsplayground/gulp-intro/Gulpfile.js
[gulp] Working directory changed to /Users/jackfranklin/git/jsplayground/gulp-intro
[gulp] Running 'lint'...
[gulp] Finished 'lint' in 0.004 seconds</p>
<p>And if I make a file break a JSHint rule (such as missing a semi-colon), I'll see this:</p>
<p>[gulp] Using file /Users/jackfranklin/git/jsplayground/gulp-intro/Gulpfile.js
[gulp] Working directory changed to /Users/jackfranklin/git/jsplayground/gulp-intro
[gulp] Running 'lint'...
[gulp] Finished 'lint' in 0.006 seconds
./src/one.js: line 1, col 29, Missing semicolon.</p>
<p>1 error</p>
<p>Gulp also has a default task, which will run when you run just <code>gulp</code> on your command line:</p>
<p>gulp.task("default", ["lint"]);</p>
<p>Here I set up the default task to just run our "lint" task.</p>
<p>We can also add a <code>watch</code> task that will automatically run specific tasks when specific files change:</p>
<p>gulp.task('watch', function() {
gulp.watch("src/*.js", ["lint"]);
});</p>
<p>Now you can run <code>gulp watch</code> in your command line, and the lint task will run whenever a JS file within the <code>src</code> directory changes.</p>
<p>Now, the big question here is which is best, Gulp or Grunt? The answer, as always, is that <em>it depends</em>. I think it's good for more than one tool to occupy this space, for a while it was only Grunt, but now for there to be more than one tool to choose between is good. As for which is superior, that very much depends, not only on the project but also on your personal preference. A lot of people have been drawn to Gulp due to the fact that it feels more like just writing JavaScript, whereas Grunt takes the approach of configuration over code, and nearly all code written in a Gruntfile is settings for plugins. If you've not tried either, I advise you to try out both before making a decision, and I'm also excited to see how they develop over time.</p>
Pub Sub with Event Emitter2014-03-05T00:00:00+00:00http://www.jackfranklin.co.uk/blog/event-emitter/<p>I'm a big fan of the Pub Sub (Publish, Subscribe) design pattern, and it's one that I tend to reach for often. I've <a href="http://www.jackfranklin.co.uk/blog/2012/04/a-jquery-pub-sub-implementation/">written previously</a> about it, but that was using jQuery and was frontend specific. Today I'd like to swap and look at using this pattern in Node.js environments.</p>
<p>The idea behind the Pub Sub approach is that objects can publish events, and data associated with those events. Other objects (or the same one) can then subscribe to those events, and be notified when those events occur, and gain access to the data in the event too.</p>
<p>The reason that this is a good thing is because it keeps modules decoupled. Module A can subscribe to the events Module B publishes, and vice versa, without the other one knowing that they have. The less an individual module knows about other modules, the better.</p>
<p>It's nice and straight forward using Node's EventEmitter class, too:</p>
<p>var EventEmitter = require('events').EventEmitter;</p>
<p>var server = new EventEmitter();</p>
<p>server.on('foo', function() {
console.log('got foo');
});</p>
<p>server.emit('foo');</p>
<p>In a system with multiple modules, I've taken the approach of passing in my EventEmitter instance when creating my modules:</p>
<p>var emitter = new EventEmitter();</p>
<p>moduleA.init({
emitter: emitter
});</p>
<p>moduleB.init({
emitter: emitter
});</p>
<p>That way the two can publish and subscribe to the same instance.</p>
<p>We can also create modules that inherit from the EventEmitter. This means that you can call EventEmitter methods like <code>on</code> and <code>emit</code> directly on your own modules:</p>
<p>var EventEmitter = require('events').EventEmitter;
var util = require('util');</p>
<p>var ModuleA = function() {
this.init();
};</p>
<p>util.inherits(ModuleA, EventEmitter);</p>
<p>ModuleA.prototype.init = function() {
this.on('done', function() {
console.log('done');
});
}</p>
<p>ModuleA.prototype.doSomething = function() {
this.emit('done');
};</p>
<p>var foo = new ModuleA();
foo.doSomething(); // => logs 'done'</p>
<p>To do this, we can use Node's <code>util.inherits</code>, which will in this case cause <code>ModuleA</code> to inherit from <code>EventEmitter</code>. Notice we can then call <code>this.on</code> and <code>this.emit</code> from within <code>ModuleA</code>. This is a nice pattern to use if you've got a module that's going to be firing a lot of events. You may chose to create your own EventEmitter object that extends Node's and adds some extra shared functionality relevant to the context of your application. As an additional bonus, you can also use Browserify on this code and run it in the browser, so if you're building a front end app and would like to use EventEmitters, you can.</p>
<p>I highly encourage you to play with EventEmitters and the publish and subscribe pattern; once you're comfortable with it I find it's a great way to keep your code organised, decoupled and extensible with very little effort.</p>
Embracing Command Line Tooling with Backbone Applications2014-03-31T00:00:00+00:00http://www.jackfranklin.co.uk/blog/command-line-backbone-yeoman/<p>In this article I'll take you through how we can use command line tools such as <a href="http://gruntjs.com/">Grunt</a>, <a href="http://bower.io/">Bower</a> and <a href="http://yeoman.io/">Yeoman</a> to speed up our typical development workflow. Today I'll be using the example of a Backbone application, but it's easily applied to any other type of front-end application or web site you might be building.</p>
<p>The use of tools on the command line has really increased over the past two years, particularly when it comes to tools for working on the front-end. We've seen the rise of Node.js, enabling us to run JavaScript on the command line which consequently has seen developers write scripts to automate part of their workflow. You may already use some of these tools to run preprocessors such as <a href="http://sass-lang.com/">Sass</a>, <a href="http://lesscss.org/">LESS</a>, <a href="http://coffeescript.org/">CoffeeScript</a> or another.</p>
<p>Embracing a tool like Yeoman lets you move away from a lot of the manual lifting that comes with setting up and then working on a project. For example, until I used Yeoman I would often create new projects from scratch; creating the folder structure, creating my initial JavaScript files and downloading any resources I needed manually by finding them online. Not only does this take time, but it's something us developers have to do so frequently, that it's silly not to automate this. Yeoman will set this up for you, along with a lot else. Things like upgrading to the latest version of a library, or minifying your JavaScript before deployment, can be done in an instant with a proper tool chain.</p>
<p>Today we'll be using the modern workflow as defined on the <a href="http://yeoman.io/">Yeoman site</a>. This consists of three parts:</p>
<ul>
<li><strong>Yo</strong>. Yo is the tool built by the Yeoman team to quickly generate a project and scaffolding out a new application.</li>
<li><strong>Bower</strong>. Bower is used for managing dependencies, so there's no longer any need to manually download library source files yourself.</li>
<li><strong>Grunt</strong>. Grunt is a JavaScript task runner and contains tasks for running your app's tests, building a minified and ready for deployment version of your app, and much more that we'll see shortly.</li>
</ul>
<h2>Yo</h2>
<p>Before we can look at how Bower and Grunt work, we need to have a sample project to use. Thankfully, this is where Yo is perfect. To install Yo, you'll need to have NodeJS, npm (which usually comes as part of Node) and Git installed. You can install NodeJS through the installer on the <a href="http://nodejs.org/">NodeJS website</a>. This also installs npm, the node package manager, for you. Similarly, you can install Git from the <a href="http://git-scm.com/">Git website</a>.</p>
<h3>Installing Yo</h3>
<p>Once you've got that far, it's time to install Yo. Yo is a node module which we install via npm. It will provide us with a command line program that we can use to scaffold new applications. The first thing to do is load up your terminal and run:</p>
<p>$ npm install --global yo</p>
<p>The <code>--global</code> flag instructs npm to install the module <em>globally</em>. By installing it globally, it will be available to use from everywhere on your machine, so you can run <code>yo</code> regardless of the directory you are currently in. When you run that command you'll get a whole load of output, but once it's done Yo will be installed. To test it, run this command:</p>
<p>$ yo --version
1.1.2</p>
<p>If you see that, you can be confident that Yeoman is installed properly.</p>
<h3>Generators</h3>
<p>Generators are at the heart of Yo - they are what you run run to generate files and folders for projects. Yo doesn't come with any generators by default, but there are a vast number available that are <a href="http://yeoman.io/community-generators.html">listed on the Yeoman site</a>. In this article we're going to use the Backbone generator. The Backbone generator is on <a href="https://github.com/yeoman/generator-backbone">Github</a> and, just like Yo, is installed through npm. You can install it by running this command on your command line:</p>
<p>$ npm install --global generator-backbone</p>
<p>However, before we run the Backbone generator, let's see what happens if you simply run <code>yo</code> on your command line. You'll see Yo give you a prompt, asking you what to do. It will list the generators you have installed, allow you to update your generators, search for a new generator, or get some help. If you ever forget what generators you have available, or want to update your installed generators, the <code>yo</code> command is the easiest way to do this.</p>
<h3>Yo Backbone</h3>
<p>Yo will detect that the generator has been installed and we can now use it. So let's scaffold our new application! Create a new directory to host your application and navigate into it with this command:</p>
<p>$ mkdir my-new-project && cd $_</p>
<p>Then run this command in your terminal:</p>
<p>$ yo backbone library</p>
<p>Yo will then prompt you to ask if you'd like any other functionality. It will ask if you'd like Twitter Bootstrap for Sass, CoffeeScript or RequireJS. To select these options, navigate up and down with your arrow keys and hit 'space' to select the item. For the purposes of this tutorial, I'm going to keep it simple and not use any extras.</p>
<p>Once you're happy, hit 'enter'. You'll see a whole load of output to your terminal as the generator creates the necessary files and folders. It will then run <code>npm install</code> and install Grunt and Bower too, which we will look at in more detail shortly.</p>
<h3>Other Generators</h3>
<p>If you like the look of Yeoman but don't do much work with Backbone, don't worry, there's a huge list of generators out there, including ones for building <a href="https://github.com/yeoman/generator-chromeapp#readme">Chrome Apps</a>, <a href="https://github.com/yeoman/generator-angular#readme">AngularJS</a> and <a href="https://github.com/yeoman/generator-ember#readme">EmberJS</a>, to name just a couple. The <a href="http://yeoman.io/community-generators.html">generators list</a> previously linked is the best resource for finding a generator to fit your needs.</p>
<h3>The Generated Code</h3>
<p>A lot happened there so let's step through it, firstly by looking at the files that were created.</p>
<p>You'll see that the following directories have been created:</p>
<ul>
<li><code>test/</code> - this is where all your tests will go</li>
<li><code>app/</code> - this houses the main code in your application. It contains the Bower dependencies, images, CSS and most importantly a <code>scripts/</code> folder, which is where most of your JavaScript should go.</li>
<li><code>node_modules</code> - when <code>npm</code> is used to install the dependencies listed in <code>package.json</code>, this is where they will be installed to. You can typically ignore this folder - you should never have to directly interact withit yourself.</li>
</ul>
<p>Along with those main directories it's also created some important files, the three most important of which are in the root directory:</p>
<ul>
<li>
<p><code>bower.json</code> - this is where the Bower dependencies are listed. As you can see, by default we have a few dependencies:</p>
<p>{
"name": "app",
"version": "0.0.0",
"dependencies": {
"jquery": "~2.1.0",
"underscore": "~1.6.0",
"backbone": "~1.1.0",
"modernizr": "~2.7.1"
},
"devDependencies": {}
}</p>
</li>
</ul>
<p>When <code>bower install</code> was run earlier, it downloaded jQuery, Underscore, Backbone and Modernizr for us, matching the version numbers specified above. If you find yourself needing another JS library, you should add it here and let Bower do the hard work of downloading it for you.</p>
<ul>
<li>
<p><code>package.json</code> - just like the <code>bower.json</code> file names the JS dependencies, <code>package.json</code> does the same for any Node dependencies. If you take a look, you'll see that there are a lot of Grunt plugins. These are all used with Grunt to create the build process for building and distributing our app.</p>
</li>
<li>
<p><code>Gruntfile.js</code> - there is a lot going on here! Grunt is a JavaScript task runner and its tasks and plugins are configured in the Gruntfile. There is a lot going on here but this sets up our task runner for us. In a moment we will look at the tasks available and what they do.</p>
</li>
</ul>
<p>There's also some other files here that you might not have noticed because they start with a <code>.</code>, and your editor may be hiding them. These are important:</p>
<ul>
<li>
<p><code>.bowerrc</code> - this is used to configure Bower. It contains a JSON object of configuration. The only code in the file sets the directory to which Bower will download the dependencies.</p>
</li>
<li>
<p><code>.editorconfig</code> - this is a file used to configure your editor. It's part of <a href="http://editorconfig.org/">EditorConfig</a>, which is designed to be an easy way for developers to use the same code settings, such as spaces/tabs and size of tabs, in a project. If you have the <a href="http://editorconfig.org/#download">EditorConfig plugin</a> for your editor (Vim, Sublime Text, Notepad++, Emacs, and many more), your editor will update its settings to match the ones in this file.</p>
</li>
<li>
<p><code>.jshintrc</code> - the Yeoman generator adds in <a href="http://www.jshint.com/">JSHint</a>, a code linter and quality checker, so we can check our code. Grunt has a task for JSHint, so we can run <code>grunt jshint</code> to check our code. The settings JSHint will use when checking our code are defined in this file.</p>
</li>
</ul>
<h2>Building an Application</h2>
<p>Let's get to work on the application. It's going to be a simple library app, and the bit we'll build today will show a list of books in our library. First, we can see the application running. In your terminal, run <code>grunt serve</code> and visit <code>http://localhost:9000</code>. Bring up the console too, and you should see something that looks like below:</p>
<p><img src="http://www.jackfranklin.co.uk/img/yobb-image3.png" alt=""></p>
<p>If you see this, Yeoman has set everything up properly and we're all ready to build our application.</p>
<p>Hint: the <code>grunt serve</code> task is set up to automatically refresh when it detects changes, so I suggest leaving it running in another tab, rather than stopping and starting it all the time.</p>
<h3>Generating a Model</h3>
<p>Previously we used the <code>yo backbone</code> command to generate an entire Backbone application, but we can also use it to generate just specific components. Here, we can generate our book model:</p>
<pre><code>yo backbone:model book
</code></pre>
<p>This will create the file <code>app/scripts/models/book.js</code>, which looks like this:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/*global app, Backbone*/</span><br><br>app<span class="token punctuation">.</span>Models <span class="token operator">=</span> app<span class="token punctuation">.</span>Models <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token string">'use strict'</span><span class="token punctuation">;</span><br><br> app<span class="token punctuation">.</span>Models<span class="token punctuation">.</span>BookModel <span class="token operator">=</span> Backbone<span class="token punctuation">.</span>Model<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Notice it attaches onto the <code>app</code> global which is created within the <code>scripts/main.js</code> file. Our <code>app</code> object contains a blank object called <code>Models</code> too, so we add <code>BookModel</code> into that. Grunt takes care of loading this file in too, so we don't have to worry about that.</p>
<h3>Testing a Model</h3>
<p>Yeoman sets up everything you need to get started testing your Backbone entities. Let's write some tests for our new model. Load up <code>test/index.html</code>, and add in <code><script></code> tags to load your application files. While we're here, I'll also add a <code>script</code> tag for our spec file, which we'll create in a minute. Your <code>index.html</code> file should look like so:</p>
<pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">doctype</span> <span class="token name">html</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>utf-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>X-UA-Compatible<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>IE=edge,chrome=1<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Mocha Spec Runner<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lib/mocha/mocha.css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>mocha<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lib/mocha/mocha.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">mocha<span class="token punctuation">.</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token string">'bdd'</span><span class="token punctuation">)</span></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token comment"><!-- assertion framework --></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>lib/chai.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"><span class="token keyword">var</span> expect <span class="token operator">=</span> chai<span class="token punctuation">.</span>expect</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>bower_components/jquery/jquery.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>bower_components/underscore/underscore.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>bower_components/backbone/backbone.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br><br> <span class="token comment"><!-- include source files here... --></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>../scripts/main.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>../scripts/models/book.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br><br> <span class="token comment"><!-- include spec files here... --></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>spec/book_model.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">mocha<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre>
<p>Now let's write our test. Create the file <code>test/spec/book_model.js</code> and add write your test. You'll need to leave some comments at the top to tell JSHint which variables it should expect to be global too. For now, we'll write the typical starting test, and make sure 2 + 2 really is 4.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/*global describe, it, app */</span><br><span class="token string">'use strict'</span><span class="token punctuation">;</span><br><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">'BookModel'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'should pass'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">expect</span><span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now you should be able to run <code>grunt test</code> on your command line and see that you have 1 spec which is passing! Just for completeness' sake, change <code>4</code> to <code>5</code> and run it again. You'll see this time you get a failure reported. Grunt's <code>test</code> command is used in the default Grunt command which Yeoman set up for us, so it's impossible to ever fully build your app if the tests aren't working. I won't explictly talk about testing and what tests to write, but I encourage you to write tests as you develop.</p>
<h3>Building the app</h3>
<p>Let's continue on and define some properties in our model. I'm expecting each book to have a <code>title</code> and an <code>author</code> property, and as such I'd like to define a summary method, which returns a string summarising the book. It's effectively just the title and the author, joined with the word "by":</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/*global app, Backbone*/</span><br><br>app<span class="token punctuation">.</span>Models <span class="token operator">=</span> app<span class="token punctuation">.</span>Models <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token string">'use strict'</span><span class="token punctuation">;</span><br><br> app<span class="token punctuation">.</span>Models<span class="token punctuation">.</span>BookModel <span class="token operator">=</span> Backbone<span class="token punctuation">.</span>Model<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token function-variable function">summary</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'title'</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">' by '</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'author'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>We can write a test too, to make sure the summary method returns what we expect:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">'BookModel'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'should have a summary method'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">var</span> book <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">app<span class="token punctuation">.</span>Models<span class="token punctuation">.</span>BookModel</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'JavaScript: The Good Parts'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token string">'Douglas Crockford'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>book<span class="token punctuation">.</span><span class="token function">summary</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span><span class="token function">equal</span><span class="token punctuation">(</span><br> <span class="token string">'JavaScript: The Good Parts by Douglas Crockford'</span><br> <span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Running <code>grunt test</code> confirms the good news, we're all green! Now we can write a view so we can start to display this information on screen. Just like with our model, we can use Yeoman to generate it for us:</p>
<p>yo backbone:view book</p>
<p>This creates two files. The first is <code>scripts/views/book.js</code>, which contains the boilerplate around our book:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/*global app, Backbone, JST*/</span><br>app<span class="token punctuation">.</span>Views <span class="token operator">=</span> app<span class="token punctuation">.</span>Views <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token string">'use strict'</span><span class="token punctuation">;</span><br> app<span class="token punctuation">.</span>Views<span class="token punctuation">.</span>BookView <span class="token operator">=</span> Backbone<span class="token punctuation">.</span>View<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">template</span><span class="token operator">:</span> <span class="token constant">JST</span><span class="token punctuation">[</span><span class="token string">'app/scripts/templates/book.ejs'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Notice, however, that it links to another file, a template. If you head to <code>scripts/templates/book.ejs</code>, you'll see the following:</p>
<p></p><p>Your content here.</p><p></p>
<p>What's happening here is that Yeoman has made us a template, and it also has configured a Grunt task to manage these templates. It will compile the templates and inline them before your app runs. This is why we can refer to it within our view as <code>JST['app/scripts/templates/book.ejs']</code>. The Grunt task will create a global <code>JST</code> object containing our templates.</p>
<p>Now we'll write a <code>render</code> method for our book view, and then get something appearing in the browser.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/*global app, Backbone, JST*/</span><br><br>app<span class="token punctuation">.</span>Views <span class="token operator">=</span> app<span class="token punctuation">.</span>Views <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token string">'use strict'</span><span class="token punctuation">;</span><br><br> app<span class="token punctuation">.</span>Views<span class="token punctuation">.</span>BookView <span class="token operator">=</span> Backbone<span class="token punctuation">.</span>View<span class="token punctuation">.</span><span class="token function">extend</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">template</span><span class="token operator">:</span> <span class="token constant">JST</span><span class="token punctuation">[</span><span class="token string">'app/scripts/templates/book.ejs'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token function-variable function">render</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">var</span> html <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">template</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>model<span class="token punctuation">.</span>attributes<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>$el<span class="token punctuation">.</span><span class="token function">html</span><span class="token punctuation">(</span>html<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Our <code>render</code> method is very straight forward. It compiles the template by passing in the attributes of the model, then sets the HTML content of the view's element, before returning the view itself. Now we have this set up, we can render it on the page! Head to <code>scripts/main.js</code> and add in some code to get everything going:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token comment">/* global app*/</span><br>window<span class="token punctuation">.</span>app <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">Models</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token literal-property property">Collections</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token literal-property property">Views</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token literal-property property">Routers</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token function-variable function">init</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token string">'use strict'</span><span class="token punctuation">;</span><br> <span class="token keyword">var</span> book <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">this<span class="token punctuation">.</span>Models<span class="token punctuation">.</span>BookModel</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'JavaScript The Good Parts'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">author</span><span class="token operator">:</span> <span class="token string">'Douglas Crockford'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> <span class="token keyword">var</span> view <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">this<span class="token punctuation">.</span>Views<span class="token punctuation">.</span>BookView</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">model</span><span class="token operator">:</span> book <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token function">$</span><span class="token punctuation">(</span><span class="token string">'body'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>view<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>el<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token function">$</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token string">'use strict'</span><span class="token punctuation">;</span><br> app<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Here we just create a new book and a new view instance. We pass that book into the view instance, and then append it to the body.</p>
<p>Now for the moment of truth. Run <code>grunt server</code> again and examine the resulting web page. You should see the text "Your content here" on the left hand side:</p>
<p><img src="http://www.jackfranklin.co.uk/img/yobb-image4.png" alt=""></p>
<p>That's great! It means that the view was rendered, it correctly used the template and grabbed the content. Let's change the template to the following:</p>
<p></p><p><%= title %></p><p></p>
<p>The opening <code><%=</code> and closing <code>%></code> signify to the templating engine that it should replace them with the value of the variable within them. When we compile the template we pass in the model's attributes, one of which is <code>title</code>. If you go back to your browser, you'll see that it does indeed output "JavaScript The Good Parts".</p>
<p>Finally, let's use the <code>summary</code> method we wrote earlier. To do this, we need to make one quick change to the book model. We need to add an <code>initialize</code> method, which is called when we create the model, that will set a <code>summary</code> attribute:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token function-variable function">initialize</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'summary'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">summary</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>We can then update our template to simply be:</p>
<p></p><p><%= summary %></p><p></p>
<p>If you go back to your browser and refresh, you should see the new content.</p>
<h3>Summary</h3>
<p>I hope you've seen in this tutorial the power that Yeoman can provide, and the time saved for rapidly getting a new project up and running. It can take some time to get used to the Yeoman mindset, but once you're comfortable harnessing the power of Yeoman, its generators and the Grunt configuration it creates, you can save yourself a huge amount of time.</p>
<p>If you'd like to go further into the world of Yeoman, the below resources should provide you with all you need.</p>
<ul>
<li><a href="http://yeoman.io/">The Yeoman.io site</a>. This should always be your starting point. There's plenty of documentation, help and links to other resources available.</li>
<li><a href="http://github.com/yeoman">GitHub</a>. If you happen to stumble upon a bug in Yeoman or a generator, the best place to report that is on the relevant GitHub repository. It's also a good place to see if the issue you've found is already known.</li>
<li><a href="https://twitter.com/yeoman">@yeoman</a>. For the latest updates, new generators and other information, the Yeoman Twitter account is definitely worth following. Similarly, there is also the <a href="https://plus.google.com/101063139999404044459">Yeoman community</a> on Google Plus.</li>
</ul>
<p><em>Thanks to Addy Osmani, Sindre Sorhus and Pascal Hartig for their help reviewing and tweaking this article.</em></p>
Real Life ES6 - Arrow Functions2014-04-22T00:00:00+00:00http://www.jackfranklin.co.uk/blog/real-life-es6-arrow-fn/<p>Some of the features soon to be at our fingertips with the growing support for ECMAScript 6 are absolutely fantastic, but often examples shown online are contrived. In this series of blog posts, we'll pick out a few ES6 features and show you some real code that's improved with new features of the language.</p>
<p><em>This post was written in collaboration with <a href="http://twitter.com/adamyeats">Adam Yeats</a>.</em></p>
<h2>Support</h2>
<p>ES6 support is mixed across platforms, so you shouldn't expect to start using this stuff today. Implementations are being added all the time, and I recommend using <a href="http://kangax.github.io/es5-compat-table/es6/">The ES6 Compatability Table</a> to see the current state of affairs.</p>
<h2>Traceur</h2>
<p>All the code examples seen in this post were run through <a href="https://github.com/google/traceur-compiler">Traceur</a>, a tool for compiling ES6 code into ES5 code which has a much better browser support at this time. It allows you to write ES6, compile it and use the result in environments where ES6 features are not implemented. Traceur is installed through npm:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> <span class="token function">install</span> --global traceur</code></pre>
<p>And then used on a source file like so:</p>
<pre class="language-shell"><code class="language-shell">traceur --out build.js --script my_source_file.js</code></pre>
<p>You'll also need to include the Traceur runtime in your HTML. The runtime comes as part of the Node module, and is found in the <code>bin/runtime.js</code> directory.</p>
<h2>Arrow Functions</h2>
<p>Today we'll focus exclusively on Arrow functions. One of the quickest of quick wins, arrow functions allow us to write less and achieve more. Let's take a look at an example of mapping over an array and performing the same task on each element. The code below maps over an array of objects and turns them into an array containing just one particular property from each object:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> users <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">21</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Ben'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">23</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Adam'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">22</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">]</span><span class="token punctuation">;</span><br><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><br> users<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">user</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> user<span class="token punctuation">.</span>age<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token comment">// [21, 23, 22]</span></code></pre>
<p>That's really nice, but also feels a little verbose having to type all that. With the new arrow functions, we can write it like so:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> users <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">21</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Ben'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">23</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Adam'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">22</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">]</span><span class="token punctuation">;</span><br><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>users<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">user</span> <span class="token operator">=></span> user<span class="token punctuation">.</span>age<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token comment">// [21, 23, 22]</span></code></pre>
<p>Notice how much nicer that feels to read, as well as to type? It's much less code to achieve the same thing. We could then go about summing those ages:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> users <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">21</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Ben'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">23</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Adam'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">22</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">]</span><span class="token punctuation">;</span><br><br><span class="token keyword">var</span> ages <span class="token operator">=</span> users<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">user</span> <span class="token operator">=></span> user<span class="token punctuation">.</span>age<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token keyword">var</span> sum <span class="token operator">=</span> ages<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> a <span class="token operator">+</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>sum<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token comment">// 66</span></code></pre>
<p>Because <code>reduce</code> takes two parameters, brackets are required to make it clear that the parameters are for the arrow function, not for the <code>reduce</code> call.</p>
<p>Arrow functions can have multiple statements within, in which case you need to use a block. You also need to use the <code>return</code> keyword, whereas in the one line examples above, the return was implicit.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> users <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">21</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Ben'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">23</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Adam'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">22</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">]</span><span class="token punctuation">;</span><br><br><span class="token keyword">var</span> agesDoubled <span class="token operator">=</span> users<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">user</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">var</span> age <span class="token operator">=</span> user<span class="token punctuation">.</span>age<span class="token punctuation">;</span><br> <span class="token keyword">return</span> age <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>However, once you get to this stage it's a good sign that you probably want to be using regular functions - the benefit of the arrow function is definitely for small, one line methods.</p>
<p>Another handy feature of arrow functions is the lexical binding of <code>this</code> to a function. As you'll probably know already, when you create a new function, the <code>this</code> keyword is set to a value depending on the way a function is called, and the rules as to what <code>this</code> might be defined as <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this">are notoriously convoluted</a>. Let's see how arrow functions might help us out here, using a trivial example of creating an API wrapper that returns a Promise (another great ES6 feature that we'll cover very soon). Consider the following example:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token constant">API</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>uri <span class="token operator">=</span> <span class="token string">'http://www.my-hipster-api.io/'</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><br><br><span class="token comment">// let's pretend this method gets all documents at</span><br><span class="token comment">// a specific RESTful resource...</span><br><span class="token class-name">API</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">get</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resource</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// this doesn't work</span><br> http<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>uri <span class="token operator">+</span> resource<span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">resolve</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">var</span> api <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">API</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br><span class="token comment">// by calling this method, we should be making a request to</span><br><span class="token comment">// http://www.my-hipster-api.io/nuggets</span><br>api<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'nuggets'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>So what's wrong here? Well, aside from not being the best example of Promise usage in the world (it's generally considered a bit of an anti-pattern to wrap a callback function in this way), <code>this.uri</code> is <code>undefined</code> so when we come to call our <code>http.get()</code> method that we're wrapping, we can't properly form the URL we need. Why would this be? Well, when we call <code>new Promise()</code>, we're calling a constructor of another object, which creates a new lexical <code>this</code> in turn. Put simply, <code>this.uri</code> is not in scope.</p>
<p>Today, we can work around this in a few ways. We could have written something like this:</p>
<pre class="language-js"><code class="language-js"><span class="token class-name">API</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">get</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resource</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">var</span> self <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token comment">// a-ha! we'll assign to a local var</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// this works!</span><br> http<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>uri <span class="token operator">+</span> resource<span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">resolve</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>...and, lo and behold, it works! By creating a variable that points to <code>this</code>, we can access it from any of our inner functions. In fact, if we were to use Traceur to transpile our ES6 into ES5 compatible code, it actually outputs something very similar to the above pattern. But we shouldn't have to do this, right? Surely there must be a way for us to define <code>this</code> ourselves? If we're working inside an environment where we have ES5 features (IE9 or above), we could use <code>.bind()</code>, which is a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">method on the <code>Function</code> prototype</a> that allows us to "bind" (funnily enough) a value a function's lexical <code>this</code>.</p>
<pre class="language-js"><code class="language-js"><span class="token class-name">API</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">get</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resource</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><br> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// this works!</span><br> http<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>uri <span class="token operator">+</span> resource<span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">resolve</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">bind</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><br> <span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>This works, but could be a little tidier. If we decide to nest a few callbacks within each other, and they all need access to the outer function's <code>this</code> keyword, then we have to affix <code>.bind()</code> to every nested function. There are also <a href="http://stackoverflow.com/questions/18895305/will-function-prototype-bind-always-be-slow">performance implications in using <code>.bind()</code></a>, but likely (hopefully) these will be fixed in due time.</p>
<p>Enter arrow functions! In ES6, the same function above could be defined like this:</p>
<pre class="language-js"><code class="language-js"><span class="token class-name">API</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">get</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resource</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> http<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>uri <span class="token operator">+</span> resource<span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">resolve</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>It certainly looks a bit more concise, but what's the arrow doing? Well, it actually binds the context of the Promise's <code>this</code> to the context of the function that contains it, so <code>this.uri</code> resolves to the value we assigned in the constructor. This avoids having to use <code>bind</code> or the dreaded <code>var self = this</code> trick to keep a reference to the desired scope.</p>
Using ES6 Modules Today2014-06-08T00:00:00+00:00http://www.jackfranklin.co.uk/blog/s6-modules-today/<p>Continuing with the theme of playing with new features of ES6, today we're going to look at how we can use the new ES6 module syntax today, using Square's <a href="https://github.com/square/es6-module-transpiler">ES6 Module Transpiler</a>. <strong>Remember, this syntax is not set in stone yet and could change</strong>, but that's no reason to not have a play with the new syntax today.</p>
<p>The transpiler takes the JavaScript and transpiles it into either the CommonJS format (which is what NodeJS uses) or AMD (using RequireJS). This means you write your code using the ES6 syntax, and then run it with CommonJS, RequireJS, or similar.</p>
<p>It's easier to show with an example. Let's make <code>adder.js</code>, which has a multiplier function:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">multiplier</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">y</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> x <span class="token operator">*</span> y<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">export</span> <span class="token punctuation">{</span> multiplier <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>The <code>multiplier</code> function takes an argument and returns a function that will multiply its argument by the initial argument. So <code>multiplier(2)(2)</code> will return <code>4</code>, and <code>multiplier(2)(4)</code> gives us <code>8</code>.</p>
<p>Notice the last line of the function:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">export</span> <span class="token punctuation">{</span> multiplier <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>This uses the new ES6 syntax to export the <code>multiplier</code> function from this file.</p>
<p>Now let's write a second file, <code>app.js</code>, and use our <code>adder</code> module:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> multiplier <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./adder'</span><span class="token punctuation">;</span><br><br><span class="token keyword">var</span> timesTwo <span class="token operator">=</span> <span class="token function">multiplier</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">timesTwo</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Again, pay particular attention to the top line:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> multiplier <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./adder'</span><span class="token punctuation">;</span></code></pre>
<p>This is how we import exported objects from modules using the ES6 syntax.</p>
<p>To run this code, first we need to compile it. Firstly, install the ES6 transpiler:</p>
<pre><code>npm install -g es6-module-transpiler
</code></pre>
<p>Now we can transpile it. For this example, as we want to run the resulting code through Node, we will tell the transpiler to use the CommonJS syntax:</p>
<pre><code>compile-modules app.js adder.js --to compiled --type cjs
</code></pre>
<p>This instructs the transpiler to transpile <code>app.js</code> and <code>adder.js</code> into the <code>compiled</code> directory.</p>
<p>Let's take a look at <code>compiled/adder.js</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token string">'use strict'</span><span class="token punctuation">;</span><br><span class="token keyword">var</span> <span class="token function-variable function">multiplier</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">y</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> x <span class="token operator">*</span> y<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br>exports<span class="token punctuation">.</span>multiplier <span class="token operator">=</span> multiplier<span class="token punctuation">;</span></code></pre>
<p>Notice how it has updated the exports code to the CommonJS style.</p>
<p>Now let's check <code>compiled/app.js</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token string">'use strict'</span><span class="token punctuation">;</span><br><span class="token keyword">var</span> multiplier <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'./adder'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>multiplier<span class="token punctuation">;</span><br><br><span class="token keyword">var</span> timesTwo <span class="token operator">=</span> <span class="token function">multiplier</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">timesTwo</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Once again, the import has been changed into a standard CommonJS <code>require</code> call.</p>
<p>Now we can run <code>node compiled/app.js</code> and get <code>8</code> as our output. It worked!</p>
<p>Let's see what the output would be if we chose AMD support instead. Try running:</p>
<pre><code>compile-modules app.js adder.js --to compiled --type amd
</code></pre>
<p>Now, <code>compiled/adder.js</code> looks like so:</p>
<pre class="language-js"><code class="language-js"><span class="token function">define</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'exports'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">__exports__</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token string">'use strict'</span><span class="token punctuation">;</span><br> <span class="token keyword">var</span> <span class="token function-variable function">multiplier</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">y</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> x <span class="token operator">*</span> y<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">;</span><br><br> __exports__<span class="token punctuation">.</span>multiplier <span class="token operator">=</span> multiplier<span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>And <code>compiled/app.js</code> looks like this:</p>
<pre class="language-js"><code class="language-js"><span class="token function">define</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'./adder'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">__dependency1__</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token string">'use strict'</span><span class="token punctuation">;</span><br> <span class="token keyword">var</span> multiplier <span class="token operator">=</span> __dependency1__<span class="token punctuation">.</span>multiplier<span class="token punctuation">;</span><br><br> <span class="token keyword">var</span> timesTwo <span class="token operator">=</span> <span class="token function">multiplier</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">timesTwo</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>If we were to setup RequireJS and require <code>app.js</code>, this would work just fine in a browser.</p>
<p>If you're not a fan of running the transpiler directly, you can find both <a href="https://github.com/joefiorini/grunt-es6-module-transpiler">Grunt</a> and <a href="https://github.com/ryanseddon/gulp-es6-module-transpiler">Gulp</a> plugins. I highly recommend having a play and exploring the module syntax - we've not covered it all in this post and seeing as it will be standard fairly soon, it makes sense to be familiar with it.</p>
Unit testing ExpressJS route functions2014-07-09T00:00:00+00:00http://www.jackfranklin.co.uk/blog/testing-express-routes/<p>I've recently been working on an application which has two distinct parts: an Angular front-end, and an API powered by ExpressJS. Something I was keen to do from the beginning was to look at how I could test these API endpoints - not through an integration test, where we fire up the app and make sure hitting an endpoint gives back a response, but through isolated unit tests, where we test the inputs and outputs of the endpoint functions.</p>
<p>A typical route function in my application looks something like:</p>
<pre class="language-js"><code class="language-js">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">my</span><span class="token operator">:</span> <span class="token string">'response'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The steps to being able to test this are:</p>
<ul>
<li>Define each route's function elsewhere, and then pass it into an <code>app.get</code> call later. This lets us have access to the route function isolated from Express.</li>
<li>Because all of my responses call <code>res.json</code>, in our tests we will need to fake the method. We can pass in a method called <code>json</code>, so the code will work, but in there we can add our own implementation that will test the JSON response is what we expect.</li>
</ul>
<p>I like to split my routes up into different files, one for each grouping of endpoints. For example, the below code contains routes that will be used under the <code>/users</code> endpoint. This is a good example of how I like to define my routes - completely independent of the Express framework.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> userRoutes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token string-property property">'/'</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">'get'</span><span class="token punctuation">,</span><br> <span class="token function-variable function">fn</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> res<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">foo</span><span class="token operator">:</span> <span class="token string">'hello world'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br>module<span class="token punctuation">.</span>exports <span class="token operator">=</span> userRoutes<span class="token punctuation">;</span></code></pre>
<p>To test this, all we need to do is call the <code>fn</code> method of the <code>/</code> object within <code>userRoutes</code>. We can pass in fake arguments to this function when we call it, and provide our own fake <code>json</code> method which we can then make assertions on. By doing this we avoid having to load Express, or anything else. This is a big deal - as your app gets larger, loading it will take longer. Being able to test your components in isolation, away from your framework, helps keep test suites quick, which is vital to a good development workflow.</p>
<p>Let's see this in action. Here I'm using Mocha for <code>describe</code> and <code>it</code>, and I'm using the <a href="https://github.com/LearnBoost/expect.js/">expect.js</a> library for my expectations.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> expect <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'expect.js'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token keyword">var</span> userRoutes <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'../../routes/users'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">'user routes'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'returns hello world'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> userRoutes<span class="token punctuation">[</span><span class="token string">'/'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">fn</span><span class="token punctuation">(</span><br> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span><br> <span class="token function-variable function">json</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span><span class="token function">eql</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">foo</span><span class="token operator">:</span> <span class="token string">'hello world'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The key bit of that is this section:</p>
<pre class="language-js"><code class="language-js">userRoutes<span class="token punctuation">[</span><span class="token string">'/'</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">fn</span><span class="token punctuation">(</span><br> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span><br> <span class="token function-variable function">json</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">.</span>to<span class="token punctuation">.</span><span class="token function">eql</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">foo</span><span class="token operator">:</span> <span class="token string">'hello world'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Here we call the function, passing in an empty object for the request (if we needed to we could easily pass in fake data, if the function used the request object at all) and a fake <code>json</code> method as part of the resonse object. The function under test calls this <code>json</code> method, passing in the data we want to return. Hence, within the body of our fake <code>json</code> method, we can define the expectation we're after, and check that the data the function returns matches what we expect.</p>
<p>If you take just one thing away from this post, isolate your code from your framework as much as possible. Yes, it means a little more work to wire things up, but the speed gains from doing so really pay off, particularly as your app grows.</p>
<p>PS - recently I've created a JSPlayground Twitter account, so if you'd like to be aware when new posts get released, the best way to do so is to <a href="http://twitter.com/jsplayground_">follow the site on Twitter</a>.</p>
The Refactoring Tales book2014-07-20T00:00:00+00:00http://www.jackfranklin.co.uk/blog/refactoring-tales/<p>Something that I've been researching into a lot recently is refactoring - one of the most popular posts on this blog was <a href="http://javascriptplayground.com/blog/2013/06/refactoring-js/">the one on refactoring</a>. I really have enjoyed getting stuck into the principles of large systems development, and how to keep code maintainable over time and as it grows.</p>
<p>I've been collecting some examples of this from tutorials I've written and real life code for a while, and have been writing them up into case studies. Today I finished my fourth write up, and I've decided to parcel them up into a small book, which I've called "The Refactoring Tales".</p>
<p>"The Refactoring Tales" is a collection of case studies (currently four examples, but more being written) that look at specific code examples and ways they can be improved, going through the stages of refactorings and the reasoning behind them. I also discuss some principles like coupling and single responsibility, along with many more.</p>
<h2>Free Online</h2>
<p>You can read the book in its entirety <a href="http://www.jackfranklin.co.uk/the-refactoring-tales">online here</a>, and even check out the source <a href="https://github.com/jackfranklin/the-refactoring-tales">on GitHub</a> if it interests you. Please remember that the book is <strong>not yet finished</strong>, this is somewhat of a beta release. There is more content to come, along with refinements to the existing content too.</p>
<p>If you'd like to support the JavaScript Playground, you can purchase a digital download version for $15, which gives you access to the PDF, EPUB and MOBI versions of the book. Buying the book helps me dedicate more time to this site, but also ensures you full access to the current <strong>and all future</strong> editions of the book.</p>
<p><a class="buynow" href="https://transactions.sendowl.com/products/64361/A591CEA4/add_to_cart" rel="nofollow">Buy Kindle, iPad and PDF versions for $15</a></p>
<p>If you'd like to try before you buy, you can read it online, and the content in the downloadable versions is identical to the content online.</p>
<p>For more information, please <a href="http://www.jackfranklin.co.uk/the-refactoring-tales">see the book's page on this site</a>, and if you have any questions please tweet <a href="http://twitter.com/jsplayground_">@jsplayground_</a> or myself (<a href="http://twitter.com/jack_franklin">@jack_franklin</a>) and I'll get back to you.</p>
An introduction to ES6 classes.2014-07-22T00:00:00+00:00http://www.jackfranklin.co.uk/blog/introduction-to-es6-classes-tutorial/<h2>Support</h2>
<p>ES6 support varies across environments and platforms, implementations get updated all the time and it's important to also note that the spec is in draft, so everything below has the potential to change. I recommend using <a href="http://kangax.github.io/es5-compat-table/es6/">The ES6 Compatability Table</a> to see the current state of affairs.</p>
<h2>Traceur</h2>
<p>All the code examples seen in this post were run through <a href="https://github.com/google/traceur-compiler">Traceur</a>, a tool for compiling ES6 code into ES5 code which has much better browser support. The beauty of Traceur is that it allows you to write ES6, compile it and use the result in environments where ES6 features are not implemented. Traceur is installed through npm:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> <span class="token function">install</span> --global traceur</code></pre>
<p>And then used on a source file like so:</p>
<pre class="language-shell"><code class="language-shell">traceur --out build.js --script my_source_file.js</code></pre>
<p>You'll also need to include the Traceur runtime in your HTML. The runtime comes as part of the Node module, and is found in the <code>bin</code> directory, called <code>traceur-runtime.js</code> directory. If you'd like to see an example of this, you can <a href="https://github.com/javascript-playground/es6-classes">check out the sample repo on GitHub</a>.</p>
<h2>Classes</h2>
<p>ES6 classes are syntactical sugar over the Objects and prototypes that we're used to working with. They simply offer a much nicer, cleaner and clearer syntax for creating these objects and dealing with inheritance.</p>
<p>To show this in action we're going to build our own small (and very simplified) framework for building web applications to demonstrate using classes. We're going to have two classes, one to represent a view, and another to represent a model. Here's the <code>View</code> class:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">View</span> <span class="token punctuation">{</span><br> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>model <span class="token operator">=</span> options<span class="token punctuation">.</span>model<span class="token punctuation">;</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>template <span class="token operator">=</span> options<span class="token punctuation">.</span>template<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> _<span class="token punctuation">.</span><span class="token function">template</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>template<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>model<span class="token punctuation">.</span><span class="token function">toObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Notice how we still set properties through <code>this.property</code>, but defining methods on the class is done very differently to how you might be used to. Not a <code>function</code> keyword in sight! Functions are defined by putting their name, followed by any arguments within brackets, and then a set of braces. That's it. Our view class is very simple, and provides just a simple <code>render()</code> method, which takes the template (I'm using Underscore here for templating) and the model object and then returns the compiled template.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">Model</span> <span class="token punctuation">{</span><br> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">properties</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>properties <span class="token operator">=</span> properties<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">toObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>properties<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Our <code>Model</code> class is equally as simple. It stores all the properties and provides the <code>toObject</code> method that gives access to the properties.</p>
<p>We can now use these to output some HTML:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> jack <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Model</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'jack'</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br><span class="token keyword">var</span> view <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">View</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">model</span><span class="token operator">:</span> jack<span class="token punctuation">,</span><br> <span class="token literal-property property">template</span><span class="token operator">:</span> <span class="token string">'Hello, <%= name %>'</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>view<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The classes are instantiated just as they are in the ES5 and below world, with the <code>new</code> keyword used. The <code>constructor</code> function is called automatically when an instance of the class is created.</p>
<p>If you run the above code (remembering to run it through Traceur), you'll see <code>"Hello, jack"</code> logged to the console.</p>
<h2>Extending</h2>
<p>Say we have some views where we actually just want the <code>render</code> method not to return the compiled template, but to simply just <code>console.log</code> the resulting rendered HTML. (This is a contrived example, but stick with me!). We might call this view <code>LogView</code>, and we can implement it by extending our regular <code>View</code> class. I'll explain the call to <code>super.render()</code> shortly.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">LogView</span> <span class="token keyword">extends</span> <span class="token class-name">View</span> <span class="token punctuation">{</span><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">var</span> compiled <span class="token operator">=</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>compiled<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Using the <code>extends</code> keyword to extend a class is a great example of where the simplicity of the class syntax shines. Extending <code>View</code> means that <code>LogView</code> inherits everything that <code>View</code> has. If we were to just have:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">LogView</span> <span class="token keyword">extends</span> <span class="token class-name">View</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code></pre>
<p>Then <code>LogView</code> functionality would be effectively identical to <code>View</code>.</p>
<p>Instead though, we override the <code>render</code> method:</p>
<pre class="language-js"><code class="language-js"><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">var</span> compiled <span class="token operator">=</span> <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>compiled<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre>
<p>We first call <code>super.render()</code>. This calls the parent class' <code>render()</code> method, and returns the result. Using <code>super</code>, you can access methods and properties available on the parent class. This means that the <code>render</code> method on the <code>View</code> class is first called, and the result is stored in the <code>compiled</code> variable. We then simply log out the result.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> jack <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Model</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'jack'</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br><span class="token keyword">var</span> view <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LogView</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">model</span><span class="token operator">:</span> jack<span class="token punctuation">,</span><br> <span class="token literal-property property">template</span><span class="token operator">:</span> <span class="token string">'Hello, <%= name %>'</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br>view<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>If you rerun Traceur and refresh the browser, you'll still see <code>Hello, jack</code> logged to the console, but this time the only <code>console.log</code> call was from within the <code>LogView</code> class.</p>
<h2>Conclusion</h2>
<p>I hope that serves as a nice introduction to ES6 classes. Just because they exist, it doesn't mean that you should immediately seek to change every object in your system to classes, but they certainly have some great use cases.</p>
<p>The code I used in this post is <a href="https://github.com/javascript-playground/es6-classes">on GitHub</a>, so feel free to check it out and have a play around.</p>
<p><em>Thanks to <a href="http://twitter.com/toddmotto">@toddmotto</a> for his help reviewing a draft of this piece.</em></p>
Upcoming JavaScript Workshops2014-09-02T00:00:00+00:00http://www.jackfranklin.co.uk/blog/workshops/<p>Coming up in October and November I'm doing two different workshops; the first in Bristol and the second in London.</p>
<h2>Web Dev Conf</h2>
<p>On the <strong>9th of October</strong> I'm doing a workshop on building web apps with NodeJS and Express in Bristol. It runs for about three hours in the afternoon and tickets cost £50. You can <a href="http://2014.webdevconf.com/workshops/#jackfranklin">buy them through the WDC site</a>.</p>
<h2>White October Events</h2>
<p>On the <strong>4th of November</strong>, I'm doing a full day workshop on JS Tooling with Grunt and Gulp. White October are the folks behind jQuery UK, one of the best conferences I've attended before and I'm sure they are going to do an awesome job with the workshops. Tickets for this full day workshop at Imperial College, London cost £270 + VAT and can be bought <a href="http://www.whiteoctoberevents.co.uk/event/javascript-workshops/introduction-to-js-tooling/">on the White October site</a>.</p>
<p>If you have any questions about the workshops please get in touch, and I hope to see you at one of them!</p>
Slides from "An introduction to ES6"2014-10-07T00:00:00+00:00http://www.jackfranklin.co.uk/blog/es6-introduction/<p>I had the pleasure last weekend of speaking at <a href="http://epic.frontendlondon.co.uk/">Epic FEL</a>, a single day, single track conference in the heart of London, run by <a href="http://madebymany.com/">Made by Many</a>. They did an absolutely fantastic job and if you are ever in London, I recommend their monthly <a href="http://www.frontendlondon.co.uk/">Front End London meetup</a> too.</p>
<p>I spoke on introducing ES6, a topic that I've been writing and speaking about more and more recently. I'm really excited by the evolution of the language and some of the new features. You can find my slides below along with the video.</p>
<script async="" class="speakerdeck-embed" data-id="3cffd6802e29013233bc1ac45923d988" data-ratio="1.33333333333333" src="http://speakerdeck.com/assets/embed.js"></script>
<iframe width="560" height="315" src="http://www.youtube.com/embed/mPq5S27qWW8" frameborder="0" allowfullscreen=""></iframe>
<p>Below I have included a list of resources that I used when putting the talk together which may be useful if you'd like to read more on any of the features in particular:</p>
<ul>
<li><a href="http://kangax.github.io/compat-table/es6/">ES6 Compat Table</a></li>
<li><a href="https://github.com/lukehoban/es6features">ES6 Features Repo</a></li>
<li><a href="https://chrome.google.com/webstore/detail/es6-repl/alploljligeomonipppgaahpkenfnfkn">ES6 REPL Chrome Addon</a></li>
</ul>
<h4>Arrow Functions</h4>
<ul>
<li><a href="http://javascriptplayground.com/blog/2014/04/real-life-es6-arrow-fn/">http://javascriptplayground.com/blog/2014/04/real-life-es6-arrow-fn/</a></li>
</ul>
<h4>Classes</h4>
<ul>
<li><a href="http://javascriptplayground.com/blog/2014/07/introduction-to-es6-classes-tutorial/">http://javascriptplayground.com/blog/2014/07/introduction-to-es6-classes-tutorial/</a></li>
</ul>
<h4>Object Literals</h4>
<ul>
<li><a href="http://maximilianhoffmann.com/posts/object-based-javascript-in-es6">http://maximilianhoffmann.com/posts/object-based-javascript-in-es6</a></li>
</ul>
<h4>Generators</h4>
<ul>
<li><a href="http://www.slideshare.net/domenicdenicola/es6-the-awesome-parts">http://www.slideshare.net/domenicdenicola/es6-the-awesome-parts</a></li>
<li><a href="http://pag.forbeslindesay.co.uk/#/">http://pag.forbeslindesay.co.uk/#/</a></li>
<li><a href="http://jlongster.com/A-Study-on-Solving-Callbacks-with-JavaScript-Generators">http://jlongster.com/A-Study-on-Solving-Callbacks-with-JavaScript-Generators</a></li>
</ul>
<h4>Template Strings</h4>
<ul>
<li><a href="http://tc39wiki.calculist.org/es6/template-strings/">http://tc39wiki.calculist.org/es6/template-strings/</a></li>
</ul>
<h4>Destructuring</h4>
<ul>
<li><a href="http://ariya.ofilabs.com/2013/02/es6-and-destructuring-assignment.html">http://ariya.ofilabs.com/2013/02/es6-and-destructuring-assignment.html</a></li>
</ul>
<h4>Function Arguments</h4>
<ul>
<li><a href="http://globaldev.co.uk/2013/10/es6-part-4/">http://globaldev.co.uk/2013/10/es6-part-4/</a></li>
</ul>
<h4>Modules</h4>
<ul>
<li><a href="http://guybedford.com/practical-workflows-for-es6-modules">http://guybedford.com/practical-workflows-for-es6-modules</a></li>
<li><a href="https://github.com/esnext/es6-module-transpiler">https://github.com/esnext/es6-module-transpiler</a></li>
<li><a href="http://www.2ality.com/2014/09/es6-modules-final.html">http://www.2ality.com/2014/09/es6-modules-final.html</a></li>
</ul>
<h4>Promises</h4>
<ul>
<li><a href="http://www.2ality.com/2014/09/es6-promises-foundations.html">http://www.2ality.com/2014/09/es6-promises-foundations.html</a></li>
</ul>
<h4>ES6 Today</h4>
<ul>
<li><a href="https://github.com/google/traceur-compiler">https://github.com/google/traceur-compiler</a></li>
<li><a href="http://www.2ality.com/2014/08/es6-today.html">http://www.2ality.com/2014/08/es6-today.html</a></li>
</ul>
<h4>Block Scope</h4>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let</a></li>
</ul>
<h4>Other Talks</h4>
<ul>
<li><a href="http://es6isnigh.com/">http://es6isnigh.com/</a></li>
<li><a href="https://speakerdeck.com/anguscroll/es6-uncensored">https://speakerdeck.com/anguscroll/es6-uncensored</a></li>
</ul>
ES6 Destructuring2014-10-16T00:00:00+00:00http://www.jackfranklin.co.uk/blog/es6-destructuring/<p>ES6 comes both with huge new features like generators or classes, but also packs in a lot of smaller features that are going to make a big difference to how your JavaScript looks. Today I want to explore some of the new destructuring abilities ES6 adds, and how it can reduce the amount of code we have to write.</p>
<p>## Traceur
All the code examples seen in this post were run through <a href="https://github.com/google/traceur-compiler">Traceur</a>, a tool for compiling ES6 code into ES5 code which has much better browser support. The beauty of Traceur is that it allows you to write ES6, compile it and use the result in environments where ES6 features are not implemented. Traceur is installed through npm:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> <span class="token function">install</span> --global traceur</code></pre>
<p>And then used on a source file like so:</p>
<pre class="language-shell"><code class="language-shell">traceur --out build.js --script my_source_file.js</code></pre>
<p>You'll also need to include the Traceur runtime in your HTML. The runtime comes as part of the Node module, and is found in the <code>bin</code> directory, called <code>traceur-runtime.js</code> directory. If you'd like to see an example of this, you can <a href="https://github.com/javascript-playground/es6-classes">check out this example repo on GitHub</a>, which has Traceur set up.</p>
<h2>Destructuring</h2>
<p>The most common destructuring example is to pull values out of an array:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token punctuation">[</span>a<span class="token punctuation">,</span> b<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br>a<span class="token punctuation">;</span> <span class="token comment">//=> 1</span><br>b<span class="token punctuation">;</span> <span class="token comment">//=> 2</span></code></pre>
<p>You can also miss out parts of the array too:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token punctuation">[</span>a<span class="token punctuation">,</span> <span class="token punctuation">,</span> b<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br>a<span class="token punctuation">;</span> <span class="token comment">//=> 1</span><br>b<span class="token punctuation">;</span> <span class="token comment">//=> 3</span></code></pre>
<p>This lends itself well to splitting strings:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> fullName <span class="token operator">=</span> <span class="token string">'Jack Franklin'</span><span class="token punctuation">;</span><br><span class="token keyword">var</span> <span class="token punctuation">[</span>first<span class="token punctuation">,</span> last<span class="token punctuation">]</span> <span class="token operator">=</span> fullName<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">' '</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br>first<span class="token punctuation">;</span> <span class="token comment">//=> 'Jack'</span><br>last<span class="token punctuation">;</span> <span class="token comment">//=> 'Franklin'</span></code></pre>
<p>What is perhaps more useful is that we can perform this same type of destructuring on objects:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token punctuation">{</span> name<span class="token punctuation">,</span> age <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">22</span> <span class="token punctuation">}</span><span class="token punctuation">;</span><br>name<span class="token punctuation">;</span> <span class="token comment">//=> 'Jack'</span><br>age<span class="token punctuation">;</span> <span class="token comment">//=> '22'</span></code></pre>
<p>This is useful if you have a function that returns an object, and you want to get certain parts of the object only:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">about</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">22</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">var</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">about</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br>name<span class="token punctuation">;</span> <span class="token comment">//=> 'Jack'</span></code></pre>
<h2>Functions that take objects</h2>
<p>The above functionality is really useful, and will certainly come in handy, but we can go one step further.</p>
<p>Because we can take in an object as the only argument to a function, we can destructure against that object.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">someFunc</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> name <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token function">someFunc</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token comment">// 'Jack'</span></code></pre>
<p>The above function takes in an object and destructures it, declaring that whatever is passed in as the <code>name</code> property of the object will then be available within the function as the <code>name</code> variable. Suddenly we can rewrite this type of code:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">someFunc</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">opts</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">var</span> name <span class="token operator">=</span> opts<span class="token punctuation">.</span>name<span class="token punctuation">;</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token function">someFunc</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Into what we had earlier:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">someFunc</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> name <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token function">someFunc</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This may take some getting used to in terms of reading the code, but it makes it much clearer what's going on. You can see exactly what the object expects.</p>
<p>We can even go one step further though. In ES6 we also have some nice sugar for declaring properties on objects where the value is already defined in a variable by the same name. What this means is that we can take this code block:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> name <span class="token operator">=</span> <span class="token string">'Jack'</span><span class="token punctuation">;</span><br><span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> name <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>And rewrite it as:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> name <span class="token operator">=</span> <span class="token string">'Jack'</span><span class="token punctuation">;</span><br><span class="token keyword">return</span> <span class="token punctuation">{</span> name <span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>When you have an object where the value of the property matches a variable of the same name, you can shorten it and only refer to it once, thus avoiding duplicating the same word twice. Taking that into account, our function from earlier:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">someFunc</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> name <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token function">someFunc</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Becomes even more concise:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">someFunc</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> name <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token function">someFunc</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2>Conclusion</h2>
<p>I hope I've shown you how ES6 destructuring can really clean up your code. It might take a while for you to get used to, and the syntax can look a little weird if you're not used to it, but once you're adjusted I think it really makes code but nicer to read and work with. It also makes code much more self documenting and clear in its intentions, in my opinion.</p>
JavaScript Modules and Dependencies with jspm2014-11-10T00:00:00+00:00http://www.jackfranklin.co.uk/blog/js-modules-jspm-systemjs/<p><a href="http://jspm.io/">jspm</a> is a package manager for JavaScript applications that sits on top of the <a href="https://github.com/systemjs/systemjs">SystemJS</a>. Both were written and are maintained by <a href="http://twitter.com/guybedford">Guy Bedford</a>. SystemJS builds on top of the <a href="https://github.com/ModuleLoader/es6-module-loader">es6-module-loader</a> and adds the capability to load in modules that are defined using a variety of syntaxes:</p>
<ul>
<li>CommonJS (for example, NodeJS modules)</li>
<li>AMD (the spec that RequireJS follows)</li>
<li>ES6 modules (using the <a href="https://github.com/ModuleLoader/es6-module-loader">ES6 module loader</a> and <a href="https://github.com/google/traceur-compiler">Traceur</a>.</li>
<li>Modules that export a global variable are also supported via a shim config.</li>
</ul>
<p>I think that ES6 modules are absolutely fantastic, and at <a href="http://www.gocardless.com/">GoCardless</a>, we've structured a large JS heavy application using SystemJS, allowing us to manage our application's modules entirely through ES6. Using jspm is the next logical step up from SystemJS. It manages our dependencies, lets us install third party ones and comes with tooling to build applications into one file for production.</p>
<p>Today we will set up a very simple project using jspm, and in further posts we will explore more of its features.</p>
<h2>Why not npm?</h2>
<p>jspm is a package manager in the same ilk as npm, but with a key difference: it puts the browser loader first. This means it offers a seamless workflow for installing and using libraries in the browser with very little effort from the developer. The ability to load in modules that have been defined in a number of different syntaxes means it can offer the greatest support for front end libraries and more often than not with jspm, any module you wish to use will just work, with none or very little configuration required.</p>
<h2>Installing jspm</h2>
<p>jspm should be installed as a global tool through npm:</p>
<pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> <span class="token function">install</span> --global jspm</code></pre>
<p>Let's create a new project. Create a new directory and run <code>jspm install</code>. The CLI will ask you a set of questions about your project, which you should answer. If the default answer is fine, you can just hit enter to continue onto the next question. Once the prompts have been answered, jspm is going to perform the following tasks:</p>
<ul>
<li>create a <code>config.js</code>, which contains the configuration for your modules. We will look at this in more depth shortly.</li>
<li>create a <code>package.json</code> file for your project. jspm stores your project's dependencies in here, under the <code>jspm</code> key by default.</li>
<li>Download some libraries that jspm needs: SystemJS, the es6-module-loader, Traceur and the Traceur runtime.</li>
</ul>
<h2>Running the App</h2>
<p>To get this running we now need to create an HTML file, and load in a couple of scripts. Create <code>index.html</code>:</p>
<pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>jspm_packages/system.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>config.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"><br> System<span class="token punctuation">.</span><span class="token function">import</span><span class="token punctuation">(</span><span class="token string">'./app'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre>
<p>We first load in the SystemJS source, and then the <code>config.js</code>, which jspm created for us. Then we can use <code>System.import</code>, the proposed browser loader API for dynamically loading ES6 modules, polyfilled by the es6-module-loader, to import the file <code>app.js</code>:</p>
<pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'hello world'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>If you run the app locally (I recommend the npm module <a href="https://www.npmjs.org/package/serve">serve</a> for this), you should be able to visit <code>index.html</code> and see 'hello world' logged.</p>
<h2>Installing Dependencies</h2>
<p>So far, jspm hasn't added much to the party. Most of the work to achieve what we have has been done by SystemJS. Let's say that your application requires jQuery for some piece of functionality. jspm will let us install modules from either GitHub or from npm, and jQuery is available on both, so we're good there. There is also a small <a href="https://github.com/jspm/registry/blob/master/registry.json">registry</a> maintained for popular dependencies, and jQuery is one of them. Because of this, we can just run <code>jspm install jquery</code>, and jspm will know how to resolve "jquery" into the right files to download. Run that now and see what happens:</p>
<pre class="language-shell"><code class="language-shell"><span class="token operator">></span> jspm <span class="token function">install</span> jquery<br><br> Updating registry cache<span class="token punctuation">..</span>.<br><br> Looking up github:components/jquery<br>ok Installed jquery as github:components/jquery@^2.1.1 <span class="token punctuation">(</span><span class="token number">2.1</span>.1<span class="token punctuation">)</span><br><br>ok Install complete</code></pre>
<p>jspm has searched its registry for "jquery", and found that it is mapped to "github:components/jquery", and has gone and installed jQuery from that repository. Additionally, it has added jQuery to the <code>package.json</code>, which means if you were to clone the repository and run <code>jspm install</code>, jQuery will be downloaded and installed for you.</p>
<p>If we take a look at <code>config.js</code>, we can see jspm has modified it:</p>
<pre class="language-js"><code class="language-js">System<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">paths</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">'*'</span><span class="token operator">:</span> <span class="token string">'*.js'</span><span class="token punctuation">,</span><br> <span class="token string-property property">'github:*'</span><span class="token operator">:</span> <span class="token string">'jspm_packages/github/*.js'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br>System<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">map</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">jquery</span><span class="token operator">:</span> <span class="token string">'github:components/jquery@^2.1.1'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br>System<span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">versions</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">'github:components/jquery'</span><span class="token operator">:</span> <span class="token string">'2.1.1'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>These paths and mappings tell SystemJS how to resolve a request for a module. Most of the time jspm will generate this for you and you won't have to edit it too much, however sometimes it can be useful to map a longer package name to a smaller one, as jspm has done with jQuery. You can actually generate these mappings automatically when you install a module:</p>
<pre class="language-shell"><code class="language-shell">jspm <span class="token function">install</span> <span class="token assign-left variable">j</span><span class="token operator">=</span>jquery</code></pre>
<p>Would install jQuery and set up a path so in your code you could load it in as <code>j</code>. I don't recommend using such short names, but in some cases it can be useful to save on typing.</p>
<p>Now we can use jQuery in our application. Head back to <code>app.js</code> and load it in:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> $ <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'jquery'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>$<span class="token punctuation">.</span>fn<span class="token punctuation">.</span>jquery<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Remember, SystemJS can deal with modules defined and loaded in using either AMD, CommonJS or ES6 modules. Here I've chosen to use the CommonJS style just to show that it works. If you now run this in your browser, you will see <code>2.1.1</code> logged to the console - <code>$.fn.jquery</code> returns the current version of jQuery running.</p>
<h2>Installing a dependency from npm</h2>
<p>Let's now look at installing something from npm, namely <a href="http://lodash.com/">LoDash</a>. Typically, if a dependency you need is on npm, you should install it from there rather than on GitHub. We can install it with jspm like so:</p>
<pre><code>> jspm install lodash=npm:lodash
Updating registry cache...
Looking up npm:lodash
Looking up github:jspm/nodelibs
Looking up npm:Base64
Looking up npm:base64-js
Looking up npm:ieee754
Looking up npm:inherits
Looking up npm:pbkdf2-compat
Looking up npm:ripemd160
Looking up npm:sha.js
ok Installed github:jspm/nodelibs@0.0.5 (0.0.5)
ok Installed lodash as npm:lodash@^2.4.1 (2.4.1)
ok Install complete
</code></pre>
<p>Don't worry that a lot of extra files got downloaded - these are dependencies that jspm has in order to install npm modules correctly. Notice how we install LoDash with the command <code>jspm install lodash=npm:lodash</code>. This gets jspm to install LoDash from npm, but then set up a mapping so we can require it as <code>lodash</code>, rather than the slightly more verbose <code>npm:lodash</code>, which gets tiring to type very quickly.</p>
<p>Now head into <code>app.js</code> and load in LoDash.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> $ <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'jquery'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token keyword">var</span> _ <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'lodash'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>$<span class="token punctuation">.</span>fn<span class="token punctuation">.</span>jquery<span class="token punctuation">)</span><span class="token punctuation">;</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>_<span class="token punctuation">.</span><span class="token constant">VERSION</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>You will see the current version of LoDash (<code>2.4.1</code> at time of writing) in the console.</p>
<h2>ES6 Syntax</h2>
<p>To round off this tutorial, let's swap to using the ES6 module syntax:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> $ <span class="token keyword">from</span> <span class="token string">'jquery'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> _ <span class="token keyword">from</span> <span class="token string">'lodash'</span><span class="token punctuation">;</span><br><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>$<span class="token punctuation">.</span>fn<span class="token punctuation">.</span>jquery<span class="token punctuation">)</span><span class="token punctuation">;</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>_<span class="token punctuation">.</span><span class="token constant">VERSION</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>If you load your browser again, you'll see that everything still works. If you need a primer on the ES6 module syntax, I covered it <a href="http://javascriptplayground.com/blog/2014/06/es6-modules-today/">previously on the site</a>.</p>
<h2>Advantages over RequireJS or Browserify</h2>
<p>This approach of jspm + SystemJS offers a number of advantages over other solutions such as Require or Browserify. With RequireJS, you have to install it through a tool such as Bower, but then manage the mappings and namings of the modules manually. With jspm, you very rarely have to edit the configuration, it is just done for you. In the cases where jspm isn't able to do it all for you, you can manually override and add to the jspm registry, fixing the problem for you and for others.</p>
<p>The primary benefit over Browserify is that you do not need any form of build tool or task running all the time every time you change a file. Because it's all run and compiled (in development, anyway), in the browser, there's much less tooling or set up required. Compilation through Traceur for your ES6 files is all done for you.</p>
<h2>Conclusion</h2>
<p>The combination of jspm and SystemJS is a powerful one, in particular when combined with the new module syntax in ES6. In future tutorials we will look more at structuring applications and defining your own modules and use jspm to bundle our application into one file that can be used in production.</p>
<p>Thank you to <a href="http://twitter.com/guybedford">Guy Bedford</a>, <a href="http://twitter.com/oliverjash">Oliver Ash</a> and <a href="http://twitter.com/theefer">Sebastien Cevey</a> for their time spent reviewing this blog post.</p>
Embracing Promises in JavaScript2015-02-08T00:00:00+00:00http://www.jackfranklin.co.uk/blog/promises/<p>In this post we will look at how we can embrace promises to lead to much nicer code when working asynchronously with JavaScript. This post is not a full, in-depth exploration of Promises. For that, <a href="http://www.html5rocks.com/en/tutorials/es6/promises/">Jake Archibald's post on HTML5 Rocks</a> has you covered. I highly recommend reading it.</p>
<p>Throughout this post I will be working using the <a href="https://github.com/jakearchibald/es6-promise">es6-promise library</a>, a polyfill for the native Promise implementation that will exist in ECMAScript 6. All my code examples will be run through Node.js, but they should behave identically when run in a browser environment. Whenever in the code you see <code>Promise</code>, this will be using the above polyfill, but if you're reading this in a world where promises are widely implemented in browsers, you should still find everything here works exactly the same.</p>
<h2>Dealing with Errors</h2>
<p>The first subject to tackle is that of error handling with promises. This was something that a lot of people have asked about and something that trips a lot of people up, understandably. Take a look at the below code. When I run this, what do you expect to be logged?</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">someAsyncThing</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// this will throw, x does not exist</span><br> <span class="token function">resolve</span><span class="token punctuation">(</span>x <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token function">someAsyncThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'everything is great'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>You might expect an error to be thrown, because <code>x</code> does not exist. That's what would happen if you wrote that code outside of a promise. However, running this code gives you absolutely nothing. Nothing is logged to the console, and no errors are thrown. Within a promise, any error that is thrown is swallowed up and treated as the promise rejecting. This means we have to catch the error to see it:</p>
<pre class="language-js"><code class="language-js"><span class="token function">someAsyncThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'everything is great'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'oh no'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now, running this gives:</p>
<pre class="language-js"><code class="language-js">oh no <span class="token punctuation">[</span>ReferenceError<span class="token operator">:</span> x is not defined<span class="token punctuation">]</span></code></pre>
<p>You also need to be comfortable with how errors are caught in a chain of promises. Take the below example:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">someAsyncThing</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// this will throw, x does not exist</span><br> <span class="token function">resolve</span><span class="token punctuation">(</span>x <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">var</span> <span class="token function-variable function">someOtherAsyncThing</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">reject</span><span class="token punctuation">(</span><span class="token string">'something went wrong'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token function">someAsyncThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">someOtherAsyncThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'oh no'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Here we will still get <code>oh no [ReferenceError: x is not defined]</code>, because <code>someAsyncThing</code> rejected. However, if <code>someAsyncThing</code> resolves successfully, we'll still see the error when <code>someOtherAsyncThing</code> rejects:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">someAsyncThing</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">var</span> x <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span><br> <span class="token function">resolve</span><span class="token punctuation">(</span>x <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">var</span> <span class="token function-variable function">someOtherAsyncThing</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">reject</span><span class="token punctuation">(</span><span class="token string">'something went wrong'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token function">someAsyncThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">someOtherAsyncThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'oh no'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now we get <code>oh no something went wrong</code>. When a promise rejects, the first <code>catch</code> in the chain following that is called.</p>
<p>Another important point is that there's nothing special about <code>catch</code>. It's just a method to register a handler for when a promise rejects. It doesn't stop further execution:</p>
<pre class="language-js"><code class="language-js"><span class="token function">someAsyncThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">someOtherAsyncThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'oh no'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'carry on'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Given the above code, once something rejects, <code>carry on</code> will then be logged to the screen. Of course, if the code within the <code>catch</code> throws an error, that is not the case:</p>
<pre class="language-js"><code class="language-js"><span class="token function">someAsyncThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">someOtherAsyncThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'oh no'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token comment">// y is not a thing!</span><br> y <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'carry on'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now the catch callback is executed, but <code>carry on</code> is not, because the catch callback threw an error. Notice again that there is no record of the error, it is not logged, nor is anything thrown visibly. If you were to add another <code>catch</code> onto the end, that <code>catch</code> function would run, because when a callback function throws, the next <code>catch</code> in the chain is called.</p>
<h2>Chaining and Passing around Promises</h2>
<p>This part is inspired by some work I did recently to add CSV exporting to our client-side application. In that case it was using the <code>$q</code> framework within an AngularJS application, but I have replicated it here so we can use it as an example.</p>
<p>The steps to export a CSV (the CSV itself is built in the browser using <a href="https://github.com/eligrey/filesaver.js">FileSaver</a>) are as follows:</p>
<ol>
<li>Fetch the data from the API that will make up the CSV (this could mean multiple API requests)</li>
<li>Pass that data into an object which does some editing of the data to make it CSV ready.</li>
<li>Write the data to a CSV.</li>
<li>Show the user a message confirming their CSV has been successfully created, or an error.</li>
</ol>
<p>We won't go into the underlying specifics of how the code works, but I wanted to look at a high level how we used Promises to build a robust solution that handles errors too. In a complex operation like this, errors could easily occur at any stage of the process (the API might be down, or the code parsing the data might throw an error, or the CSV might not save properly) and we found that with promises we could handle this really nicely, using a sensible combination of <code>then</code> and <code>catch</code>.</p>
<p>As you'll see we also end up chaining promises heavily. The chaining of promises is something that really makes them shine in my opinion, but it does take some getting used to - the way they work can be a little odd at first. Jake Archibald (yup, him again!) puts this best:</p>
<blockquote>
<p>When you return something from a "then" callback, it's a bit magic. If you return a value, the next "then" is called with that value. However, if you return something promise-like, the next "then" waits on it, and is only called when that promise settles (succeeds/fails)</p>
</blockquote>
<p>Again, for a real in-depth look at promises, I can't recommend <a href="http://www.html5rocks.com/en/tutorials/es6/promises/">this blog post</a> highly enough.</p>
<p>Let's start with a really simple function that just returns some data. In a real application this would be a http call of some sort. In our case after 50ms, this promise will resolve with an array of users that we want to export to CSV:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">fetchData</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">users</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">22</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Tom'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">21</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Isaac'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">21</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Iain'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">20</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Next, there's the function that prepares this data for the CSV. In this case all it actually does is immediately resolve with the data its given, but in a real application it would do more work:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">prepareDataForCsv</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// imagine this did something with the data</span><br> <span class="token function">resolve</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>There's something quite important to note here: in this example (and in the real app), none of the work <code>prepareDataForCsv</code> does is async. There's no need for this to be wrapped in a promise. But when a function exists as part of a larger chain, I've found it really beneficial to wrap it in a promise, because it means all your error handling can be done through promises. Else, you have to deal with error handling through promises in one area, but through good old <code>try {} catch</code> in another.</p>
<p>Finally, we have the function for writing to a CSV too:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">writeToCsv</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// write to CSV</span><br> <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>And now we can put them all together:</p>
<pre class="language-js"><code class="language-js"><span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">prepareDataForCsv</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">writeToCsv</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'your csv has been saved'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>That's pretty succinct, and I think reads really well. It's clear what's going on and the order in which things happen. We can also tidy it up further though. If you have a function that just takes one argument, you can pass that directly to <code>then</code> rather than calling it from a callback function:</p>
<pre class="language-js"><code class="language-js"><span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>prepareDataForCsv<span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>writeToCsv<span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'your csv has been saved'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Bearing in mind how complex the underlying code is (at least, in the real application), the high level API reads really nicely. This is something I've come to really appreciate with promises, once you get used to writing them and working with them, you can end up with some really nice looking code that's easy to follow.</p>
<p>However, right now we don't have any error handling, but we can add it all with one extra piece of code:</p>
<pre class="language-js"><code class="language-js"><span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>prepareDataForCsv<span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>writeToCsv<span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'your csv has been saved'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'something went wrong'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Because of how the chaining of promises and errors work, as discussed earlier, it means that just one <code>catch</code> at the end of the chain is guaranteed to catch any errors thrown along the way. This makes error handling really straight forward.</p>
<p>To demonstrate this, I'll change <code>prepareDataForCsv</code> so it rejects:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">prepareDataForCsv</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// imagine this did something with the data</span><br> <span class="token function">reject</span><span class="token punctuation">(</span><span class="token string">'data invalid'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>And now running the code logs the error. That's pretty awesome - <code>prepareDataForCsv</code> is right in the middle of our promise chain but we didn't have to do any extra work or trickery to deal with the error. Plus, the <code>catch</code> will not only catch errors that we trigger by making the promise reject, but also any that are thrown unexpectedly. This means even if a really unexpected edge case triggers a JS exception, the user will still have their error handled as expected.</p>
<p>Another approach that we've found to be very powerful is changing functions that expect some data to instead take a promise that will resolve to some data. Let's take <code>prepareDataForCsv</code> as the example:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">prepareDataForCsv</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">dataPromise</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">dataPromise</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> data<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>We've found this to be quite a nice pattern for tidying up code and keeping it more generic - it's often easier in an application where most of the work is async to pass promises around rather than waiting for them to resolve and pass the data.</p>
<p>With the above change, the new code looks like so:</p>
<pre class="language-js"><code class="language-js"><span class="token function">prepareDataForCsv</span><span class="token punctuation">(</span>fetchData<span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>writeToCsv<span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'your csv has been saved'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'something went wrong'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The beauty of this is that the error handling hasn't changed. <code>fetchData</code> could reject in some form, and the error will still be dealt with in the last catch. Once it clicks in your mind, you'll find promises really nice to work with and even nicer to handle errors with.</p>
<h2>Recursion in Promises</h2>
<p>One of the problems we had to deal with was that sometimes to fetch the data from our API, you might have to make multiple requests. This is because we paginate all our API requests, so if you need to get more data than can fit in one response, you need to make multiple. Thankfully our API tells you if there is more data to fetch, and in this section I'll explain how we used recursion in conjunction with promises to load all this data.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> count <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><br><br><span class="token keyword">var</span> <span class="token function-variable function">http</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>count <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> count<span class="token operator">++</span><span class="token punctuation">;</span><br> <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">more</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">user</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'jack'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">22</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">more</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token literal-property property">user</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'isaac'</span><span class="token punctuation">,</span> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token number">21</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Firstly, we have <code>http</code>, which will serve as the fake HTTP calls to our API. (<code>Promise.resolve</code> just creates a promise that immediately resolves with whatever you give it). The first time I make a request, it's going to respond with a user but also the <code>more</code> flag set to true, which indicates there is more data to fetch (this isn't how the real life API responds, but it will do for the purposes of this post). The second time the request is made, it responds with a user but with the <code>more</code> flag set to <code>false</code>. Therefore to fetch all the data needed, we need to make two API calls. Let's write a function <code>fetchData</code> that can deal with this:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> <span class="token function-variable function">fetchData</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">var</span> <span class="token function-variable function">goFetch</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">users</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">http</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> users<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>data<span class="token punctuation">.</span>more<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">goFetch</span><span class="token punctuation">(</span>users<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> users<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">;</span><br><br> <span class="token keyword">return</span> <span class="token function">goFetch</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p><code>fetchData</code> itself does very little except define and then call another function, <code>goFetch</code>. <code>goFetch</code> takes an array of users in (the initial call to <code>goFetch</code> passes an empty array), and then calls <code>http()</code>, which resolves with some data. The new user that is returned is pushed onto the array of users, and then the function looks at the <code>data.more</code> field. If it's true, it calls itself again, passing in the new array of users. If it's false, and there is no more data to get, it just returns the array of users. The most important thing here and the reason this works is that at every stage something is <code>return</code>ed. <code>fetchData</code> returns <code>goFetch</code>, which either returns itself or an array of users. It's the fact that everything returns itself that allows this recursive promise chain to be built up.</p>
<h2>Conclusion</h2>
<p>Promises are not going anywhere, and are going to become the standard approach for dealing with large amounts of asynchronous operations. However, I've found them to generally offer a lot of benefits when working on complex sequences of operations where some are sync, and others async. If you've not tried them yet I'd really recommend it on your next project.</p>
Writing Command Line Tools with Node2015-03-01T00:00:00+00:00http://www.jackfranklin.co.uk/blog/node-command-line-tool/<p>Back in August 2012 I wrote a post on <a href="http://www.jackfranklin.co.uk/blog/2012/08/writing-a-command-line-node-tool/">building a command line tool in NodeJS</a>. That post is now over two years old and plenty has changed, hence I thought it worth writing a new post building the same tool, showing how I'd do it now.</p>
<p>We're going to build the same tool, one that's used to search a directory for files that match a given string. This is not a very useful plugin, but will let me demonstrate the basics of building a CLI in NodeJS.</p>
<h2>Creating the Project</h2>
<p>First things first: let's create a new project. Create a directory for the project, enter it and run <code>npm init</code> to initialise the new project with a <code>package.json</code> file. Answer the prompts if you wish, or just hit enter a bunch of times to get a template <code>package.json</code> file that you can fill out at your own leisure.</p>
<h2>Editing package.json</h2>
<p>The <code>package.json</code> file is used by npm, Node's package manager, to know about your project, its dependencies and how it works. We need to make a couple of edits to it.</p>
<ul>
<li>remove the <code>main</code> entry: this is only used for modules that will be used through the module system (e.g. <code>var _ = require('underscore');</code>).</li>
<li>add <code>preferGlobal</code> and set it to true, which means if someone installs this module through npm and doesn't use the <code>--global</code> option, they will be warned that the module is designed to be installed globally.</li>
<li>add the <code>bin</code> object, which maps commands to files. This means when this module is installed, npm will set up the <code>filesearch</code> executable to execute <code>index.js</code>.</li>
</ul>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span><br> <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"filesearch"</span><span class="token punctuation">,</span><br> <span class="token string-property property">"version"</span><span class="token operator">:</span> <span class="token string">"1.0.0"</span><span class="token punctuation">,</span><br> <span class="token string-property property">"description"</span><span class="token operator">:</span> <span class="token string">"searches for files"</span><span class="token punctuation">,</span><br> <span class="token string-property property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">"test"</span><span class="token operator">:</span> <span class="token string">"echo \"Error: no test specified\" && exit 1"</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token string-property property">"author"</span><span class="token operator">:</span> <span class="token string">"JavaScript Playground"</span><span class="token punctuation">,</span><br> <span class="token string-property property">"license"</span><span class="token operator">:</span> <span class="token string">"ISC"</span><span class="token punctuation">,</span><br> <span class="token string-property property">"preferGlobal"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br> <span class="token string-property property">"bin"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">"filesearch"</span><span class="token operator">:</span> <span class="token string">"index.js"</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<h2>Creating the Script</h2>
<p>Create <code>index.js</code> and add this to the top:</p>
<pre class="language-js"><code class="language-js"><span class="token hashbang comment">#! /usr/bin/env node</span><br><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'This is the filesearch script.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2>Installing the Script</h2>
<p>Now in your project you can run <code>npm link</code> to install the script on your system. This creates a symlink to your project so that you can run the project whilst working on it, with no need to keep reinstalling it over and over again.</p>
<p>Once <code>npm link</code> has run, you should be able to run <code>filesearch</code> on the command line and see the string printed back:</p>
<pre><code>~/git/filesearch > filesearch
This is the filesearch script.
</code></pre>
<h2>Processing Arguments</h2>
<p><code>filesearch</code> is going to be called with one argument, which is going to be the pattern to search through files for. We need to get at that argument. When a Node.js script is executed on the command line, the <code>process.argv</code> array contains all the arguments used to call that script.</p>
<p>Change <code>index.js</code> so it instead logs out this array:</p>
<pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span>argv<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>And now run the script again, this time with an argument:</p>
<pre><code>~/git/filesearch > filesearch foo
[ 'node', '/Users/jackfranklin/.nvm/v0.10.32/bin/filesearch', 'foo']
</code></pre>
<p>The first argument is always <code>node</code>, and the second is the path to the file that has been executed. Any following arguments are ones that the user has called your script with, and those are the ones we care about. We can use <code>slice</code> to get an array of just the arguments we need:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> userArgs <span class="token operator">=</span> process<span class="token punctuation">.</span>argv<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br><span class="token keyword">var</span> searchPattern <span class="token operator">=</span> userArgs<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre>
<p>Now we have the one argument we need.</p>
<h2>Searching for Files</h2>
<p>We'll hand the actual searching of the files over to a combination of two Unix commands, <code>ls</code> and <code>grep</code>. We can use <code>ls -a</code> to list all files in the current directory, and pass them to <code>grep</code> to search for our actual pattern.</p>
<p>To run a command in the system we can use the <code>exec</code> method of the <code>child_process</code> module - a module that comes with Node and doesn't need to be separately installed - to execute the right command, passing in the search pattern the user passed in through to <code>grep</code>:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> exec <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'child_process'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>exec<span class="token punctuation">;</span><br><span class="token keyword">var</span> child <span class="token operator">=</span> <span class="token function">exec</span><span class="token punctuation">(</span><span class="token string">'ls -a | grep '</span> <span class="token operator">+</span> searchPattern<span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><br> <span class="token parameter">err<span class="token punctuation">,</span><br> stdout<span class="token punctuation">,</span><br> stderr</span><br><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>stdout<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>And that is that! We can now run <code>filesearch</code> and see the results:</p>
<pre><code>~/git/filesearch > filesearch package
package.json
</code></pre>
<h2>Next Steps</h2>
<p>If this was a real module that I was working on publishing there's a couple of things I'd do before hitting <code>npm publish</code>:</p>
<ul>
<li>ensure a good, well written README</li>
<li>decide on an initial version number (I tend to go for <code>0.1.0</code>) and then follow <a href="http://semver.org/">semver</a></li>
</ul>
<p>When your module is ready, simply run <code>npm publish</code> to push it onto npm. If you've not registered on npm, you can run <code>npm adduser</code> and follow the prompts to set up and authenticate yourself.</p>
<p>Once published, users can then install your module using <code>npm install --global filesearch</code>.</p>
Predictions on JavaScript in the next 12 months2015-05-30T00:00:00+00:00http://www.jackfranklin.co.uk/blog/the-state-of-javascript/<p>Recently I gave a talk called "The State of JavaScript" at the inaugural meetup
of the <a href="https://twitter.com/london_js">London JS Community</a>. You
can find the slides for this below:</p>
<script async="" class="speakerdeck-embed" data-id="d15b87038dbc468ba94e31d0fef5118f" data-ratio="1.33333333333333" src="http://speakerdeck.com/assets/embed.js"></script>
<p>In this post I'd like to focus specifically on the end of the talk, when I
discuss my predictions for what we'll see happen in the next 12 months or so
with JavaScript. Be warned this is quite opinionated, and I don't expect people to
agree with everything I say! You should read this as "what Jack thinks" rather
than "what will happen". Find me <a href="http://twitter.com/Jack_Franklin">on Twitter</a>
if you'd like to discuss things further.</p>
<h1>Predictions</h1>
<p>I made 8 predictions on what I think we'll see in the next 12 months, and most
of these are influenced by the three core goals of ECMAScript 2015 (formerly
ES6), which hopes
to provide a better language for:</p>
<ul>
<li>complex applications</li>
<li>libraries</li>
<li>code generation (languages that compile to JS)</li>
</ul>
<p>These are by no means the most bold of predictions, more so thoughts on what I
think will happen in the next year or so.</p>
<h3>1: Fewer people will write JavaScript without a compilation step</h3>
<p>We're seeing this trend already, libraries like
<a href="http://www.typescriptlang.org/">TypeScript</a> and <a href="http://babeljs.io/">Babel</a>
have built on what <a href="http://coffeescript.org/">CoffeeScript</a> showed people
wanted, by building on top of JavaScript and compiling down to JavaScript.
CoffeeScript deserves a lot of credit here: it was the first project that really
did this and showed that people were willing to trade a slightly more complex
workflow for additional functionality.</p>
<p>Babel is slightly different in that all the new functionality it provides is
part of ECMAScript 2015 or beyond, so everything it implements in theory
will eventually be in the browser. Going forward, Babel, TypeScript and
<a href="https://github.com/clojure/clojurescript">ClojureScript</a> will probably be the
three I'd back to become even more popular.</p>
<p>As an aside, I'm really interested to see what becomes of types in JavaScript.
TypeScript has proven that there's not only a demand but a strong argument for
having types in the language, and libraries like
<a href="https://facebook.github.io/immutable-js/">ImmutableJS</a> have become very popular
too.</p>
<h3>2: Smaller libraries (and the composing of) will be preferred over large frameworks</h3>
<p>Alongside the larger, fully featured frameworks of Angular, Ember and others,
there's a myriad of smaller libraries that focus on doing one thing, and doing
it really well. You could even argue that ReactJS is a good example of this; as
a library it provides just the view layer for an application, and nothing more.
Given that npm provides a (relatively) easy way to install and manage all these
libraries, I think it will become more common for developers to construct their
own stacks of small libraries that can be swapped in and out, over using a large
framework where you're stuck with what it provides.</p>
<h3>3: Focus on libraries that do one thing and one thing well</h3>
<p>Related very much to the previous point, I think that there will be an even
bigger focus on the development and release of libraries that exist to solve one
problem, and do it very well. This feels like a natural process as an ecosystem
matures, and we figure out the best solutions to new problems (such as client
side "MVC" approaches). Why write an entire framework when you could write a
small library to plug the one problem you need to fix, and then couple it with
some other libraries that provide the rest of the functionality you need.</p>
<h3>4: Large, fully-featured frameworks will remain rightly popular</h3>
<p>The previous two thoughts might make you think that I'm predicting the demise of
Angular, Ember and so on. This is definitely not the case. There will always be
(and quite rightly so) a use case and need for these larger frameworks.</p>
<h3>5: The use of compilers (Babel etc.) will be abstracted for us by generic build tools</h3>
<p>More and more developers will use compilers like Babel, but they won't do it by
directly installing and running Babel. Most will use it through some other
system like <a href="http://jspm.io/">jspm</a> or <a href="http://webpack.github.io/">webpack</a>,
generic tools that abstract away the compiling step and provide all the
functionality you could ever need.</p>
<h3>6: Running the same JavaScript client and server side will be common</h3>
<p>There are a lot of benefits to running the same application on your client and
server. At GoCardless, we just launched the new gocardless.com, a ReactJS
application that runs on client and server (we <a href="https://gocardless.com/blog/how-we-built-the-new-gocardless.com/">blogged about how we did
it</a>) and it's
gone really well. I expect that tools will grow out to serve this demand and
that the approach will be refined over time.</p>
<h3>7: As ES2015 implementations complete, we'll be writing ES7 already</h3>
<p>Tools like Traceur and Babel (initially called 6to5) initially existed to let us
write ES2015 ahead of it being fully supported across browsers. However they
have since grown to support upcoming features of ECMAScript7 and beyond. I can't
see a time where we won't run our code through something like Babel, because by
the time ES2015 is fully implemented, the next version of the language will be
well under way. In fact, this is a good thing, because it should let new proposed
features be tested by developers before they are implemented. The feedback loop
should be quicker as a result of people writing ES7 way before release and that
can only be a benefit to everyone involved.</p>
<h3>8: The rate of new frameworks will begin to slow down</h3>
<p>Framework booms are to be expected when a new approach to web development comes
along. The swap to client side applications really began with BackboneJS, before
many others came along. Every week it felt like a new framework hit the internet
but recently to me it feels like that's slowed down a little. Angular and Ember
have emerged as the two most popular options, but we've not seen as many new
options really catch on. I think as we've figured out the best approaches for
building and architecting client side applications, we've picked out frameworks
and stuck with them. That isn't to say another framework couldn't come along, but
I'd be surprised if in 12 months the focus isn't still on the frameworks that
we're using at the moment.</p>
<h1>Conclusion</h1>
<p>They're my thoughts on what we could see happen over the next 12 months or so,
and I'd be keen to hear what everyone else thinks. I'm pretty sure that I'll get
things wrong, too! There are also other things I'm interested to see more of
once they are released, including Facebook's work on <a href="http://facebook.github.io/react/blog/2015/02/20/introducing-relay-and-graphql.html">Relay and
GraphQL</a>.
It's hard to say much about the tools when they have yet to be fully open
sourced, but I've no doubt they will have an impact when they are.</p>
<p><em>My thanks to <a href="https://twitter.com/maxalfiemurdoch">Max Murdoch</a> for his
reviewing of this post.</em></p>
Array methods in ECMAScript 62015-09-01T00:00:00+00:00http://www.jackfranklin.co.uk/blog/es6-arrays/<p>I've written at length about some of the new features coming to JavaScript with ES6, including arrow functions, classes, modules and destructuring. Today I'd like to explore some of the smaller additions, starting with new methods that are being added to arrays. This isn't a comprehensive list, rather a selection of some that I've found really useful.</p>
<p>Rather that list compatability information here about what is and what isn't supported across transpilers and browsers, you should refer to the <a href="https://kangax.github.io/compat-table/es6/#Array.prototype_methods">relevant section of the Kangax compat table</a>. Paul Miller's <a href="https://github.com/paulmillr/es6-shim/">ES6 Shim</a> includes polyfills for a number of the methods I'm going to mention today, too. All code examples below were run through Babel.</p>
<p>We'll start with methods defined on the prototype before looking a couple of new static Array methods.</p>
<h2><code>Array.prototype.find</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find">mdn</a></h2>
<p><code>find</code> lets you iterate through an array and get the first element back that causes the given callback function to return <code>true</code>. Once an element has been found, the function immediately returns. It's an efficient way to get at just the first item that matches a given condition:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> numbers <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br><span class="token keyword">let</span> oddNumber <span class="token operator">=</span> numbers<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=></span> x <span class="token operator">%</span> <span class="token number">2</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>oddNumber<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1</span></code></pre>
<p>You might think this is similar to <code>filter</code> (an ES5 method), but whereas <code>filter</code> always returns an array of matches (and will return multiple matches), <code>find</code> always returns the actual element.</p>
<h2><code>Array.prototype.findIndex</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex">mdn</a></h2>
<p><code>findIndex</code> behaves very similarly to <code>find</code>, but instead of returning the element that matched, it returns the index of that element.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> people <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'jamie'</span><span class="token punctuation">,</span> <span class="token string">'jack'</span><span class="token punctuation">,</span> <span class="token string">'isaac'</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br><span class="token keyword">let</span> jackIndex <span class="token operator">=</span> people<span class="token punctuation">.</span><span class="token function">findIndex</span><span class="token punctuation">(</span><span class="token parameter">x</span> <span class="token operator">=></span> x <span class="token operator">===</span> <span class="token string">'jack'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>jackIndex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 1</span></code></pre>
<h2><code>Array.prototype.entries</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries">mdn</a></h2>
<p><code>entries</code> is a function that returns an <code>Array Iterator</code> (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators">mdn docs for interators</a>) that can be used to loop through the array's keys and values. <code>entries</code> will return an array of arrays, where each child array is an array of <code>[index, value]</code>.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> people <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'jamie'</span><span class="token punctuation">,</span> <span class="token string">'jack'</span><span class="token punctuation">,</span> <span class="token string">'isaac'</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br><span class="token keyword">let</span> entries <span class="token operator">=</span> people<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>entries<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [0, 'jamie']</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>entries<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [1, 'jack']</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>entries<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [2, 'isaac']</span></code></pre>
<p>We can also use the spread operator to get back an array of the entries in one go:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> people <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'jamie'</span><span class="token punctuation">,</span> <span class="token string">'jack'</span><span class="token punctuation">,</span> <span class="token string">'isaac'</span><span class="token punctuation">]</span><span class="token punctuation">;</span><br><span class="token keyword">let</span> entries <span class="token operator">=</span> people<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>entries<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [[0, 'jamie'], [1, 'jack'], [2, 'isaac']]</span></code></pre>
<p>Although I won't mention them in any detail here, we also have the new <code>keys</code> (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys">mdn</a>) and <code>values</code> (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values">mdn</a>) methods, which return an iterator of the array keys and the array values respectively.</p>
<h2><code>Array.from</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from">mdn</a></h2>
<p><code>Array.from</code> takes many forms, <a href="https://kangax.github.io/compat-table/es6/#Array_static_methods">as the ES6 compat table shows</a>, but its general function is to enable the creation of a new array from an array like object. As its first argument it can accept something that's array like (has <code>length</code> and indexed items), along with <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols">iterable objects</a>, like the newly added <code>Set</code> and <code>Map</code> in ES6.</p>
<pre class="language-js"><code class="language-js">Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ['h', 'e', 'l', 'l', 'o']</span><br><br>Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [1, 2, 3]</span><br><br><span class="token keyword">let</span> namesSet <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'jamie'</span><span class="token punctuation">,</span> <span class="token string">'jack'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br>Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>namesSet<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ['jamie', 'jack']</span></code></pre>
<p><code>from</code> can also take a second argument, which is a map function to be applied to each element:</p>
<pre class="language-js"><code class="language-js">Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token parameter">x</span> <span class="token operator">=></span> x <span class="token operator">*</span> x<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [1, 4, 9]</span></code></pre>
<p>Because the method can take array like objects, we can use it to generate arrays of values too:</p>
<pre class="language-js"><code class="language-js">Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">length</span><span class="token operator">:</span> <span class="token number">4</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">val<span class="token punctuation">,</span> key</span><span class="token punctuation">)</span> <span class="token operator">=></span> key<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// [0, 1, 2, 3]</span></code></pre>
<p>Each time the mapping function gets called, the <code>val</code> argument will be <code>undefined</code>, as this object has no actual values, but the <code>key</code> argument will be <code>0</code>, then <code>1</code> and so on. This lets us generate arrays of numbers, but we can also return whatever we'd like from the mapping function:</p>
<pre class="language-js"><code class="language-js">Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">length</span><span class="token operator">:</span> <span class="token number">2</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token string">'jack'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ['jack', 'jack']</span></code></pre>
<p>With its ability to take array like objects along with iterators, and a custom mapping function, <code>Array.from</code> is incredibly versatile.</p>
<h2>Conclusion</h2>
<p>It's the addition of smaller methods like the ones I've mentioned above, along with the larger features, that make ES6 such a pleasure to work with. Get familiar with the above methods, and similar additions across other JS built-ins, and you'll find yourself wondering how you ever coped without them.</p>
The state of front end tooling2015-10-12T00:00:00+00:00http://www.jackfranklin.co.uk/blog/state-of-frontend-tooling/<p>There's been a lot of posts written recently on the web about the state of tooling in front-end development and the opinion that many share that the environment has become overwhelming both for the beginner developer and the more experienced developer.</p>
<p>At <a href="https://futureofwebapps.com/london-2015/">Future of Web Apps 2015</a> I watched a really interesting talk from <a href="https://twitter.com/ppk">Peter-Paul Koch</a> in which he argued that our tooling problem has become an epidemic; and that we should stop encouraging the creation of new tools and libraries. After my talk at FOWA, in which I demoed building applications using <a href="http://jspm.io/">jspm</a>, <a href="https://github.com/systemjs/systemjs">SystemJS</a> and <a href="http://babeljs.io/">Babel</a>, I had an attendee question if the addition of jspm was warranted. It's a perfectly reasonable question and one that got me thinking.</p>
<h2>Tools for tool's sake</h2>
<p>I explained to the attendee that I use jspm because it solves a problem that I don't want to have to deal with. In this case, jspm lets me install 3rd party modules from npm and GitHub without me having to deal with configuration or any form of additional build tool, and it also provides the bundling functionality when it comes to deploying my application. Yes, I pay the small overhead of adding another tool, but I can justify it.</p>
<p>The problem and confusion comes from using tools just because they exist or because they're the "new shiny" toy that has come along. If you're adding a tool to your workflow just because someone on the internet said you should, you're going to hit difficulties. You need to strenuously vet tools before deciding that you're happy to have them as part of your set up. The way you would do this is by using a tool on a project ultimately, but not without doing some research first. Most projects will provide examples of using them and you should try to marry those up with your project. If you find yourself struggling to explain to a colleague why you think this tool will be a good addition, it's likely that it isn't. Don't force a tool upon an application that it's not suited for. This isn't just true for package managers like jspm, but frameworks, polyfills and any form of 3rd party item you might include.</p>
<p>Additional criteria you might check to decide if a tool is right for you and your project might be:</p>
<ul>
<li>is the project active? This does not mean "committed to in the last three / six months", but is there a community around it? An active Slack / IRC channel or some form of discussion? Are there many GitHub issues, and are new ones replied to relatively quickly?</li>
<li>do you know other developers using it? Being able to speak to someone who is heavily invested in a tool is a great way to get information quickly. Additionally, you'll have more luck bringing other developers into your project if you're picking tools more people are behind and using.</li>
<li>do resources exist to help you use it? Are there answers on Stack Overflow, tutorials on other blogs or conference talks you can use when you're first learning the tool?</li>
<li>is it well implemented? You don't have to learn the source code in depth, but there's other ways to judge this. Has the library been split up into multiple files, are there some tests? Are any pull requests carefully considered before being merged? Does the maintainer carefully tag releases and version their releases properly?</li>
<li>does the project's README provide a good starting point? It should explain the motivations behind the project, some examples of its use and links to thorough documentation, tutorials and more.</li>
</ul>
<p>You should also forget about trying to "keep up" with the web as more and more tools come along. Tim Kadlec talks about this in his blog post <a href="http://timkadlec.com/2015/09/the-fallacy-of-keeping-up/">"The Fallacy of Keeping Up"</a>, which I recommend reading. It's just not worth your time and effort to try every tool as they come out and chop and change. Recently someone asked me if they should leave Grunt to try something else like Gulp, and I asked them what problems they were having with Grunt. They weren't having any, but this person had been told by many that they should consider swapping over. Yes, it's true that if you're relying on a tool that's not been maintained for years you might consider moving over, but don't let that decision be a knee jerk reaction. We have a skewed view in this industry; an "unmaintained" project on GitHub is one that's not had a commit in three months. Think longer term, and don't be afraid to stick to the tools you trust. You should end up with a tried and trusted toolset that you rely on time after time. For me and the projects I work on that's jspm along with ESLint and a couple of others. For you it might be Grunt, JSHint and CoffeeScript. It doesn't matter, as long as you can justify each of them to me and spend the time to build up your knowledge and understanding of them.</p>
<h2>Complexity is inevitable</h2>
<p>It's been said time and time again that our tooling setup has gotten incredibly complex, and that it's made the web much more daunting for new developers. There's definitely some truth to this - when most of us started writing JavaScript we created an HTML file, added a <code><script src="app.js"></script></code> and wrote our JavaScript in <code>app.js</code>. We would then open that file in our browser of choice and that was that. If you search for beginner tutorials today a large number of them will introduce you to npm, Sass or some other framework that sits atop the base layer of HTML, CSS and JavaScript (ES5, not ECMAScript 2015).</p>
<p>For me, that is <strong>still</strong> the baseline and the one that we should adhere to when introducing new developers to the ecosystem. There's no doubt in my mind if I'd have had to install Node, run Babel, or set up any other tool, I would probably have given up. I can remember struggling to install Ruby on my machine, something that today I take for granted. We all started from somewhere, and for new developers that somewhere should be an HTML file loaded into a modern browser with one JavaScript file. As that person grows in confidence and knowledge we can begin to layer these tools on top. Additionally, that person's new found knowledge will enable them to start being able to accurately judge if a particular tool is of interest to them and applicable to their project. Beginners don't know if a particular tool will suit their project, or if that tool is going to be one they can rely on. Being able to make that call is something that comes with experience, and we shouldn't force tools onto people until they're in a position to make the call themselves if it's a good decision or not.</p>
<p>As we move more and more functionality to the client, part of the trade off is that we end up with a more complicated tooling set up. If you ever work on a server side language you'll meet a bunch of tools that have grown out of the requirement to tackle the requirements of authoring and working with a large application. Traditionally in the past we've never had to deal with that, and hence there's never been much of a need for a complicated tool chain. Now we're building full, stateful applications in the client, it's inevitable that we'll need some extra tooling to help us, and we shouldn't be afraid of that.</p>
<h2>The wrong type of tools</h2>
<p>I don't think that we're creating too many tools - not only is it great to have a variety, it also encourages competition and improvement. ReactJS is a great example of this; since its introduction and adoption other frameworks like EmberJS have embraced React's virtual DOM model, and others will follow suit too.</p>
<p>What's more interesting to me is the type of tools we're creating. I'm a big believer of the Unix philosophy: each tool should do one thing, and do it well. This is definitely something we can take into our approach with web development tools. Every individual tool that you add to your project should be able to have its functionality summed up succinctly. We shouldn't look to use or to create tools that attempt to do everything. This is partly the reason ReactJS has been adopted so quickly - its surface area is very small, and the functionality it provides is well defined. This is partly the reason I've stopped using task runners like Gulp or Grunt, and instead prefer to install many smaller modules that each provide a small piece of the puzzle. Of course, I could use Gulp given that all its functionality comes from plugins, but I don't need that additional complexity. You might, and if you do, that's great. I'm not saying there's anything wrong with Gulp, larger frameworks like Angular, or tools that provide a range of features. As we go forwards though we should make a concerted effort to build tools with smaller surface areas. The benefits of this are huge:</p>
<ul>
<li>tools with smaller surface areas are much easier to pick up, and much easier to master</li>
<li>using a variety of smaller tools means you can swap one out for another with less effort if you find a better option</li>
<li>it's easier for people to create but more importantly maintain smaller tools</li>
<li>it's much easier to experiment with a smaller tool - you don't have to rewrite huge parts of your application. This makes it easier to gauge quickly if a tool is right for you or not</li>
<li>small tools can be composed together to create a larger system. Smaller tools are interopable by default, there is no larger ecosystem defining an API that everything must adhere to. Let each tool do its job, and compose them together to achieve the desired result.</li>
</ul>
<h2>Conclusion</h2>
<p>I hope that this article provides some food for thought, and I'd really love to hear what you think. Please feel free to <a href="http://twitter.com/Jack_Franklin">drop me a tweet</a>, I'd really like to discuss the issues of tooling and what we can do going forward to ensure we head in the right direction.</p>
<p>Thanks to Alex Young, Shane Hudson, Adam Onishi, Ruth John and Peter Müller for their review of this blog post.</p>
Authoring JavaScript modules with ES62015-10-15T00:00:00+00:00http://www.jackfranklin.co.uk/blog/authoring-modules-in-es6/<p><strong>Update: this post was updated on 09/11/2015 to use Babel 6, rather than Babel 5.</strong></p>
<p>I've spoken and written previously about using tools like <a href="http://jspm.io/">jspm</a> to let you write web applications in ES6 and take care of the details, leaving you free to focus on writing your app and not the tooling around it. Today we're going to talk about how we can author and publish modules written in ES6, but doing so in a way that's generic enough to allow the consumer to use your module in Node or through a client side library like jspm, Webpack or Browserify.</p>
<p>The process isn't as complicated as you might imagine; thankfully we can offload most of the work to Babel, and the only requirement on our part is to run our ES6 through Babel before publishing the module to npm.</p>
<p>Let's get started by first creating a new project, and installing Babel as a developer dependency. We'll use Babel to convert our ES6 into ES5. This means that whilst we're able to embrace ES6 as the module author, if the person using our module is unable to, they don't have to. There's no extra burden on the end user to do extra work or configuration to use our module.</p>
<pre><code>npm init
npm install --save-dev babel-cli
</code></pre>
<p>As of Babel 6 it's been split into two modules. babel-cli is for using Babel from the command line, and babel-core is for use through NodeJS. We're going to run Babel on the command line, so we'll install the CLI.</p>
<p>The module we're going to build is a tiny one that takes a GitHub username and uses the new <a href="https://developer.mozilla.org/en/docs/Web/API/Fetch_API">fetch API</a> to make a request to the GitHub API for a list of repositories that the user owns. Note that at the time of writing, the fetch API is only supported in Chrome, <a href="https://github.com/github/fetch">but a polyfill exists</a>. If you want a polyfill that works in both Node and in the browser, Matt Andrew's <a href="https://github.com/matthew-andrews/isomorphic-fetch">Isomorphic Fetch</a> is your best bet.</p>
<p>It's up to you if you want to include the polyfill in the module, or suggest to users that they use it. Personally I prefer to let the end user decide, they might not need a polyfill, or have a particular favourite, and I don't want to force that on them.</p>
<p>Because we'll be converting our source code into code that we then publish, I like to create a directory, typically named <code>src</code>, that holds our source code. Let's create <code>src/githubby.js</code>, that exports the function I mentioned previously:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">getReposForUser</span><span class="token punctuation">(</span><span class="token parameter">username</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br><span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.github.com/users/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>username<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/repos</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br><br><span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre>
<p>This code makes use of a few ES6 features, including ES6 modules, block scoping, template literals and arrow functions. This code won't run in many environments right now, and that makes our module pretty useless. We can use Babel's command line tool to convert this code:</p>
<pre><code>babel -d lib src/
</code></pre>
<p>This tells Babel to take every JavaScript file in the <code>src</code> directory, and output a corresponding compiled file into <code>lib</code>. However, as of Babel 6, this won't do anything by default. Babel doesn't provide any transforms by default, you have to tell it what transforms you want it to perform. Luckily for us Babel also provides a number of presets to quickly configure things. One such preset is <code>babel-preset-es2015</code>, which configures Babel 6 to transform our code into ECMAScript 5 code. First, install the preset:</p>
<pre><code>npm install --save-dev babel-preset-es2015
</code></pre>
<p>And then create a <code>.babelrc</code> file to tell Babel to use that preset:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br> <span class="token string-property property">"presets"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"es2015"</span><span class="token punctuation">]</span><br><span class="token punctuation">}</span></code></pre>
<p>Now when we run Babel 6, our code will be transformed as we expect. If we take a look at <code>lib/githubby.js</code>, you'll see a file that looks similar to the below:</p>
<pre class="language-js"><code class="language-js"><span class="token string">'use strict'</span><span class="token punctuation">;</span><br><br>Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>exports<span class="token punctuation">,</span> <span class="token string">'__esModule'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">value</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br>exports<span class="token punctuation">.</span>getReposForUser <span class="token operator">=</span> getReposForUser<span class="token punctuation">;</span><br><span class="token keyword">function</span> <span class="token function">getReposForUser</span><span class="token punctuation">(</span><span class="token parameter">username</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">var</span> url <span class="token operator">=</span> <span class="token string">'https://api.github.com/users/'</span> <span class="token operator">+</span> username <span class="token operator">+</span> <span class="token string">'/repos'</span><span class="token punctuation">;</span><br><br> <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre>
<p>You can see that Babel has converted our code into JavaScript that is widely supported across browsers and environments like NodeJS.</p>
<p>The final step is to set up our module such that when we publish it to npm, we first rerun Babel to generate the files in the <code>lib</code> directory. We also need to tell npm which file it should load when our module is imported by another.</p>
<p>Firstly, we can add an npm script called <code>prepublish</code> in our <code>package.json</code> file:</p>
<pre class="language-json"><code class="language-json"><span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token property">"prepublish"</span><span class="token operator">:</span> <span class="token string">"./node_modules/.bin/babel -d lib src/"</span><br><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>There's a very good reason that we call this script <code>prepublish</code>. When we want to push our module onto npm, we'll run <code>npm publish</code>. This is a command built into npm. When we run <code>npm publish</code>, it will first look for a script called <code>prepublish</code>, and run that if it exists.</p>
<p>To tell npm which file it should load by default, we need to edit the <code>main</code> property in our <code>package.json</code> file to point to our generated <code>lib/githubby.js</code> file:</p>
<pre class="language-json"><code class="language-json"><span class="token property">"main"</span><span class="token operator">:</span> <span class="token string">"lib/githubby.js"</span><span class="token punctuation">,</span></code></pre>
<p>With both of those set up we can now run <code>npm publish</code> to publish our module for all to use:</p>
<pre><code>jack/jsplayground-example > npm publish
> jsplayground-example@1.0.0 prepublish /Users/jackfranklin/git/jsplayground-example
> babel -d lib src/
src/githubby.js -> lib/githubby.js
+ jsplayground-example@1.0.0
</code></pre>
<p>Now we have a module that we've authored entirely in ES6 that is published in a way that makes it usable to as many different consumers as possible. Nothing in our module is specific to the browser or specific to Node, and a person using this module could be using it in the client or on the server, and it will work just as well on both. In a future article I'll look at the different ways we can consume this module. If you'd like to grab the code and check out the module for yourself, <a href="https://github.com/jackfranklin/authoring-es6-module-example">you can check the example repository on GitHub</a>.</p>
Elm for JavaScript Developers2015-11-23T00:00:00+00:00http://www.jackfranklin.co.uk/blog/elm-for-javascript-developers/<p>If you follow me on GitHub or Twitter you'll have noticed that I've been doing a lot of work with <a href="http://elm-lang.org/">Elm</a> recently. Elm is a new language aimed at making it easier to build more robust, complex applications. It compiles to JavaScript but shares very little in common with the language, and its syntax will look familiar to anyone who's worked with Haskell. In the first of many posts about Elm, I'll talk through some of the major features of the language and why you should consider giving it a try. Don't be put off by its different syntax; once you get used to it you'll realise that it's a pleasure to work with.</p>
<h2>Immutability and Pure Functions</h2>
<p>Every single piece of data you have in your Elm application is immutable. This means that it can never be modified, and will always be set to the value it was given when it was created. What this means in practice is that code is much easier to follow, because you know it hasn't changed. As an example, think about the below JavaScript code:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> person <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span><br><span class="token function">doSomethingWith</span><span class="token punctuation">(</span>person<span class="token punctuation">)</span><span class="token punctuation">;</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>person<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Without executing that code, are you able to make any guarantees about the value of <code>person</code> once <code>doSomethingWith</code> has executed?</p>
<p>None.</p>
<p>Because objects in JavaScript are mutable, anything could have happened to <code>person</code>.</p>
<p>This is a fruitful source of bugs in larger applications. Functions that modify the state of the world, by mutating variables available to it, are functions with <strong>side effects</strong>. Functions like this are difficult to debug and harder to work with. They are also harder to test and you should aim to avoid them whenever possible.</p>
<p>In Elm, every function is <strong>pure</strong>. This means two things:</p>
<ul>
<li>Given an input X, it will always result in output Y. If you give a function the same value, it will always produce the same result.</li>
<li>The function has no side effects, and does not mutate anything or change the state of the world around it.</li>
</ul>
<p>It's entirely possible to create functions like this in JavaScript, and you can make it a rule in your application that functions should be pure. Elm enforces it due to its immutable nature, and this means it's impossible for impure functions to sneak into your code base, either through code you write or through code in a 3rd party library you're using.</p>
<p>You might be wondering how you're expected to keep track of state in your application when you can't mutate values. This is entirely possible in Elm using Signals, and we'll visit it in a later article.</p>
<h2>Types</h2>
<p>Elm is a statically typed language. This might sound off-putting, but it actually leads to far more robust applications. In Elm every value has a type.</p>
<pre><code>"Hello World" - String Type
True - Boolean type
3 - number type
3.14 - Float type
[1, 2, 3] - List number type
</code></pre>
<p>You might think this is similar to JavaScript, and you'd be right. In JavaScript (and every other programming language), values have a particular type. The crucial difference comes when we pair this type system with functions. In JavaScript you might have a function that can take multiple types, and return multiple types:</p>
<pre class="language-js"><code class="language-js"><span class="token function">someMadeUpFn</span><span class="token punctuation">(</span><span class="token string">'Foo'</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token number">5</span><br><span class="token function">someMadeUpFn</span><span class="token punctuation">(</span><span class="token parameter"><span class="token number">5</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token string">'Foo'</span><br><span class="token function">someMadeUpFn</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'jack'</span> <span class="token punctuation">}</span></code></pre>
<p>Additionally, JavaScripts type system is <strong>dynamic</strong>, which means types are only decided at <strong>runtime</strong>, when your code is executed. Elm's type system is <strong>static</strong>, which means the compiler can figure out the types ahead of time. We'll come back to this later.</p>
<p>In the code above there are no restrictions on the types of the arguments that <code>someMadeUpFn</code> takes, and there's no restrictions on the type of the value it returns either. In Elm we have to explicitly declare all the types (actually, we could leave it up to the compiler to infer the types, but it's best practice to declare them). The below code creates a function <code>square</code> that takes an integer and returns another.</p>
<pre><code>square : Int -> Int
square x = x * x
</code></pre>
<p>If I were to write the same function in JavaScript, I'd write:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">square</span><span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> x <span class="token operator">*</span> x<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre>
<p>Notice the first line of our Elm function:</p>
<pre><code>square : Int -> Int
</code></pre>
<p>This is a <strong>type annotation</strong> that tells Elm that this function will take one argument which will be an integer, and return a value that's also an integer. That means if we try to call this function with a different data type, we'll get an error. Although this restriction can take some time to adjust to, it actually leads to much cleaner code that's easier to work with and follow. It also means you realise straight away if you're using a function incorrectly.</p>
<h2>Compiling</h2>
<p>Above we noted that trying to call a function with the wrong types causes an error. Even better, we get these errors at <strong>compile time</strong>. Elm as a language compiles to JavaScript, and we need to run the compiler to generate JavaScript from our Elm code. Elm's compiler is smart, and is able to check the types of values when it compiles our code into JavaScript. For example, if I take this Elm code and try to compile it, we'll get an error. Don't worry about the specifics of the syntax, but know that this code will call the <code>square</code> function with the argument <code>"Hello"</code>.</p>
<pre><code>square : Int -> Int
square x = x * x
main =
square "Hello"
</code></pre>
<p>Here's what the compiler gives me:</p>
<pre><code>The argument to function `square` is causing a mismatch.
5│ square "Hello"
^^^^^^^
Function `square` is expecting the argument to be:
Int
But it is:
String
</code></pre>
<p>How great is that?! The compiler detected our mistake, and rather than getting an odd error when we run the code in the browser, we instead see a much nicer error telling us of our mistake ahead of time.</p>
<h2>Getting started with Elm</h2>
<p>I hope that this post has peaked your interest in this language. In the coming weeks I'll be posting more about Elm and how to get started, but if this post has you eager for more here's some resources I'd recommend:</p>
<ul>
<li><a href="http://elm-lang.org/docs/from-javascript">Comparison of Elm and JS Syntax</a></li>
<li><a href="http://elm-lang.org/docs/syntax">Elm syntax introduction</a></li>
<li><a href="https://pragmaticstudio.com/elm">Elm video course ($24 but recommended)</a></li>
<li><a href="https://github.com/jackfranklin/elm-game-of-life">My Game of Life implementation in Elm</a></li>
<li><a href="https://github.com/jackfranklin/elm-connect-four">Connect Four in Elm</a></li>
</ul>
Better bundles with Rollup2016-02-05T00:00:00+00:00http://www.jackfranklin.co.uk/blog/better-bundles-rollup/<p>Recently I've been hearing a lot about <a href="https://github.com/rollup/rollup">Rollup</a>, a new JavaScript bundling tool that aims to produce smaller bundling sizes through <em>tree shaking</em>, which is the process of taking an application and figuring out which code is actually used.</p>
<p>Sam Saccone's <a href="https://github.com/samccone/The-cost-of-transpiling-es2015-in-2016">cost of transpiling ES2015</a> repository also peaked my interest by comparing bundle sizes of popular bundling solutions. Rollup performed well in it and I was keen to give it a go!</p>
<h2>What is Tree Shaking?</h2>
<p>A bundler that supports tree shaking will "shake" your application when it bundles it to see which code is actually used. Think of this like shaking a tree branch and seeing which leaves stay on it. This is most effective when you're depending on a huge library, Lodash for example, but only use one or two of the methods in it. A bundling tool that can calculate which parts of the library are used and only include them will cut out the vast majority of the library, which is unused. With a large application that includes many 3rd party dependencies we can dramatically reduce the size of our bundle we ship to users.</p>
<h2>Isn't this dead code elimination?</h2>
<p>There's a subtle difference that the <a href="https://github.com/rollup/rollup">rollup README</a> notes:</p>
<blockquote>
<p>Rather than excluding dead code, we should be including live code (aka 'tree-shaking'). That's only possible with ES6 modules.</p>
</blockquote>
<p>## ES2015 Modules required</p>
<p>We need our application to be written in ES2015 modules because they allow us to only import parts of a module. That is, rather than:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">var</span> each <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'lodash'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>each<span class="token punctuation">;</span></code></pre>
<p>Which requires the entire module to be loaded, we can instead in ES2015 say:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> each <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'lodash'</span><span class="token punctuation">;</span></code></pre>
<p>ES2015 modules are <em>static</em>, which means that their imports and exports are known without having to run the application. For example, the following isn't allowed in an ES2015 module:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">if</span> <span class="token punctuation">(</span>something<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">export</span> <span class="token keyword">const</span> foo <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre>
<p>Rollup is able to parse your ES2015 application and its dependencies and eliminate any code that isn't used.</p>
<h2>ES2015 TodoMVC</h2>
<p>To demonstrate this in action I took the <a href="https://github.com/tastejs/todomvc/tree/gh-pages/examples/vanilla-es6">vanilla ES6 TodoMVC example</a> as a base. To be clear, this is not a criticism of this project, it's well written and a great example ES2015 application. I picked it because it was a good sized project to experiment if Rollup would make a difference.</p>
<h2>Bundling with Browserify</h2>
<p>Out of the box that project comes with Babel 6 and Browserify for building. To try to be as fair as possible I updated the Browserify build process to include <a href="https://github.com/hughsk/uglifyify">Uglifyify</a>, a Browserify transform which minifies code as it's run through Browserify. Uglifyify can make some extra optimisations due to being run on each file, so it's worth including. To generate the Browserify bundle I ran:</p>
<pre><code>babel src --presets es2015 --out-dir=dist && browserify -t uglifyify dist/app.js | uglifyjs -c > dist/bundle.js
</code></pre>
<p>This runs Babel with the ES2015 preset and then runs the processed code through Browserify, using the Uglifyify transform and then minifying again with UglifyJS to be most effective. <strong>If you have any ideas on how to optimise this further, please let me know and I'll update the post</strong>.</p>
<p>Running this on my machine gives me a file that's 15.8KB in size. Not bad, but can we do better?</p>
<h2>Bundling with Rollup</h2>
<p>There's a bit of extra work to get Rollup playing nicely. Rollup requires code written with ES2015, but Babel's default ES2015 plugin set will convert the code into CommonJS. Therefore we can't use that preset in order to transpile our code. Thankfully Rollup publishes its ES2015 preset that matches Babel's which the exclusion of the CommonJS plugin. First I installed that and Rollup itself, along with the Rollup Babel plugin and the Rollup Uglify plugin.</p>
<pre><code>npm install --save-dev babel-preset-es2015-rollup rollup rollup-plugin-babel rollup-plugin-uglify
</code></pre>
<p>I also can't do everything I need to do with Rollup in a command line call, so I created <code>rollup-build.js</code> to contain my code:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> rollup <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'rollup'</span><span class="token punctuation">;</span><br><br><span class="token keyword">import</span> babel <span class="token keyword">from</span> <span class="token string">'rollup-plugin-babel'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> uglify <span class="token keyword">from</span> <span class="token string">'rollup-plugin-uglify'</span><span class="token punctuation">;</span><br><br><span class="token function">rollup</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token comment">// tell rollup our main entry point</span><br> <span class="token literal-property property">entry</span><span class="token operator">:</span> <span class="token string">'src/app.js'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token comment">// configure rollup-babel to use the ES2015 Rollup preset</span><br> <span class="token comment">// and not transpile any node_modules files</span><br> <span class="token function">babel</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">exclude</span><span class="token operator">:</span> <span class="token string">'node_modules/**'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">presets</span><span class="token operator">:</span> <span class="token string">'es2015-rollup'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token comment">// minify with uglify</span><br> <span class="token function">uglify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token punctuation">]</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">bundle</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// write bundle to a file and use the IIFE format so it executes immediately</span><br> <span class="token keyword">return</span> bundle<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">format</span><span class="token operator">:</span> <span class="token string">'iife'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">dest</span><span class="token operator">:</span> <span class="token string">'dist/rollup-bundle.js'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Bundle created'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>To run this code I first need to run it through Babel (this is optional, I could have written the above script using only features Node supports), so I'll install <code>babel-cli</code>:</p>
<pre><code>npm install --save-dev babel-cli
</code></pre>
<p>And then I can generate the Rollup bundle:</p>
<pre><code>babel-node --presets es2015 rollup-build.js
</code></pre>
<p>That generates <code>dist/rollup-bundle.js</code>, which comes in at 11.3KB in size, a saving of approximately 4.5KB.</p>
<h2>Update</h2>
<p>Rich Harris, the creator of Rollup, pointed out to me that you can indeed have a config file and use the command line version of Rollup. To do this create <code>rollup.config.js</code> which looks like so:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">import</span> babel <span class="token keyword">from</span> <span class="token string">'rollup-plugin-babel'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> uglify <span class="token keyword">from</span> <span class="token string">'rollup-plugin-uglify'</span><span class="token punctuation">;</span><br><br><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span><br> <span class="token comment">// tell rollup our main entry point</span><br> <span class="token literal-property property">entry</span><span class="token operator">:</span> <span class="token string">'src/app.js'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">dest</span><span class="token operator">:</span> <span class="token string">'dist/rollup-bundle.js'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token function">babel</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">exclude</span><span class="token operator">:</span> <span class="token string">'node_modules/**'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">presets</span><span class="token operator">:</span> <span class="token string">'es2015-rollup'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token function">uglify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token punctuation">]</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>And then we can run <code>rollup -c</code> to achieve the same result.</p>
<h2>Conclusion</h2>
<p>Even on this small project with no external dependencies Rollup's build was able to save 4.5KB on an initial bundle of 15.8KB, which is a saving of over 33%. On a larger project with more dependencies and code I'd be willing to bet Rollup would save more.</p>
<p>In a future post I will do more exploring with Rollup and look at how we'd configure it on a much larger project that contains npm dependencies, and modules written in CommonJS (that Rollup, without a plugin) can't parse.</p>
JavaScript Releases: ES2016 and Beyond2016-02-08T00:00:00+00:00http://www.jackfranklin.co.uk/blog/es2016-and-beyond/<p>ES2015 introduces a huge new set of features to the language, many of them welcomed, but does so at a huge cost: there's a vast amount for people to learn. From arrow functions to sets, maps, classes and destructuring, ES2015 is almost like learning an entirely new version of JavaScript. Quite understandably this has overwhelmed a lot of people and caused them to have concern about the future of the language.</p>
<p>Thankfully it was widely recognised that big bang releases like ES2015 are not the way forward - going so long between releases has many issues and it also leads to an unwillingness from many sections of the community to pick up and learn the new additions until they are supported across most popular browsers.</p>
<h2>ES2016</h2>
<p>The good news if you've been left feeling like you're entirely lost in the world of JavaScript is that the final feature set for ECMAScript 2016 was confirmed as two new additions: <a href="http://www.2ality.com/2016/02/array-prototype-includes.html"><code>Array.prototype.includes</code></a> and the <a href="http://www.2ality.com/2016/02/exponentiation-operator.html">exponentiation operator</a>. I've linked to posts by Dr Axel Rauschmayer who explains the features thoroughly. This means when ES2016 comes into action there's two small, succinct additions to the language that shouldn't take long to pick up. Once more, this is how it's going to be for every JavaScript release going forward: once a year, containing any proposals that have made it to Stage 4, the final stage of the proposal process.</p>
<p>If you're concerned that you've barely got up to speed on ES2015 and now you have an entirely new version to learn, there's two reasons not to worry:</p>
<ul>
<li>ES2016 will have its full specification ratified in the summer and <a href="http://kangax.github.io/compat-table/esnext/">browser support isn't exactly huge yet</a>, so if you don't want to care about it until there's more chance of using it, that's fine.</li>
<li>If you do decide you'd like to get up to speed there's only two features, and both are very self contained.</li>
</ul>
<h2>JS Going Forward</h2>
<p>Whilst we're still a little hungover from the efforts trying to get up to speed with ES2015 and its vast array of features and might be frustrated that a new release has appeared, going forward this bodes really well for the JavaScript community and the adoption of new features introduced to the language. Fast forward another year or two to a point where ES2015 is now history and we'll be in a place of yearly JS releases containing a small set of features to learn. There should be no more sense of sinking amidst new features or losing track with the progress of the language. I'm personally really excited and confident that this new process will help everyone in the community feel more confident keeping up with JavaScript as it matures and changes.</p>
<h2>Future Features in the Open</h2>
<p>If you are someone who wants to keep up with language proposals and have a sense ahead of time of the features that could potentially make it into standard, you absolutely can. Another great thing about the new process is that it's all hosted in the open in GitHub repositories so anyone is able to take an interest.</p>
<p>Proposals start at Stage 0, where they can be proposed by anyone who is a member of TC39 (the commmittee who oversee JavaScript) or a non member registered as a contributor. From there they progress through stage 1, 2, 3 and finally stage 4. Stage 4 is hit when there are two native implementations in browsers that are fully spec compliant, at which point the feature is ready to be included in the standard. <a href="http://www.2ality.com/2015/11/tc39-process.html">The 2Ality blog has a more thorough article on the details of this process</a>.</p>
<p>The great news is that you can see all of this on GitHub:</p>
<ul>
<li><a href="https://github.com/tc39/ecma262/blob/master/stage0.md">A repository of Stage 0 proposals</a></li>
<li><a href="https://github.com/tc39/ecma262/blob/master/README.md">A repository of Stage 1-4 proposals</a></li>
</ul>
<p>By following those links you can read up more on any particular proposal and get a sense of where it's at in the process and how likely it is to be included in the specification.</p>
<p>## Trying features</p>
<p>With the rise of transpilers like Babel it's also now much easier to try new features out, whether those are features guaranteed to make it into a future addition, or ones that you're interested in and would like to try. Most proposals come with a Babel plugin which you can install and then make use of the feature. You should be wary of depending on too many proposals ahead of them making it to stage 3 and beyond (once a proposal gets to stage 3, it's likely to make it into the standard) but it's a really nice way to try new features.</p>
<h2>ES6?</h2>
<p>The infamous renaming of ES6 to ES2015 made no sense at the time, and lead more to confusion than anything else. However, now we have ES2016 in the works it makes much more sense to stick with the yearly naming than "ES6", which becomes very ambigious given "ES2015" and "ES2016". I will also be making an effort to avoid "ES7" as a term and prefer "ES next" or "ES2017 and beyond".</p>
<h2>Conclusion</h2>
<p>ES2015 was a huge big bang release that provided equal parts excitement and confusion. Once we move past that the new yearly release cycle will make it much less overwhelming to keep up to date with the latest version of JavaScript and I'm excited to see that happen.</p>
Misconceptions of Tooling in JavaScript2016-02-24T00:00:00+00:00http://www.jackfranklin.co.uk/blog/the-react-webpack-tooling-problem/<p>I wrote back in 2015 about the <a href="http://javascriptplayground.com/blog/2015/10/state-of-frontend-tooling">state of front end tooling</a> and since that post it's continued to be a topic I follow with interest. I'm particularly interested in other people's perceptions of where the JS community is up to in terms of tooling and what people expect to be provided when they start working with a library.</p>
<p>A library that seems to see this problem most of any is React. I think <a href="http://twitter.com/scott_riley">Scott Riley</a> put this best:</p>
<blockquote class="twitter-tweet" data-lang="en-gb"><p lang="en" dir="ltr"><a href="https://twitter.com/Jack_Franklin">@Jack_Franklin</a> People need to talk about this more; React is becoming synonymous with ‘spending a week in Webpack before you write any code’</p>— Scott ☠ (@scott_riley) <a href="https://twitter.com/scott_riley/status/697833161292701697">February 11, 2016</a></blockquote>
<script async="" src="http://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>What I struggle to understand most is <em>why</em> there is an expectation that React should provide (or be easy) to get working very straightforwardly. I suspect this is partly because React has always been written using JSX and hence some form of transformation has always been required, even if you avoid using React's ES2015 <code>class</code> syntax in favour of <code>React.createClass</code>.</p>
<p>Additionally developers fairly new to React often have this misconception that they must set up a project using Webpack with hot reloading, file watching, ES2015 and so on. Don't get me wrong, Webpack is a fantastic tool and I love working in a project with hot reloading and all the extra developer features, but there's absolutely nothing wrong with working on a project that makes you have to refresh the page manually! Particularly when starting out with a new ecosystem, setting all that extra stuff up at first is only going to lead to frustration. Focus on writing the JavaScript, and add in the developer functionality you need as you feel more comfortable in the environment.</p>
<h2>Getting started with React</h2>
<p>To try to demonstrate how this tooling fascination is mostly avoidable when starting out, I want to show how I would set up a React project if someone new to the library wanted to get up and running and have a play around.</p>
<p>In the past I would have done this by dropping Babel into an HTML file as a <code>script</code> tag - something that would mean we could get started with no <code>npm</code> required - but Babel 6 removed that functionality which means we do have to dive into Node land.</p>
<p>Firstly I'd set up an <code>index.html</code> file that loads React, React DOM and then a JavaScript file that Babel will generate for us.</p>
<pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>My React App<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>app<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://fb.me/react-0.14.7.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://fb.me/react-dom-0.14.7.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>bundle.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre>
<p>I'd then create a folder <code>src</code>, and create <code>src/app.js</code>. Note that there's no ES2015 modules or any of that, we're just creating all our components globally <em>for now</em>. I'm focusing on getting up and running with a React project quickly and with as little friction as possible. Once the person gets more comfortable we could layer in additional functionality - starting probably with CommonJS modules.</p>
<p><code>src/app.js</code> is a straight forward component and then the <code>ReactDOM</code> call:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> App <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">createClass</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token function-variable function">render</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>Hello World<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br>ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token operator"><</span>App <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'app'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Now we need to install the Babel CLI tool and run it on the files in the <code>src</code> directory to produce <code>bundle.js</code>. First I'd install <code>babel-cli</code> and <code>babel-preset-react</code> locally. I always install CLI tools locally such that different projects are able to use different versions of tools if they need.</p>
<p>Before doing the install I'd first run <code>npm init -y</code> to create a <code>package.json</code> for us.</p>
<pre><code>npm install --save-dev babel-cli babel-preset-react
</code></pre>
<p>Finally, we can compile our files by calling <code>./node_modules/.bin/babel</code>:</p>
<pre><code>./node_modules/.bin/babel --presets babel-preset-react src --out-file bundle.js
</code></pre>
<p>And then we <em>don't even need a file server</em> to run our app - simply opening <code>index.html</code> in the browser does the trick.</p>
<p><img src="https://i.imgur.com/Galeap0.jpg" alt=""></p>
<p>At this point we could stop now and tell the developer that every time they change their code they need to rerun the above command, but we can do so much better than that.</p>
<p>Firstly, let's move this call into a <code>package.json</code> script, which has two benefits:</p>
<ul>
<li>we can run it more easily with <code>npm run <name></code></li>
<li><code>npm</code> will look in <code>./node_modules/.bin</code> for us, so we can shorten the command a little</li>
</ul>
<pre class="language-json"><code class="language-json"><span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token property">"babel"</span><span class="token operator">:</span> <span class="token string">"babel --presets babel-preset-react src --out-file bundle.js"</span><br><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>Now <code>npm run babel</code> will get our app built. Babel's CLI also provides a <code>--watch</code> flag, which will watch the files for changes and recompile them for us, so we can tack that onto the end of our command to get file watching sorted too:</p>
<pre class="language-json"><code class="language-json"><span class="token property">"babel"</span><span class="token operator">:</span> <span class="token string">"babel --presets babel-preset-react src --out-file bundle.js --watch"</span></code></pre>
<p>And finally if we wanted to avoid doing the manual page refreshes we could look to <a href="https://github.com/tapio/live-server">live-server</a>, a great <code>npm</code> package that provides us with live reloading out the box. It's important to note that this is entirely optional though, and I probably wouldn't do this immediately for someone brand new - having to manually refresh is no huge deal.</p>
<pre><code>npm install --save-dev live-server
</code></pre>
<p>And now I can add this as another <code>package.json</code> script:</p>
<pre class="language-json"><code class="language-json"><span class="token property">"live-server"</span><span class="token operator">:</span> <span class="token string">"live-server --port=3004"</span></code></pre>
<p>And with that I can run <code>npm run live-server</code> to get my app running locally and being reloaded for me when files change.</p>
<h2>Conclusion</h2>
<p>Is the above what I'd recommend for someone new to a library wanting to get started? Yes. Is it what I'd recommend for a very experienced JS developer working on a large app? No. The key takeaway from this blog post is that you can <strong>layer tools and functionality</strong> as you get more comfortable with the tools and the ecosystem you're working with. Whilst I've used React as the example in this post this applies more generally across the board with any fairly modern JS library (with the exception of Ember and Ember CLI).</p>
<p>You should start with nothing, and work your way up, rather than jumping in right at the deep end with some complex boilerplate project. Boilerplates are great if you're familiar with the environment, but a nightmare for a beginner. Taking time to understand exactly what the tools are doing and why we need them will give a greater understanding and appreciation. By introducing beginners with less complex tools we keep the barrier to entry low and hopefully their enjoyment of the language and libraries high.</p>
<p>Finally, yes our tooling can get better and we can definitely make improvements to keep developers happier and more productive. If you're jumping into a complex React + ES2015 + JSX + whatever else environment, you have to be prepared to deal with the occasional rough edge and tool problem.</p>
ReactJS workshops in London2016-02-26T00:00:00+00:00http://www.jackfranklin.co.uk/blog/react-workshops-london/<p>If you've ever been interested in learning more about React and getting to grips with the framework then I have some good news for you! I've teamed up with <a href="http://www.whiteoctoberevents.co.uk/">White October Events</a> to run two one day ReactJS workshops in London.</p>
<p>These workshops will be a great chance for you to dive into React with a tonne of hands on exercises (you'll be writing lots of code!) covering not only the core concepts of React but some of the most popular libraries, including Redux and React Router.</p>
<p>In addition we'll look at ES2015, Babel, Webpack and more as we dive into building complex applications with the React ecosystem.</p>
<p>Tickets will cost £299 which includes lots of refreshements and lunch. The workshops are being run on two dates:</p>
<ul>
<li><a href="http://www.whiteoctoberevents.co.uk/event/reactjs-workshop-march-16/">21st March 2016</a></li>
<li><a href="http://www.whiteoctoberevents.co.uk/event/reactjs-workshop-june-16/">10th June 2016</a></li>
</ul>
<p>If you have any questions about the content please feel free to email me: jack at pusher dot com.</p>
Using ReactJS without Webpack2016-04-25T00:00:00+00:00http://www.jackfranklin.co.uk/blog/react-no-webpack/<p>Webpack is a fantastic tool but there's no doubting that as a newcomer to React it's can be a challenge to get started with. I've met numerous developers who have been stumped in their efforts to learn React because they fell into the rabbit hole of Webpack and its configuration.</p>
<p>To demonstrate how you can focus on learning React without needing ES2015, JSX compilation or Webpack I built a sample repository that you can find <a href="https://github.com/jackfranklin/react-no-webpack-required">on GitHub</a>.</p>
<p>The repository uses Gulp to concatenate and minify your files into one, and doesn't do anything to compile ES2015 or JSX. If you've wanted to focus on React without anything else to get in your way, give it a try.</p>
<p>To get started, clone the repository and run <code>npm install</code> to get Gulp setup. You can then run <code>gulp build</code> to get your app running and <code>gulp serve</code> to run a live-server locally, which will refresh when your code changes. Running <code>gulp watch</code> will rebuild your application everytime a file changes.</p>
<h2>What, no JSX?</h2>
<p>JSX is great and I like using it on projects; but it's another step that can get in the way of focusing on React concepts when getting started. Because JSX gets converted into <code>React.createElement</code> calls, we can just use that directly instead:</p>
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>Foo name<span class="token operator">=</span><span class="token string">'jack'</span> <span class="token operator">/</span><span class="token operator">></span><br><span class="token comment">// equivalent:</span><br>React<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span>Foo<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'jack'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br><span class="token operator"><</span>p<span class="token operator">></span><br> <span class="token operator"><</span>span<span class="token operator">></span>Hello<span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><br><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br><span class="token comment">// equivalent:</span><br>React<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> React<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'span'</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token string">'Hello'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>However, this gets pretty verbose quickly, so I included in the repository a global function <code>h</code> that is a shorthand:</p>
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>Foo name<span class="token operator">=</span><span class="token string">"jack"</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">;</span><br><span class="token comment">// equivalent:</span><br><span class="token function">h</span><span class="token punctuation">(</span>Foo<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br><span class="token operator"><</span>p<span class="token operator">></span><br> <span class="token operator"><</span>span<span class="token operator">></span>Hello<span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><br><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br><span class="token comment">// equivalent:</span><br><span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token function">h</span><span class="token punctuation">(</span><span class="token string">'span'</span><span class="token punctuation">,</span> <span class="token string">'Hello'</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>A natural improvement to this repo would be to add JSX support, but I'll leave that as an exercise to the reader.</p>
<h2>No Modules</h2>
<p>Because this repo avoids ES2015 and any transpilation there is no module system available. Instead we just have a global variable, <code>app</code>, that contains all of our application. This isn't great, but storing everything in one global variable isn't particularly bad practice, and it means that no module system is required.</p>
<h2>No dependency management</h2>
<p>All dependencies are stored in <code>vendor</code> and commited into Git, to avoid any package management confusions or overhead.</p>
<h2>Should I use this in my big production React app?</h2>
<p>No, you shouldn't. Tools like Webpack, ES2015 / JSX transpilation and dependency management are incredibly useful as your app scales, but they are not needed when you're working on a smaller app. If you're building a small React application for learning I recommend starting with my repository and then experimenting with adding ES2015, JSX, Webpack and so on as you get more familiar with the ecosystem.</p>
Better data fetching with RemoteDataJS2016-06-21T00:00:00+00:00http://www.jackfranklin.co.uk/blog/remote-data-js/<p>One of the things that most of us have to do in our applications is fetch data from a remote data source, typically an API that gives us back some JSON data. This is something that's pretty straight forward, particularly with the newer <code>fetch</code> API, and I'm willing to bet most developers would be quite happy writing the code to do this.</p>
<p>However, something that's less obvious is how to deal with all the different states that a piece of remote data can be in. I reckon there's four distinct states:</p>
<ul>
<li>Not requested: no request has yet been made</li>
<li>Pending: a request has been made, but no data has been returned</li>
<li>Succeeded: a request has succeeded, and we have some data back</li>
<li>Failed: a request was made, it went wrong, and we have an error</li>
</ul>
<p>Dealing with all of those states in your application is tricky, and it's also dull. No one wants to deal with the error case, and writing the logic to show a spinner when a request is pending is really dull.</p>
<p>Most of the time people will model their data with a flag that states if the request is loading or not, and then a <code>data</code> key that is undefined initially and is populated when the request succeeds:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br> <span class="token literal-property property">loading</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token keyword">undefined</span><br><span class="token punctuation">}</span><br><br><span class="token comment">// later</span><br><br><span class="token punctuation">{</span><br> <span class="token literal-property property">loading</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>But then how do you deal with an error that you might want to keep around and store?</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br> <span class="token literal-property property">loading</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span><br> <span class="token literal-property property">data</span><span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">,</span><br> <span class="token literal-property property">error</span><span class="token operator">:</span> <span class="token operator">...</span><br><span class="token punctuation">}</span></code></pre>
<p>Suddenly your state has three keys on it that are all tightly related. In his post <a href="http://blog.jenkster.com/2016/06/how-elm-slays-a-ui-antipattern.html">"How Elm slays an antipattern"</a>, Kris Jenkins describes how Elm's type system enables you to present data using one type, which he calls <code>RemoteData</code>, that encapsulates every state that a request can be in. Today I'm announcing my efforts on recreating this in JavaScript with my new library, <a href="https://github.com/jackfranklin/remote-data-js">RemoteDataJS</a>.</p>
<p>## RemoteDataJS</p>
<p>RemoteDataJS is a single object that encapsulates all of the logic and states involved in an HTTP request. You create it and tell it what URL it should make a request to (no request will be made until you tell it to, though):</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> githubPerson <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RemoteData</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token function-variable function">url</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">username</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.github.com/users/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>username<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token function-variable function">onChange</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">newPerson</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token operator">...</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>In addition, you define an <code>onChange</code> that will be called with a <em>new instance of <code>RemoteData</code></em> every time the state changes.</p>
<p>To make a request, you call <code>fetch</code>, passing in any arguments needed to create the URL:</p>
<pre class="language-js"><code class="language-js">githubPerson<span class="token punctuation">.</span><span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'jackfranklin'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Your <code>onChange</code> callback will then be called twice, first as the request transitions from the starting state of <code>NOT_ASKED</code> to <code>PENDING</code>, and then again from <code>PENDING</code> to <code>SUCCESS</code> (or, potentially <code>FAILURE</code> instead).</p>
<p>The <code>fetch</code> call also returns a promise, and will throw if it fails:</p>
<pre class="language-js"><code class="language-js">githubPerson<br> <span class="token punctuation">.</span><span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'jackfranklin'</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token comment">/*success!*/</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token comment">/*fail!*/</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2>Avoiding Mutation</h2>
<p>Every time your <code>onChange</code> function is called, or you chain to the promise returned by <code>fetch</code>, the argument that is passed to your function is a <strong>brand new <code>RemoteData</code> instance</strong>. Rather than mutate the existing instance, <code>RemoteData</code> constructs a new instance of itself, copying all its callback functions and information across, but defining the new state. This means nothing gets mutated and you can avoid weird mutation bugs.</p>
<h2>With React</h2>
<p>Because we avoid mutation and provide an <code>onChange</code> function for you to listen to data changing, it's easy to tie <code>RemoteData</code> in with React. First, define an instance of <code>RemoteData</code> as state:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">Person</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span><br> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">githubPerson</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">RemoteData</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token function-variable function">url</span><span class="token operator">:</span> <span class="token parameter">username</span> <span class="token operator">=></span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">https://api.github.com/users/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>username<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br> <span class="token function-variable function">onChange</span><span class="token operator">:</span> <span class="token parameter">githubPerson</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> githubPerson <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br> <span class="token operator">...</span><br><span class="token punctuation">}</span></code></pre>
<p>Note how rather than have multiple keys on our state we can wrap all the logic up in an instance of <code>RemoteData</code>. In the <code>onChange</code> call we simply set the state to have the new remote data instance.</p>
<p>We can then define a <code>render</code> function that takes our <code>githubPerson</code> and returns the right response based on the state:</p>
<pre class="language-js"><code class="language-js"><span class="token function">renderGithubPerson</span><span class="token punctuation">(</span><span class="token parameter">person</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>person<span class="token punctuation">.</span><span class="token function">isNotAsked</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token string">"No Request Made"</span><span class="token punctuation">;</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>person<span class="token punctuation">.</span><span class="token function">isPending</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token string">"Loading data from GitHub"</span><span class="token punctuation">;</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>person<span class="token punctuation">.</span><span class="token function">isSuccess</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Name: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>person<span class="token punctuation">.</span>data<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>person<span class="token punctuation">.</span><span class="token function">isFailure</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token string">"Failure"</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre>
<p>And finally we can bind a <code>click</code> event to tell the instance to make the request:</p>
<pre><code>click() {
this.state.githubPerson.fetch('jackfranklin');
}
</code></pre>
<p><a href="http://jsbin.com/yefuwapuja/1/edit?js,output">You can see this example on JSBin</a>.</p>
<h2>Using RemoteDataJS</h2>
<p>I hope the above gives you some context and reasoning about why I think <code>RemoteDataJS</code> can clear up your data fetching logic and make it easier for you to deal with requests across all states that they can find themselves in.</p>
<p>If you want to start using it you can <a href="https://github.com/jackfranklin/remote-data-js">check out the GitHub repository</a> to find more thorough documentation and information. RemoteDataJS is available as <code>remote-data-js</code> on npm for you to install. I'd love to hear your feedback, bug reports and anything else, so please feel free to raise an issue.</p>
Screencast: Creating a React and Webpack Project2016-06-22T00:00:00+00:00http://www.jackfranklin.co.uk/blog/react-webpack-workflow-screencast/<p>Last week at the <a href="http://www.meetup.com/London-JavaScript-Community/events/227578573/">London JavaScript Community Meetup</a> I did a live coding presentation where I created a React project from scratch and configured Webpack to build my application. I also added hot loading to my development workflow and configured ES2015 and JSX support through Babel, along with building a production Webpack file too.</p>
<p>Today I recorded a screencast of me doing this presentation so you can view even if you weren't able to make it to the meetup. In it I do the following:</p>
<ul>
<li>Set up Webpack and the Webpack Dev Server.</li>
<li>Configure Webpack to transpile ES2015 and JSX through Babel.</li>
<li>Add the react-hot-loader plugin to enable hot reloading of React components.</li>
<li>Build a small counter application to demonstrate and take advantage of hot loading.</li>
<li>Create a production Webpack config that can bundle our application into production.</li>
</ul>
<iframe src="https://player.vimeo.com/video/171783550" width="630" height="394" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
<p><a href="https://vimeo.com/171783550">A React and Webpack Workflow</a> from <a href="https://vimeo.com/javascript">The JavaScript Playground</a> on <a href="https://vimeo.com/">Vimeo</a>.</p>
<p>You can find the repository containing all the code <a href="https://github.com/jackfranklin/react-hot-load-webpack-boilerplate">on GitHub</a>. Feel free to fork it or raise an issue if you come across problems.</p>
<p>In future videos I'll cover:</p>
<ul>
<li>Testing React using Node, JSDOM and Tape</li>
<li>Clever bundling using Webpack to create multiple files</li>
<li>Quicker rebuilds with the Webpack DLL plugin</li>
<li>And whatever else you'd like to see :)</li>
</ul>
Setting up CSS Modules with React and Webpack2016-07-18T00:00:00+00:00http://www.jackfranklin.co.uk/blog/css-modules-webpack-react/<p>One of the biggest problems that developers face with CSS is that CSS is global. Each CSS class gets exposed globally and it’s very easy to inadvertently break a piece of your site when editing or adding CSS for a new feature. In an era where many developers are building websites as components with a framework such as React, CSS is an even bigger problem.</p>
<p>CSS Modules allow us to write <em>scoped</em> CSS, just like a variable in JavaScript or any other programming language. We can write CSS for a component and be certain that it won’t leak into other components. You can also have confidence that adding a new component to your application won’t interfere with any other components on the system.</p>
<p>CSS Modules are a fantastic idea and play particularly nicely with React, but at the time of writing there isn’t a good resource for getting started and setting up React, CSS Modules and Webpack to build everything correctly. In this article I’ll show you how I took a React application and added CSS modules, which Webpack plugins I used for this, and an example of CSS modules in action. If you’d like to get this running yourself you’ll find all the <a href="https://github.com/jackfranklin/react-css-modules-webpack">code available on GitHub</a>. We’ll also look at how we can generate a production <code>bundle.css</code> file which has all our CSS together and fully minified.</p>
<h2>The goal</h2>
<p>What we’re aiming for is to be able to write CSS on a per component basis. That is, for each component we have a corresponding <code>component.css</code> file that will define the CSS for that component.</p>
<p>For a component <code>App.js</code>, we also have <code>app.css</code>:</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.app p</span> <span class="token punctuation">{</span><br> <span class="token property">color</span><span class="token punctuation">:</span> blue<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre>
<p>And then in the component we can import this CSS file, as if it was a JavaScript module:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> styles <span class="token keyword">from</span> <span class="token string">'./app.css'</span><span class="token punctuation">;</span></code></pre>
<p>Finally, we can reference the class name in our CSS file:</p>
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>div className<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">.</span>app<span class="token punctuation">}</span><span class="token operator">></span><br> <span class="token operator"><</span>p<span class="token operator">></span>This text will be blue<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></code></pre>
<p>None of this works out of the box, but we’ll use Webpack with a couple of additional loaders to get this working. The beauty is that the actual class name in the generated CSS file won’t be <code>.app</code> as above, but <code>.app-[some-hash]</code>. By adding a hash to each class name it’s guaranteed that each CSS class declaration is unique (the hash is based on the contents - so if two classes clash it’s because they have the same styles).</p>
<h2>Webpack Loaders</h2>
<p>To set this up we’re going to dive into the wonderful world of Webpack loaders. These can be confusing at first, but in essence a Webpack loader is a plugin for Webpack that can apply extra transformations or manipulate files before they are bundled.</p>
<p>There’s two we need to use:</p>
<ul>
<li><a href="https://github.com/webpack/style-loader"><code>style-loader</code></a> is a Webpack loader that can load some CSS and inject it into the document via a <code><link></code> tag.</li>
<li><a href="https://github.com/webpack/css-loader"><code>css-loader</code></a> is the loader that can parse a CSS file and apply various transforms to it. Crucially it has a CSS Modules mode that can take our CSS and hash the classes as mentioned above.</li>
</ul>
<p>In the project that I’m adding CSS Modules to we already have one loader defined for our JavaScript:</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">module</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">loaders</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span><br> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.js$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span><br> <span class="token literal-property property">loaders</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'react-hot'</span><span class="token punctuation">,</span> <span class="token string">'babel'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token literal-property property">include</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'src'</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>This configures every JavaScript file to be run through the <code>react-hot</code> loader, which configures hot module loading, and <code>babel</code>, which will transpire ES2015 features and the JSX syntax.</p>
<p>What we need to do is add another configuration for <code>.css</code> files where we first configure <code>style-loader</code>, and then <code>css-loader</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.css$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'style-loader'</span><br><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.css$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'css-loader'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">query</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">modules</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br> <span class="token literal-property property">localIdentName</span><span class="token operator">:</span> <span class="token string">'[name]__[local]___[hash:base64:5]'</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>First we configure the <code>style-loader</code>, which needs no extra configuration, so we’re set. Then we have to configure <code>css-loader</code>. The important bit to this is the <code>query</code> object, which defines two properties:</p>
<ul>
<li><code>modules: true</code> turns on the CSS modules mode</li>
<li><code>localIdentName: '[name]__[local]___[hash:base64:5]'</code> defines the structure of the generated CSS class should be. You don’t need to worry too much about this, other than knowing that this maps to the generated output. For example, our CSS from above with the class of <code>app</code> will end up as <code>app__app___2x3cr</code> in the browser.</li>
</ul>
<h2>Running Webpack</h2>
<p>With the above changes to our Webpack configuration we’re done! You can now run Webpack (if you’re running the <a href="https://github.com/jackfranklin/react-css-modules-webpack">example repository</a>, run <code>npm start</code> to fire up the Webpack dev server) and have your CSS modules converted and working for you in the browser.</p>
<p>If you’re using the dev server you’ll also note that the CSS is automatically updated when you change without a hard refresh in the browser which is useful during development.</p>
<h2>Tidying up the Webpack configuration</h2>
<p>One thing that irks me about the Webpack configuration in its current state is the fact that we have to configure loaders for <code>.css</code> twice - once for the style loader, and once for the css loader. I’d much rather group these both up into one. However, once you configure multiple loaders you can’t pass in the <code>query</code> object as we did above, and must use Webpack’s string configuration. In our case if we did that, our configuration would look like so:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.css$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'style-loader!css-loader?modules=true&localIdentName=[name]__[local]___[hash:base64:5]'</span><br><span class="token punctuation">}</span></code></pre>
<p>I think this is pretty messy and much harder to follow.</p>
<p>Thankfully I found <a href="https://github.com/jsdf/webpack-combine-loaders">webpack-combine-loaders</a> which enables us to use the <code>query</code> object syntax to configure a loader, but without having to repeat the <code>test: /\.css$/</code> line. Using this module our configuration becomes:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.css$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token function">combineLoaders</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br> <span class="token punctuation">{</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'style-loader'</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'css-loader'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">query</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">modules</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br> <span class="token literal-property property">localIdentName</span><span class="token operator">:</span> <span class="token string">'[name]__[local]___[hash:base64:5]'</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">]</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">]</span></code></pre>
<p>I think this is cleaner because it’s clearer that we’re using both <code>style-loader</code> and <code>css-loader</code> on the same file type.</p>
<h2>Deploying to Production</h2>
<p>The final step is to update the production Webpack build to parse all our CSS and generate an outputted CSS file that contains all our CSS. We don’t want to have our CSS injected through Webpack in production, and we don’t want the CSS module transformations to run in the browser; instead we want to simply deploy a generated stylesheet that contains all our styles.</p>
<p>To do this we can use the <a href="https://github.com/webpack/extract-text-webpack-plugin"><code>extract-text-plugin</code></a> for Webpack that will take all files that match a regular expression (in our case we’ll look for CSS files as we did previously) and bundle them all into one file. We can also run them through the CSS Modules transform just like we did in our development config.</p>
<p>To get started we first need to install the plugin:</p>
<pre><code>npm install extract-text-webpack-plugin —save-dev
</code></pre>
<p>Then we need to configure the plugin. First we’ll add an entry to the <code>plugins</code> key in the Webpack configuration:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// at top of file</span><br><span class="token keyword">var</span> ExtractTextPlugin <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'extract-text-webpack-plugin'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br><span class="token comment">// in the webpack config</span><br><span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token keyword">new</span> <span class="token class-name">ExtractTextPlugin</span><span class="token punctuation">(</span><span class="token string">'styles.css'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token operator">...</span><br><span class="token punctuation">]</span></code></pre>
<p>This configures the plugin to output to <code>styles.css</code>.</p>
<p>Then we will configure the module loader again to find all our CSS files and bundle them together. The configuration here looks similar, we call <code>ExtractTextPlugin.extract</code>. This takes multiple arguments, where each argument is an individual loader to pass. We first pass <code>style-loader</code>, and then use <code>combineLoaders</code> again to generate a string version of the configuration for <code>css-loader</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">module</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token operator">...</span><span class="token punctuation">,</span><br> <span class="token literal-property property">loaders</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span><br> <span class="token comment">// JS loader config</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.css$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> ExtractTextPlugin<span class="token punctuation">.</span><span class="token function">extract</span><span class="token punctuation">(</span><br> <span class="token string">'style-loader'</span><span class="token punctuation">,</span><br> <span class="token function">combineLoaders</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">{</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'css-loader'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">query</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">modules</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br> <span class="token literal-property property">localIdentName</span><span class="token operator">:</span> <span class="token string">'[name]__[local]___[hash:base64:5]'</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token operator">...</span><br><span class="token punctuation">}</span></code></pre>
<p>Now when we run Webpack with this configuration we’ll have a JavaScript and a CSS file that we can use in production with CSS Modules fully transformed.</p>
<h2>Conclusion</h2>
<p>There’s a few final pieces we could do to tidy up, but I’m going to leave those as exercises for the reader. The main issue now is that we’re duplicating configuration for the CSS Loader across our development Webpack setup and our production Webpack setup. You might consider extracting a file that contains that configuration, rather than duplicating it.</p>
<p>CSS Modules are a great way to organise your CSS in a component based system. Here I’ve used them with React but you’ll notice that none of the code in this tutorial is React specific - this approach can be used with other frameworks with no extra effort.</p>
<p>If you’d like to use this tutorial as a starting point, don’t forget that you can <a href="https://github.com/jackfranklin/react-css-modules-webpack">find the repository on GitHub</a>, and please get in touch if you have any questions. You can find more information on the <a href="https://github.com/css-modules/css-modules">CSS Modules repository</a> and Glenn Maddern’s <a href="http://glenmaddern.com/articles/css-modules">“CSS Modules: Welcome to the Future”</a> blog post.</p>
Using the HTML Webpack Plugin for generating HTML files2016-07-21T00:00:00+00:00http://www.jackfranklin.co.uk/blog/webpack-html-plugin/<p>Whilst most people use Webpack primarily for their JS scripts, there's always one final part of deploying that is forgotten: the HTML. In production we often have extra scripts we want to insert (such as Google Analytics) and also we want to insert a <code>script</code> tag to the minified JavaScript and CSS, which probably will have a different filename each time as we generate files with a hash on the end.</p>
<p>Recently I came across the <a href="https://github.com/ampedandwired/html-webpack-plugin">html-webpack-plugin</a> and was amazed at how easy it was to add to an application to have all my HTML generated for me too, both in development with the Webpack Dev Server and in production. Following on from my <a href="http://www.jackfranklin.co.uk/blog/2016/07/css-modules-webpack-react/">last post about CSS Modules with Webpack</a>, today I'll take that codebase and automate the HTML side of deploys using the HTML Webpack plugin.</p>
<h2>Configuring for Production</h2>
<p>The first step is to install the plugin, which is done through npm:</p>
<pre><code>npm install html-webpack-plugin --save-dev
</code></pre>
<p>Then, to configure our production deploys, I'll edit my <code>webpack.config.prod.js</code> file, first by requiring the plugin:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> HtmlWebpackPlugin <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'html-webpack-plugin'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Next I'll add an entry to the <code>plugins</code> array where I instantiate the plugin with two properties:</p>
<ul>
<li><code>template</code> defines the template that the plugin will use to generate the HTML. I'll create this shortly.</li>
<li><code>inject: body</code> tells the plugin to inject any JavaScript into the bottom of the page, just before the closing <code></body></code> tag, rather than into the <code><head></code>.</li>
</ul>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token operator">...</span><br> <span class="token keyword">new</span> <span class="token class-name">HtmlWebpackPlugin</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">template</span><span class="token operator">:</span> <span class="token string">'index.template.ejs'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">inject</span><span class="token operator">:</span> <span class="token string">'body'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">]</span><span class="token punctuation">,</span></code></pre>
<p>That's the only configuration we need! The plugin will automatically include any files that you're using Webpack to generate. It supports both JS and CSS files so it's a great fit with our CSS Modules project.</p>
<p>Finally I need to create my template. This uses the <a href="http://www.embeddedjs.com/">EJS</a> templating system, which is useful if you need to pass any values into the plugin that should be outputted into the HTML. In our case we don't though, so our template looks like so:</p>
<pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Content-type<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/html; charset=utf-8<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Sample App<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>root<span class="token punctuation">'</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre>
<p>That's it! The resources generated from the bundle will be placed into the HTML at the right points. I can now run <code>webpack --config webpack.config.prod.js</code> and see that three files are generated; my JS, my CSS and now an <code>index.html</code> too.</p>
<p>The generated HTML file looks like so:</p>
<pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Content-type<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/html; charset=utf-8<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Sample App<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>styles-4585896ecd058603fc99.css<span class="token punctuation">"</span></span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>root<span class="token punctuation">'</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>javascripts-4585896ecd058603fc99.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre>
<p>As you can see, the CSS and the JS were placed into the file.</p>
<h3>Configuring with Webpack Dev Server</h3>
<p>Rather than have a template that's used for my production HTML and a static file I use in development, I'd rather have the same template used for both, to stop my HTML getting out of sync between environments. You might prefer to keep them seperate, but for most of my projects I want the same HTML structure, and I'm happy to trust the HTML Webpack Plugin to insert the right scripts into the right place.</p>
<p>I can edit <code>webpack.config.dev.js</code> to use the plugin:</p>
<pre class="language-js"><code class="language-js"><span class="token operator">...</span> other requires here<br><span class="token keyword">var</span> HtmlWebpackPlugin <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'html-webpack-plugin'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br>module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token operator">...</span><span class="token punctuation">,</span><br> <span class="token literal-property property">entry</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token operator">...</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token literal-property property">output</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">path</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">'dist'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token literal-property property">filename</span><span class="token operator">:</span> <span class="token string">'bundle.js'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">publicPath</span><span class="token operator">:</span> <span class="token string">'/'</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token keyword">new</span> <span class="token class-name">webpack<span class="token punctuation">.</span>HotModuleReplacementPlugin</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token keyword">new</span> <span class="token class-name">HtmlWebpackPlugin</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">template</span><span class="token operator">:</span> <span class="token string">'index.template.ejs'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">inject</span><span class="token operator">:</span> <span class="token string">'body'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token literal-property property">module</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>This is identical to before, but there's one change to the configuration that is easier to miss: I've changed <code>output.publicPath</code> from <code>/static</code> to simply <code>/</code>. This means that the dev server will generate the files at the root, which means I can load up <code>localhost:3000</code> and see my generated HTML without having to visit <code>/static/index.html</code>. It's a little messy to keep all my generated JavaScript and CSS at this root level, but I don't mind because I'm using the dev server and the files aren't ever actually written to disk. If you wanted to keep all the files generated in a folder, you can set <code>publicPath</code> to <code>/static</code> (or whatever you'd like) and use that URL when working on your application.</p>
<p>Now, when I fire up the dev server, I see the generated HTML and everything works as before. Any time I need to change my HTML I can do so in the template and have my development and production HTML environments kept perfectly in sync!</p>
<p>If you'd like to check out this project in action you can see the <a href="https://github.com/jackfranklin/react-css-modules-webpack">react-css-modules-webpack</a> repository where I've added all the functionality described above.</p>
Migrating to Webpack 22016-10-21T00:00:00+00:00http://www.jackfranklin.co.uk/blog/moving-to-webpack-2/<p><a href="http://webpack.js.org/">Webpack</a> is on the verge of having its latest major version released, and it's expected to drop very soon. However, the main thing holding the release back is documentation, and the code is mostly written. I recently took the time to update our work project from Webpack 1 to 2, and thought I'd document the steps taken for anyone else who wants to make the move.</p>
<p>You can also check out the <a href="https://webpack.js.org/guides/migrating/">Migrating from V1 to V2 guide on the Webpack documentation</a>.</p>
<h2>Install Webpack 2</h2>
<p>The first thing to do is install the latest version. Because it's not a stable release, you have to specify the exact beta version you'd like. At the time of writing it's 2.1.0-beta.25:</p>
<pre><code>npm install --save-dev webpack@2.1.0-beta.25
</code></pre>
<p>If you're using any other Webpack plugins, be aware that they might need updating. For example, the <a href="https://github.com/webpack/extract-text-webpack-plugin">Extract Text Plugin has a v2 in beta also</a>:</p>
<pre><code>npm install --save-dev extract-text-webpack-plugin@2.0.0-beta.4
</code></pre>
<h2><code>module.loaders</code> => <code>module.rules</code></h2>
<p>This is not a breaking change because <code>module.loaders</code> will continue to be supported, but in the future it will be deprecated in favour of <code>module.rules</code>. This is just an easy renaming step.</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// before</span><br><span class="token literal-property property">module</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">loaders</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token operator">...</span><span class="token punctuation">]</span><br><span class="token punctuation">}</span><br><br><span class="token comment">// after</span><br><span class="token literal-property property">module</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">rules</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token operator">...</span><span class="token punctuation">]</span><br><span class="token punctuation">}</span></code></pre>
<h2><code>resolve.modulesDirectories</code> => <code>resolve.modules</code></h2>
<p>Another renaming step, the <code>resolve</code> options have been renamed:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// before</span><br><span class="token literal-property property">resolve</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">modulesDirectories</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token operator">...</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><br><br><span class="token comment">// after</span><br><span class="token literal-property property">resolve</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">modules</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token operator">...</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span></code></pre>
<h2>No <code>webpack.optimize.OccurenceOrderPlugin</code></h2>
<p>It's now included by default, so there is no need to have this in our config.</p>
<h2>Configuring loaders</h2>
<p>At work we're using postcss and <a href="https://github.com/postcss/postcss-loader">postcss-loader</a> to load our CSS through Webpack. The loader used to expect a top level <code>postcss</code> key in the Webpack config. As of Webpack 2 this is no longer allowed; we can instead define an <code>options</code> key when we configure the loader. This replaces the <code>query</code> option from Webpack 1. Any plugin that looked for top level configuration will have to be swapped to this style.</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// before, in Webpack top level</span><br><span class="token literal-property property">postcss</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token operator">...</span><br><span class="token punctuation">}</span><br><br><span class="token comment">// after</span><br><span class="token literal-property property">module</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">rules</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span><br> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.scss$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span><br> <span class="token literal-property property">use</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'postcss-loader'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token operator">...</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token string">'sass-loader'</span><br> <span class="token punctuation">]</span><br> <span class="token punctuation">}</span><span class="token punctuation">]</span><br><span class="token punctuation">}</span></code></pre>
<h2>ExtractTextPlugin changes</h2>
<p>The above change to loader configuration also makes it way easier to configure multiple loaders; previously it would only be possible to pass an array of loaders in string form to some plugins, such as <code>ExtractTextPlugin</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// Webpack 1</span><br>ExtractTextPlugin<span class="token punctuation">.</span><span class="token function">extract</span><span class="token punctuation">(</span><br> <span class="token string">'style-loader'</span><span class="token punctuation">,</span><br> <span class="token string">'css-loader!postcss-loader!sass-loader'</span><br><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>This quickly got very hard to work with if you had to pass options:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// Webpack 1</span><br>ExtractTextPlugin<span class="token punctuation">.</span><span class="token function">extract</span><span class="token punctuation">(</span><br> <span class="token string">'style-loader'</span><span class="token punctuation">,</span><br> <span class="token string">'css-loader?modules-true!postcss-loader!sass-loader'</span><br><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>But now Webpack 2 can deal with arrays of objects to configure loaders. We can replace the above with:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// Webpack 2</span><br><span class="token keyword">var</span> loaders <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'css-loader'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">options</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">modules</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'postcss-loader'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> <span class="token string">'sass-loader'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">]</span><span class="token punctuation">;</span></code></pre>
<p>Whereas in Webpack 1 we used the key <code>query</code> for configuring loaders, we now use <code>options</code>. <code>ExtractTextPlugin</code> can now take this array, rather than only allowing the string form:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// Webpack 2</span><br>ExtractTextPlugin<span class="token punctuation">.</span><span class="token function">extract</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">fallbackLoader</span><span class="token operator">:</span> <span class="token string">'style-loader'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">loader</span><span class="token operator">:</span> loaders<span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2>Stop Babel from compiling ES2015 modules</h2>
<p>Webpack 1 wasn't able to parse ES2015 modules, so Babel would convert them into CommonJS. Webpack 2 can parse ES2015 modules, and is able to eliminate dead code based on which modules are used, so it's recommended that you tell Babel not to convert modules into CommonJS. You can do this by changing your <code>.babelrc</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// before</span><br><span class="token string-property property">"presets"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"es2015"</span><span class="token punctuation">]</span><br><br><span class="token comment">// after</span><br><span class="token string-property property">"presets"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token punctuation">[</span><span class="token string">"es2015"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token string-property property">"modules"</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><br><span class="token punctuation">]</span></code></pre>
<p>We've seen a good file size saving by doing this, and hopefully this will continue to improve in the future!</p>
<h2>Fin</h2>
<p>Webpack 2 offers better performance, improved bundling and a much nicer experience when configuring it. Given that the code is so stable, despite its beta status, I highly recommend giving it a go on your projects when you can.</p>
Authoring and publishing JavaScript modules with Flow2017-01-04T00:00:00+00:00http://www.jackfranklin.co.uk/blog/npm-flowjs-javascript/<p><a href="https://flowtype.org/">Flow</a> is a static type checker for JavaScript which adds the ability to annotate our JavaScript code with extra information on what types we're expecting values to be, what types functions can return, and so on. Having done a lot of work in <a href="https://elm-lang.org/">Elm</a>, a language that is typed, I began to recently explore the popular options for adding types to JavaScript. Along with Flow there is also <a href="https://www.typescriptlang.org/">TypeScript</a>, which is very popular and used extensively in the Angular 2 community.</p>
<p>I started with Flow primarily because it's used a lot in the React community (unsurprising given Flow is a Facebook project) and it has built in knowledge of React and its types. Although we won't use Flow with React today, it's easy to do so and I'm sure that I'll cover it in a future blog post. This post <em>is not</em> me stating that I have a strong preference for Flow over TypeScript, or a post claiming Flow is better. I am just sharing my experience with Flow - so far it's been a very positive one.</p>
<h2>Writing Typed JavaScript</h2>
<p>To start with I needed an example project to work with; I picked <a href="https://github.com/jackfranklin/util-fns">util-fns</a>. <code>util-fns</code> is a small project I started working on that contains a bunch of tiny utility functions (much like Lodash or Underscore, but much smaller and less optimised!). It's primarily a dummy project for the sake of learning Flow and experimenting. I also chose this because it's a module that I have published to npm, and as such could explore how to publish the module in such a way that the types are not lost. This means any developers who run <code>npm install util-fns</code> can access the type information and be notified if they use the library with the one arguments, assume incorrect return types, and so on.</p>
<h3>Installing Flow</h3>
<p>To get started with Flow, I first installed it as a local dependency. You need the <code>flow-bin</code> package from npm:</p>
<pre><code>npm install --save-dev flow-bin
</code></pre>
<p>You could install this globally, but I like to have all project dependencies installed locally. This also covers you in the circumstance that you have different projects that want to use different versions of Flow.</p>
<p>You then need to run <code>./node_modules/.bin/flow init</code>.</p>
<p><strong>Note:</strong> I have the <code>./node_modules/.bin</code> directory on my <code>$PATH</code>, <a href="https://github.com/jackfranklin/dotfiles/blob/master/zsh/zshrc#L101">which you can find in my dotfiles</a>. This is <em>slightly</em> risky, as I could accidentally run any executable that's in that directory, but I'm willing to take that risk because I know what's installed locally and it saves a lot of typing!</p>
<p>By running <code>flow init</code> you'll create a <code>.flowconfig</code> file which will look like so:</p>
<pre><code>[ignore]
[include]
[libs]
[options]
</code></pre>
<p>Don't worry about the slightly odd syntax here, or the fact that it's largely empty. That config is more than enough for now - I've yet to really have to edit a Flow config - but if you need to there is <a href="https://flowtype.org/docs/advanced-configuration.html">extensive documentation on configuring Flow</a> on the Flow site.</p>
<p>By creating this file we're now able to run Flow and have it check our code. You can run <code>flow</code> now to see what happens!</p>
<pre><code>Launching Flow server for /Users/jackfranklin/git/flow-test
Spawned flow server (pid=30624)
Logs will go to /private/tmp/flow/zSUserszSjackfranklinzSgitzSflow-test.log
No errors!
</code></pre>
<p>The first thing you'll see is that Flow launches a server. This server runs in the background and allows you to incrementally check Flow code as you work. By running on a server, Flow can cache the state of your files and only recheck them when the contents change. This makes it really quick to run Flow on files as you're working. For times when you do want to just check your entire project you can run <code>flow check</code>, but in development you should always just run <code>flow</code>. This will connect to the Flow server (or start one if there isn't one running) and be much more efficient about checking only the files that have changed.</p>
<p>When you run Flow and see that you have no errors, that's because we don't actually have any code that Flow will check, yet! Flow is designed to be able to be dropped into an existing JavaScript project and not cause a heap of errors, so it only runs on files that have the following comment at the top of the page:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// @flow</span></code></pre>
<p>This means you can incrementally move files over to Flow, which is a big plus point for me. We're considering adding it to our large JS codebase at work and if we couldn't do it incrementally we wouldn't even be able to consider including it in the project.</p>
<h3>Stripping types with Babel</h3>
<p>One final piece of admin: Flow is only a type checker, it won't strip the types out of your code and produce JavaScript for production. To do this I recommend using the Babel plugin <a href="https://babeljs.io/docs/plugins/transform-flow-strip-types/"><code>transform-flow-strip-types</code></a>, which tells Babel to remove the types when you compile the code. We'll look at how we then deploy this code to npm later.</p>
<h3>Writing some Flow!</h3>
<p>We're now ready to write some code! Let's start with a <code>sum</code> function. It can take an array of numbers and will produce the sum of all of these numbers. Here's the JavaScript implementation I came up with:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">sum</span> <span class="token operator">=</span> <span class="token parameter">input</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> input<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> a <span class="token operator">+</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">export</span> <span class="token keyword">default</span> sum<span class="token punctuation">;</span></code></pre>
<p>There's nothing too crazy going on here - by using <code>reduce</code> we can iterate through the array and add up the numbers as we go. Now I'll use Flow's type annotations to annotate this function. First let's annotate the arguments that this function takes, by declaring that the input argument should be an <code>Array</code> of type <code>number</code>. This means that <code>input</code> will be an array where all the values are of type <code>number</code>, and the syntax for this in Flow is <code>Array<number></code>:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// @flow</span><br><span class="token keyword">const</span> <span class="token function-variable function">sum</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">input</span><span class="token operator">:</span> Array<span class="token operator"><</span>number<span class="token operator">></span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> input<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> a <span class="token operator">+</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">export</span> <span class="token keyword">default</span> sum<span class="token punctuation">;</span></code></pre>
<p>Note that I've also added the <code>// @flow</code> comment so that Flow will start type checking my code. I'll now declare that the return type of this function is a <code>number</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// @flow</span><br><span class="token keyword">const</span> sum <span class="token operator">=</span> <span class="token punctuation">(</span>input<span class="token operator">:</span> Array<span class="token operator"><</span>number<span class="token operator">></span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token parameter">number</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> input<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> a <span class="token operator">+</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">export</span> <span class="token keyword">default</span> sum<span class="token punctuation">;</span></code></pre>
<p>If you run <code>flow</code> again, you'll see that there are still no errors. This means that Flow has confirmed that our code is conforming to the types we told it about.</p>
<p>Let's say we make a mistake (obvious to spot on this small code - but imagine if this was a real life application with much more going on):</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// @flow</span><br><span class="token keyword">const</span> sum <span class="token operator">=</span> <span class="token punctuation">(</span>input<span class="token operator">:</span> Array<span class="token operator"><</span>number<span class="token operator">></span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token parameter">number</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> input<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token operator">=></span> a <span class="token operator">+</span> <span class="token string">'b'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Now when you run <code>flow</code>, you will see an error (you may need to scroll the codebox to see the full error):</p>
<pre><code>3: return input.reduce((a, b) => a + 'b')
^^^^^^^ string.
This type is incompatible with the expected param type of
2: const sum = (input: Array<number>): number => {
^^^^^^ number
</code></pre>
<p>Flow has correctly spotted that our <code>reduce</code> call is adding the string <code>'b'</code> to the number <code>a</code> and is telling us that it is invalid. It knows <code>a</code> is a <code>number</code> because we specified that <code>input</code> is of type <code>Array<number></code>, and therfore it can spot the issue.</p>
<p>Flow is really good generally at picking up silly mistakes like this and you'll find once you get into the habit of using it that any silly mistakes you make are automatically picked up by Flow, and you'll realise them before you've gone into your browser, refreshed the page and spotted an error.</p>
<p>What's even nicer about Flow is that once you've annotated a function with types, Flow can spot when you then use that function wrong in other places in your codebase.</p>
<p>Let's say in 6 months time you're using the <code>sum</code> function that we wrote earlier and you forget that you have to pass an array of numbers. Instead of <code>sum([1, 2, 3])</code> you call <code>sum(1, 2, 3)</code>. An easy mistake to make but it will have you digging in the browser console or digging into the source code to see what <code>sum</code> expects. With Flow checking our code though, we get a much nicer errror:</p>
<pre><code>8: sum(1, 2, 3)
^ number. This type is incompatible with the expected param type of
2: const sum = (input: Array<number>): number => {
^^^^^^^^^^^^^ array type
</code></pre>
<p>This saves a lot of time and energy digging into hard to follow console errors, and enables you to spot mistakes as soon as they happen. There are also plugins available for Flow and most popular code editors, so you can have these errors appear the moment you type the incorrect code.</p>
<p>This tutorial has barely even begun to scratch the surface of the type system in Flow and what it can do, but for now we're going to move on and look at how we can publish code to npm that's written in Flow. The <a href="https://flowtype.org/docs/getting-started.html#_">Flow docs</a> have much more information on all that Flow can do for you, and be sure to keep an eye out for future articles on Flow.</p>
<h2>Publishing Typed JavaScript modules</h2>
<p>So my small <code>util-fns</code> library is ready to be published to npm for the whole world to download and use. I've got a tonne of types throughout my code, and I've also written all the code using ES2015. For publishing in the browser I'm going to use Babel to strip the types and also compile the code into ES5, so it's usable across more browsers. However, it's silly to spend a lot of time and energy adding types to our code, only to strip them from the published module so that no other developers can benefit from them.</p>
<p>Instead, I'd like developers who are using Flow to be able to see the type information for the functions that my module is providing, so if they use them incorrectly, Flow can tell them so. I also want users who don't use Flow to be able to use my module out of the box too, without the need for any additional compilation steps.</p>
<p>The solution here is to publish two versions of the code within one module. One version will be fully compiled with Babel and have all types stripped. The other will be the original code, with all the types left in it. When researching approaches for publishing types to npm, I discovered that when a file is imported, Flow will look not only for that file but for the same file name with <code>.flow</code> added on the end. That is, if my code has:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> foo <span class="token keyword">from</span> <span class="token string">'./my-module'</span><span class="token punctuation">;</span></code></pre>
<p>Flow will first see if <code>my-module.js.flow</code> exists, and use that if it does, before using <code>my-module.js</code>. Of course, all other tools will use <code>my-module.js</code>, and ignore the file with the <code>.flow</code> extension.</p>
<p>What we need to do is publish two versions of each file in our project. So, for the file <code>sum.js</code>, we should publish:</p>
<ul>
<li><code>lib/sum.js</code>, which is compiled with Babel and stripped of types.</li>
<li><code>lib/sum.js.flow</code>, which is the original file, with types left in it.</li>
</ul>
<h3>Configuring Babel</h3>
<p>Configuring Babel to strip Flow types is a matter of creating a <code>.babelrc</code> with the <code>transform-flow-strip-types</code> plugin enabled, along with any others you might be using.</p>
<pre class="language-js"><code class="language-js"> <span class="token string-property property">"presets"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"es2015"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token string-property property">"plugins"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token string">"transform-flow-strip-types"</span><span class="token punctuation">,</span><br> <span class="token punctuation">]</span><br><span class="token punctuation">}</span></code></pre>
<p>You can then tell Babel to take each file in the <code>src</code> directory and output a compiled version in the <code>lib</code> directory with:</p>
<pre><code>babel src/ -d lib
</code></pre>
<p>Typically you'll want to add the <code>lib</code> directory to your <code>.gitignore</code>, as we don't want compiled code in Git.</p>
<h3>Telling npm to use the <code>lib</code> directory</h3>
<p>We also need to tell npm that it should publish files in the <code>lib</code> directory when we publish this package. If you've added the <code>lib</code> directory to your <code>.gitignore</code>, npm by default will respect that and not push the <code>lib</code> directory. However, the <code>lib</code> directory is actually where the code that we want users to run lives, so in our case we need it published.</p>
<p>My preferred method of doing this is to add a <code>files</code> entry to the <code>package.json</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token string-property property">"files"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token string">"lib"</span><br><span class="token punctuation">]</span></code></pre>
<p>And finally, we need to update our package's <code>main</code> property. This is the file that will be loaded when the user imports our module (via <code>import utils from 'util-fns'</code>). In the case of this project, the file that I'd like to be loaded is <code>lib/index.js</code>, so I'll update my <code>package.json</code> will that:</p>
<pre class="language-js"><code class="language-js"><span class="token string-property property">"main"</span><span class="token operator">:</span> <span class="token string">"lib/index.js"</span></code></pre>
<h3>Generating <code>.flow</code> files</h3>
<p>So now we have a <code>lib</code> directory full of compiled JavaScript files, but I also want to keep the original files in there, albeit with a <code>.flow</code> extension. Luckily I'm not the first to want this, and I found the <a href="https://github.com/AgentME/flow-copy-source">flow-copy-source</a> project on Github exactly what's needed. I can install this as a developer dependency:</p>
<pre><code>npm install --save-dev flow-copy-source
</code></pre>
<p>And now to run it I simply run:</p>
<pre><code>flow-copy-source src lib
</code></pre>
<p>Once I run that, it will take each file in <code>src</code> and copy it to <code>lib</code>, adding a <code>.flow</code> extension on the end. Now my <code>lib</code> directory looks like so:</p>
<pre><code>lib
├── index.js
├── index.js.flow
├── ...and so on
├── sum.js
└── sum.js.flow
</code></pre>
<h3>Building when publishing</h3>
<p>We're almost there now and ready to publish the module to npm, but the final step is to make sure that when publishing we don't forget any of the above steps. I can define a <code>prepack</code> script in my <code>package.json</code> that npm will run automatically when I run <code>npm publish</code>. By doing this I'll ensure my project is all up to date and fully built when I publish new versions to the repository. Typically I'll split up my npm scripts into smaller ones, so I create a new script for running Babel, and another for running flow-copy-source, and make <code>prepack</code> run the both of them:</p>
<pre class="language-js"><code class="language-js"><span class="token string-property property">"prepack"</span><span class="token operator">:</span> <span class="token string">"npm run prepack:babel && npm run prepack:flow"</span><span class="token punctuation">,</span><br><span class="token string-property property">"prepack:babel"</span><span class="token operator">:</span> <span class="token string">"babel src/ -d lib"</span><span class="token punctuation">,</span><br><span class="token string-property property">"prepack:flow"</span><span class="token operator">:</span> <span class="token string">"flow-copy-source src lib"</span><span class="token punctuation">,</span></code></pre>
<p>Finally, we're ready to publish our module! I can run <code>npm publish</code> to push a module to the repository, and when I do npm will run my <code>prepack</code> script and generate the compiled files and the <code>.flow</code> files:</p>
<pre><code>> npm run prepack:babel && npm run prepack:flow
> util-fns@0.1.3 prepack:babel /Users/jackfranklin/git/util-fns
> babel src/ -d lib
src/index.js -> lib/index.js
...and so on
src/sum.js -> lib/sum.js
> util-fns@0.1.3 prepack:flow /Users/jackfranklin/git/util-fns
> flow-copy-source src lib
</code></pre>
<h2>Using our new module</h2>
<p>To check that the types are working properly in our published code, we can install our newly published <code>util-fns</code> module in another project that's configured with Flow:</p>
<pre><code>npm install --save util-fns
</code></pre>
<p>Now let's say we've gotten confused about the API again, and we try to use a method that doesn't exist:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// @flow</span><br><span class="token keyword">import</span> utils <span class="token keyword">from</span> <span class="token string">'util-fns'</span><span class="token punctuation">;</span><br><br>utils<span class="token punctuation">.</span><span class="token function">getSum</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Flow can detect that <code>getSum</code> isn't a function that exists in the module:</p>
<pre><code>4: console.log(utils.getSum([1, 2, 3]))
^^^^^^ property `getSum`. Property not found in
4: console.log(utils.getSum([1, 2, 3]))
^^^^^ object literal
</code></pre>
<p>And now imagine I remember that the function is called <code>sum</code>, but I forget that I have to pass an array:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// @flow</span><br><span class="token keyword">import</span> utils <span class="token keyword">from</span> <span class="token string">'util-fns'</span><span class="token punctuation">;</span><br><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>utils<span class="token punctuation">.</span><span class="token function">sum</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Flow will pick up on this too, but <em>only</em> because we included those extra <code>.flow</code> files in our package. Notice that it also tells us which file to go and look in to find the source for the <code>sum</code> function if we want to dig into the types:</p>
<pre><code>4: console.log(utils.sum(1, 2, 3))
^ number. This type is incompatible with the expected param type of
2: const sum = (input: Array<number>): number => {
^^^^^^^^^^^^^ array type.
See: node_modules/util-fns/lib/sum.js.flow:2
</code></pre>
<p>This is <em>brilliant</em> as a developer working with a lot of libraries whose APIs I forget a lot. It means that I'm quickly alerted to mistakes and I have hinting and help in my editor telling me what arguments functions accept and what types they are. You can see that a little extra effort as the author of the <code>util-fns</code> package leads to a nicer experience for any developers working with my package in a Flow environment.</p>
<h2>Working with libraries without definitions</h2>
<p>Although in this case we published the <code>util-fns</code> function with type definitions, not all libraries that you'll work with have these built in. There are many, many libraries out there that are not written with Flow, but with plain JavaScript, and it's a shame to not have any type information on those available.</p>
<p>Luckily, <a href="https://github.com/flowtype/flow-typed">flow-typed</a> is here to help you out. It's an amazing repository full of type declarations for many, many popular libraries, both for NodeJS and client-side JavaScript, including Express, Lodash, Enzyme, Jest, Moment, Redux and more.</p>
<p>You can install <code>flow-typed</code> through npm, and then once you do you simply run <code>flow-typed install</code> within your project. This will look through your <code>package.json</code> for all your dependencies and, for each one, try to install the corresponding type definitions from its repository. This means you can still enjoy type information for libraries like Lodash, even though they are not written using Flow.</p>
<h2>Conclusion</h2>
<p>I hope this blog post gives you a look into the world of writing typed JavaScript with Flow. In terms of the type system itself this blog post barely touches the power of Flow, and it's something I'll be writing more about as I get more comfortable with it and learn more. If you're a library author I'd encourage you to try writing in Flow, it's a great experience whilst developing a library and can help prevent bugs. It's also great to include those type definitions when publishing your library; your users will benefit hugely from having Flow able to nudge them when using your library wrong, and it also means Flow can pick up on API changes and inform users when the types change.</p>
How to contribute to open source with Webpack2017-01-11T00:00:00+00:00http://www.jackfranklin.co.uk/blog/contributing-to-webpack-javascript/<p><a href="http://github.com/webpack/webpack">Webpack</a> is one of the most prominent open source projects in the JavaScript and they are always looking for more people to help contribute back to the project. Speaking from personal experience, it's incredibly daunting to even think about contributing back to such a large project, but in this video we'll demonstrate that it's actually no where near as tricky as you might imagine.</p>
<p>I invited Webpack core team member <a href="http://twitter.com/thelarkinn">Sean Larkin</a> onto a Google Hangouts session as we paired on contributing to Webpack. You'll see how to:</p>
<ul>
<li>Clone Webpack and get it running locally on your machine.</li>
<li>How to find code in the Webpack repository that's good for a pull request.</li>
<li>How to run the Webpack tests to ensure your work hasn't broken anything.</li>
<li>How to run ESLint to ensure you're following the code standards of the project.</li>
<li>How to open a pull request against Webpack.</li>
<li>Sean's workflow for reviewing pull requests.</li>
</ul>
<p>Even if you don't want to contribute directly to Webpack, this video should help you contribute to any open source project that you're interested in.</p>
<p>PS: it's definitely worth making the video fullscreen or viewing <a href="https://www.youtube.com/watch?v=ePdXHF2DfeY&feature=youtu.be">on Youtube</a> so you can see things more clearly.</p>
<iframe width="640" height="360" src="https://www.youtube.com/embed/ePdXHF2DfeY" frameborder="0" allowfullscreen=""></iframe>
<br>
<p><a href="https://github.com/webpack/webpack/pull/3799">You can find the pull request I opened on GitHub</a>. Once again, huge thanks to Sean for taking the time to do the video with me. Happy contributing!</p>
Loading data from APIs in React2017-01-19T00:00:00+00:00http://www.jackfranklin.co.uk/blog/http-requests-reactjs/<p>ReactJS is a brilliant framework to work in, and something that I get asked a lot by people new to the framework is how best to deal with loading data from an external source, such as an API. In today's 10 minute video I show you how to create a component that can fetch data from an API and render it onto the page.</p>
<p>You'll learn about the React lifecycle and which method is best for making HTTP requests, how to use the <code>fetch</code> API to get JSON from an API, and how to deal with errors as well as successful responses.</p>
<p>PS: it's definitely worth making the video fullscreen or viewing <a href="https://www.youtube.com/watch?v=MjavMX8fUAE">on Youtube</a> so you can see things more clearly.</p>
<iframe width="640" height="360" src="https://www.youtube.com/embed/MjavMX8fUAE" frameborder="0" allowfullscreen=""></iframe>
<br>
<p>If you'd like to play with this code, <a href="https://github.com/javascript-playground/remote-data-react-screencasts">you can find the repository on GitHub</a>, and look out for the follow up episode in a few weeks where we look at some libraries that can make fetching external data much nicer.</p>
Setting up Vim for modern JavaScript Development2017-01-30T00:00:00+00:00http://www.jackfranklin.co.uk/blog/vim-for-javascript/<p>I've been using Vim solidly for about six years now, and do all of my editing in it. This blog post, all the open source code on GitHub, and all my code at work is written in Vim. I keep all my configuration in my <a href="http://github.com/jackfranklin/dotfiles">dotfiles repo on GitHub</a> which means it's easily synced between computers, and I'm really happy with this set up.</p>
<p>I toy with my Vim configuration on a fairly frequent basis but I've now settled on a set of JavaScript plugins and configuration that's allowing me to be really productive, and integrate with tools like ESLint and Flow, and today I'll walk through the key parts of that workflow.</p>
<h2>JavaScript Syntax</h2>
<p>The main plugin I use here is <a href="http://github.com/pangloss/vim-javascript">pangloss/vim-javascript</a>. There's many options for JS highlighting in Vim but I've found this to be the most reliable. This plugin also has support for Flow and its types, and you can enable that by turning it on in your vimrc:</p>
<pre><code>let g:javascript_plugin_flow = 1
</code></pre>
<p>In addition I use <a href="http://github.com/mxw/vim-jsx">mxw/vim-jsx</a> to add syntax support for JSX to my JavaScript files. It's important to note that this plugin expects your JSX files to have a <code>.jsx</code> extension, but often I just stick with <code>.js</code>. If you're doing the same, you'll want to add the following to your config:</p>
<pre><code>let g:jsx_ext_required = 0
</code></pre>
<p>I also use <a href="http://github.com/leshill/vim-json">leshill/vim-json</a> which improves the syntax highlighing for JSON files.</p>
<p>In terms of colour theme, I keep trying others but keep coming back to the <a href="https://github.com/ajh17/Spacegray.vim">Spacegray theme</a>, which I've now had for a long time and I'm very happy with it.</p>
<h2>Finding files and navigating</h2>
<p>There are numerous options for fuzzy finding, but the one that I've found works best is <a href="https://github.com/junegunn/fzf">FZF</a> and the corresponding <a href="http://github.com/junegunn/fzf.vim">FZF.vim</a> plugin. This lets me quickly navigate through projects to find the files I'm after. Not JS specific, but definitely worth a mention.</p>
<h2>Snippets</h2>
<p>I have to say that I probably don't utilise snippets as much as I should, but when I do I'm still a fan of <a href="https://github.com/SirVer/ultisnips">UltiSnips</a>. This doesn't come with snippets by default, and whilst you can rely on another plugin to give you snippets, I've just <a href="https://github.com/jackfranklin/dotfiles/blob/master/vim/vim/UltiSnips/javascript.snippets">got my own snippets file</a>.</p>
<h2>ESLint + Flow Integration</h2>
<p>The two command line tools that I use most are ESLint and Flow. Both of these continually check my code as I'm working to ensure that I'm writing code that is typed correctly, or formatted correctly based on ESLint.</p>
<p>Until recently, integrating these with Vim was far from ideal, for two reasons:</p>
<ol>
<li>
<p>Something I always do is to install command line tools locally, rather than globally. By doing this it means that I can have projects run different versions of the same tool without them colliding. When you do this, npm puts the executable in <code>./node_modules/.bin</code>. This can break editor integrations, because they expect to have the executable available, so try running <code>eslint</code>, rather than <code>./node_modules/.bin/eslint</code>, for example.</p>
</li>
<li>
<p>Up until the release of Vim 8, Vim didn't have support for async, background jobs. This meant when you saved your file, and ESLint ran, the editor would be unresponsive for a second or two, until ESLint returned. This is only a small amount of lag but it's really noticable.</p>
</li>
</ol>
<p>Thankfully, both of these problems have been solved recently thanks to Vim 8 and the <a href="https://github.com/w0rp/ale">Ale plugin</a>, an asynchronous linting plugin for Vim. Upgrading to Vim 8 (if you're on a Mac, I recommend doing this via Homebrew) is easy, but unless you have the plugins, you don't really gain anything out of the box.</p>
<p>Ale is a linting plugin that comes out the box with support for a variety of linting tools for different filetypes and languages, and most importantly for me that includes ESLint and Flow. Once more, it even has support for using the locally installed version of a linter by default, so it's perfect for my needs. It automatically detects which linters to run and you really don't need to configure it at all.</p>
<p>The only change I made was to run the linters when I save the file, rather than continuously as I type, which is the default behaviour. This is just personal preference.</p>
<pre><code>let g:ale_lint_on_save = 1
let g:ale_lint_on_text_changed = 0
</code></pre>
<h2>Testing</h2>
<p>I run Vim from within a tmux session, which means I can split my terminal into two (much like split panes in any modern Terminal application), and have Vim on the one panel and a command line on the other. Usually I'll just do this and then run <code>npm test</code> on the command line, in watch mode. That way my tests are running side by side to my code.</p>
<p>To make navigating between Vim and Tmux windows easier, I use Chris Toomey's excellent <a href="https://github.com/christoomey/vim-tmux-navigator">vim-tmux-navigator</a>. You can read more about this set up in <a href="https://robots.thoughtbot.com/seamlessly-navigate-vim-and-tmux-splits">this post from Thoughtbot</a>.</p>
<h2>Editor Config</h2>
<p>I also include the <a href="https://github.com/editorconfig/editorconfig-vim">EditorConfig vim plugin</a> in my setup, so as I swap to any JS project that might have different space/tabs than my preference, Vim will automatically switch for me. This is particularly useful for contributing to open source projects (Webpack for example, uses tabs, whereas I use spaces). Having Vim swap for me is really handy.</p>
<h2>Conclusion</h2>
<p>Everyone has a different preference with editors, and Vim in particular is hugely configurable. If you've got any suggestions or different plugins that you like to use, please let me know, and I hope this post helps you speed up your Vim and JavaScript workflow.</p>
Context in ReactJS Applications2017-02-13T00:00:00+00:00http://www.jackfranklin.co.uk/blog/context-in-reactjs-applications/<p>There is a lot of confusion amongst React developers on what context is, and why it exists. It's also a feature that's been hidden in the React documentation in the past and, <a href="https://facebook.github.io/react/docs/context.html">although it is now documented on the React site</a> I thought a post on its usage and when to use it would be of use.</p>
<p>The short answer is that you should <strong>very rarely, if ever</strong> use context in your own React components. However, if you're writing a library of components, it can come in useful, and we'll discuss why this is later.</p>
<h2>What is context in React, and how does it work?</h2>
<p>In React the primary mechanism for communication between your components is through properties, or <code>props</code>, for short. Parent components can pass properties down to their children:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">ParentComponent</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> foo <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>ChildComponent foo<span class="token operator">=</span><span class="token punctuation">{</span>foo<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Here, the parent component <code>ParentComponent</code> passes the prop <code>foo</code> through to its child, <code>ChildComponent</code>.</p>
<blockquote>
<p>Here, a <em>child component</em> is a component that another component renders. A <em>parent component</em> is a component that directly renders another.</p>
</blockquote>
<p>If a child component wants to communicate back to its parent, it can do so through props, most commonly by its parent providing a <em>callback property</em> that the child can call when some event happens:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">ParentComponent</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token function-variable function">letMeKnowAboutSomeThing</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'something happened!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> <span class="token keyword">return</span> <span class="token operator"><</span>ChildComponent letMeKnowAboutSomeThing<span class="token operator">=</span><span class="token punctuation">{</span>letMeKnowAboutSomeThing<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">ChildComponent</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token function-variable function">onClick</span> <span class="token operator">=</span> <span class="token parameter">e</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> e<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> props<span class="token punctuation">.</span><span class="token function">letMeKnowAboutSomeThing</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">;</span><br><br> <span class="token keyword">return</span> <span class="token operator"><</span>a onClick<span class="token operator">=</span><span class="token punctuation">{</span>onClick<span class="token punctuation">}</span><span class="token operator">></span>Click me<span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>The key thing about this communication is that it's <em>explicit</em>. Looking at the code above, you know how the components are communicating, where the <code>letMeKnowAboutSomeThing</code> function comes from, who calls it, and which two components are in communication. <a href="http://codepen.io/jackfranklin/pen/vgvYOa?editors=0011">You can see this in action on CodePen</a>.</p>
<p>This property of React, its explicitness of data passing between components, is one of its best features. React is very explicit as a rule, and this is in my experience leads to clearer code that's much easier to maintain and debug when something goes wrong. You simply have to follow the path of props to find the problem.</p>
<p>This diagram shows how props keep communication clear but can get a little excessive as you gain many layers in your application; each component has to explictly pass props down to any children.</p>
<p><img src="http://www.jackfranklin.co.uk/img/posts/context-in-react/props.png" alt=""></p>
<p>One issue you might find in big apps is that you might need to pass props from a top level <code>ParentComponent</code> to a deeply nested <code>ChildComponent</code>. The components in between will probably have no use the these props and should probably not even know about them. When this situation arises, you can consider using React's context feature.</p>
<p>Context acts like a portal in your application in which components can make data available to other components further down the tree without being passed through explictly as props.</p>
<p><img src="http://www.jackfranklin.co.uk/img/posts/context-in-react/context.png" alt=""></p>
<p>When a component defines some data onto its <em>context</em>, any of its descendants can access that data. That means any child further down in the component tree can access data from it, without being passed it as a property. Let's take a look at context in action.</p>
<h2>How to use <code>context</code> in React applications</h2>
<p>First, on the <em>parent component</em>, we define two things:</p>
<ol>
<li>A function, <code>getChildContext</code>, which defines what context is exposed to its descendants.</li>
<li>A static property, <code>childContextTypes</code>, which defines the types of the objects that <code>getChildContext</code> returns.</li>
</ol>
<p>For a component to provide context to its descendants, it must define both of the above. Here, <code>ParentComponent</code> exposes the property <code>foo</code> on its context:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">ParentComponent</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span><br> <span class="token function">getChildContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">foo</span><span class="token operator">:</span> <span class="token string">'bar'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>ChildComponent <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br>ParentComponent<span class="token punctuation">.</span>childContextTypes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">foo</span><span class="token operator">:</span> React<span class="token punctuation">.</span>PropTypes<span class="token punctuation">.</span>string<span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p><code>ChildComponent</code> can now gain access to the <code>foo</code> property by defining a static property <code>contextTypes</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">ChildComponent</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">props<span class="token punctuation">,</span> context</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>The value <span class="token keyword">of</span> foo is<span class="token operator">:</span> <span class="token punctuation">{</span>context<span class="token punctuation">.</span>foo<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br>ChildComponent<span class="token punctuation">.</span>contextTypes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">foo</span><span class="token operator">:</span> React<span class="token punctuation">.</span>PropTypes<span class="token punctuation">.</span>string<span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<blockquote>
<p>In a functional, stateless component, <code>context</code> is accessed via the second argument to the function. In a standard class component, it's available as <code>this.context</code>.</p>
</blockquote>
<p>What's important here though is that any component that <code>ChildComponent</code> renders, or any component its children render, and so on, are able to access the same context just by defining <code>contextTypes</code>.</p>
<h2>Why you should avoid context</h2>
<p>There's a few reasons why you would want to avoid using context in your own code.</p>
<h4>1. Hard to find the source.</h4>
<p>Imagine that you're working on a component on a large application that has hundreds of components. There's a bug in one of them, so you go hunting and you find some component that uses context, and the value it's outputting is wrong.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">SomeAppComponent</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">props<span class="token punctuation">,</span> context</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>p<span class="token operator">></span>Hey user<span class="token punctuation">,</span> the current value <span class="token keyword">of</span> something is <span class="token punctuation">{</span>context<span class="token punctuation">.</span>value<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br> <span class="token operator"><</span>a onClick<span class="token operator">=</span><span class="token punctuation">{</span>context<span class="token punctuation">.</span><span class="token function">onSomeClick</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>Click here to change it<span class="token punctuation">.</span><span class="token operator"><</span><span class="token operator">/</span>a<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br>SomeAppComponent<span class="token punctuation">.</span>contextTypes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">value</span><span class="token operator">:</span> React<span class="token punctuation">.</span>PropTypes<span class="token punctuation">.</span>number<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br> <span class="token literal-property property">onSomeClick</span><span class="token operator">:</span> React<span class="token punctuation">.</span>PropTypes<span class="token punctuation">.</span>func<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>The bug is related to the click event not updating the right value, so you now go looking for the definition of that function. If it was being passed as a property, you could go immediately to the place where this component is rendered (which is usually just a case of searching for its name), and start debugging. In the case that you're using context, you have to search for the function name and hope that you find it. This could be found easily, granted, but it also could be a good few components up the chain, and as your apps get larger the chances of you finding the source quickly gets smaller.</p>
<p>It's similar to the problem when you work in an object oriented language and inherit from classes. The more classes you inherit from (or in React, the further down the component tree you get), it's harder to find the source for a particular function that's been inherited.</p>
<h4>2. Binds components to a specific parent</h4>
<p>A component that expects only properties (or no properties at all) can be used anywhere. It is entirely reusable and a component wanting to render it need only pass in the properties that it expects. If you need to use the component elsewhere in your application you can do easily; just by supplying the right properties.</p>
<p>However, if you have a component that needs specific context, you couple it to having to be rendered by a parent that supplies some context. It's then harder to pick up and move, because you have to move the original component and then make sure that its new parent (or one of its parents) provides the context required.</p>
<h4>3. Harder to test</h4>
<p>Related to the previous point, components that need context are much harder to test. Here's a test, using <a href="http://airbnb.io/enzyme/">Enzyme</a>, that tests a component that expects a <code>foo</code> prop:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> wrapper <span class="token operator">=</span> <span class="token function">mount</span><span class="token punctuation">(</span><span class="token operator"><</span>SomeComponent foo<span class="token operator">=</span><span class="token string">"bar"</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>And here's that same test when we need <code>SomeComponent</code> to have a specific piece of context:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">ParentWithContext</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span><br> <span class="token function">getChildContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span><br><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>SomeComponent <span class="token operator">/</span><span class="token operator">></span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><br>ParentWithContext<span class="token punctuation">.</span>childContextTypes <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span><br><br><span class="token keyword">const</span> wrapper <span class="token operator">=</span> <span class="token function">mount</span><span class="token punctuation">(</span><span class="token operator"><</span>ParentWithContext <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">)</span></code></pre>
<p>It's harder here because we have to build the right parent component - it's messier and quite verbose just to set up the component in the right context for testing.</p>
<blockquote>
<p>You can actually use Enzyme's <a href="http://airbnb.io/enzyme/docs/api/ReactWrapper/setContext.html">setContext</a> to set context for these tests - but I tend to try to avoid any methods like this that breaks the React abstraction. You also wouldn't be able to do this so easily in other testing frameworks.</p>
</blockquote>
<h4>4. Unclear semantics around context value changes and rerenders.</h4>
<p>With properties and state, it's very clear to React when it should rerender a component:</p>
<ol>
<li>When a component's properties change.</li>
<li>When <code>this.setState</code> is called.</li>
</ol>
<p>The <code>getChildContext</code> function is called whenever state or properties change, so in theory you can rely on components that use <code>context</code> values reliably updating. The problem though is <code>shouldComponentUpdate</code>. Any component can define <code>shouldComponentUpdate</code>, making it return <code>false</code> if it knows that it doesn't need to be re-rendered. If an interim component does this, a child component won't update, even if a context value changes:</p>
<pre><code>TopLevelComponent
- defines context.foo
MidLevelComponent
- defines `shouldComponentUpdate` to return `false`
ChildComponent
- renders `context.foo` into the DOM
</code></pre>
<p>In the above example, if <code>context.foo</code> changes, <code>ChildComponent</code> will not render, because its parent returned <code>false</code> from <code>shouldComponentUpdate</code>. This makes bugs possible and leaves us with no reliable way to update context and ensure renders, so this is a very good reason to avoid using <code>context</code>.</p>
<h2>When to use context</h2>
<p>If you're a library author, context is useful. Libraries like <a href="https://github.com/ReactTraining/react-router/blob/v4/packages/react-router/modules/Router.js#L13">React Router use context</a> to allow the components that they provide application developers to communicate. When you're writing a library that provides components that need to talk to each other, or pass values around, <code>context</code> is perfect. Another famous library that makes use of context is <a href="https://github.com/reactjs/react-redux/blob/master/src/components/Provider.js#L23">react-redux</a>. I encourage you to look through the source code for both React Router and React Redux, you can learn a lot about React by doing so.</p>
<p>Let's build our own router library, <code>RubbishRouter</code>. It will define two components: <code>Router</code> and <code>Route</code>. The <code>Router</code> component needs to expose a <code>router</code> object onto the context, so our <code>Route</code> components can pick up on it and use it to function as expected.</p>
<p><code>Router</code> will be used to wrap our entire application, and the user will use multiple <code>Route</code> components to define parts of the app that should only render if the URL matches. To do this, each <code>Route</code> will take a <code>path</code> property, indicating the path that they should match before rendering.</p>
<p>First, <code>Router</code>. It exposes the <code>router</code> object on the context, and other than that it simply renders the children that it's given:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">{</span> Component<span class="token punctuation">,</span> PropTypes <span class="token punctuation">}</span> <span class="token operator">=</span> React<span class="token punctuation">;</span><br><br><span class="token keyword">class</span> <span class="token class-name">Router</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">getChildContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token function">register</span><span class="token punctuation">(</span><span class="token parameter">url</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'registered route!'</span><span class="token punctuation">,</span> url<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">;</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">router</span><span class="token operator">:</span> router <span class="token punctuation">}</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>children<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><br>Router<span class="token punctuation">.</span>childContextTypes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">router</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>object<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p><code>Route</code> expects to find <code>this.context.router</code>, and it registers itself when it's rendered:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">Route</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">componentWillMount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>context<span class="token punctuation">.</span>router<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>path<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span><span class="token constant">I</span> am the route <span class="token keyword">for</span> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>path<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><br>Route<span class="token punctuation">.</span>contextTypes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">router</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>object<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Finally, we can use the <code>Router</code> and <code>Route</code> components in our own app:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>Router<span class="token operator">></span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/foo"</span> <span class="token operator">/</span><span class="token operator">></span><br> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/bar"</span> <span class="token operator">/</span><span class="token operator">></span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>Route path<span class="token operator">=</span><span class="token string">"/baz"</span> <span class="token operator">/</span><span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>Router<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The beauty of context in this situation is that as library authors we can provide components that can work in any situation, regardless of where they are rendered. As long as all <code>Route</code> components are within a <code>Router</code>, it doesn't matter at what level, and we don't tie application developers to a specific structure.</p>
<h2>Conclusion</h2>
<p>Hopefully this blog post has shown you how and when to use context in React, and why more often than not you'd be better eschewing it in favour of props.</p>
<p>Thank you to the following blog posts and documentation for providing great material whilst putting this blog post together:</p>
<ul>
<li><a href="https://facebook.github.io/react/docs/context.html">React docs on context</a></li>
<li><a href="https://medium.com/@mweststrate/how-to-safely-use-react-context-b7e343eff076">How to safely use React context</a> by Michel Weststrate.</li>
</ul>
<p>Thank you also to <a href="https://twitter.com/ArnaudRinquin">Arnaud Rinquin</a> for taking the time to review this post.</p>
Dealing with APIs in React with ReactRemoteData2017-03-02T00:00:00+00:00http://www.jackfranklin.co.uk/blog/remote-data-react-components/<p>Last year I wrote about <a href="http://javascriptplayground.com/blog/2016/06/remote-data-js/">RemoteDataJS</a>, a <a href="https://github.com/jackfranklin/remote-data-js">library I released on GitHub</a> that made it really easy to deal with data from APIs in JavaScript.</p>
<p>This library lets you represent remote pieces of data properly, dealing with all the different states it can be in, and any errors that might occur. Since writing that library I've been doing a lot of work with React, which has fast become my framework of choice, and I've now written a React library for RemoteData.</p>
<h2>React Remote Data</h2>
<p><a href="https://github.com/jackfranklin/react-remote-data">React Remote Data</a> provides a React component that will deal with loading some data and showing you the results. You tell it what to render for each possible state that your data might be in, and it does the rest.</p>
<p>You can install the library from npm by running <code>npm install react-remote-data-js</code>. Let's see how we can use this component, by writing a component that renders your data from the GitHub API.</p>
<p>You have to give the <code>RemoteData</code> five props:</p>
<ul>
<li><code>url</code>, which is the URL that should be fetched. This can be a function instead, but we'll tackle that later.</li>
</ul>
<p>The other four props all map to the states of the API request, which can be one for states:</p>
<ul>
<li><code>notAsked</code> - the request has not been made yet</li>
<li><code>pending</code> - the request is in progress</li>
<li><code>success</code> - the request has succeeded</li>
<li><code>failure</code> - the request has failed</li>
</ul>
<p>The <code>RemoteData</code> component expects a function for each of these possible states, and it will render the right component based on the right state.</p>
<p>First, let's define a function for the <code>notAsked</code> state. This gets called with a prop called <code>fetch</code>, which is the function called to trigger the request. Our <code>notAsked</code> function looks like so:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">notAsked</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>fetch<span class="token punctuation">}</span><span class="token operator">></span>Make Request<span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Next, we'll write a function for the <code>pending</code> state, which will simply show some loading text (you could render a spinner here, for example):</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">pending</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>p<span class="token operator">></span>Loading<span class="token operator">...</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span></code></pre>
<p>Next, our <code>success</code> case. When a request has succeeded the data will be provided via the <code>request</code> prop, which contains all the information about the request, including a <code>data</code> key, which has the parsed data as JSON, which we can render:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">success</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>p<span class="token operator">></span>Name<span class="token operator">:</span> <span class="token punctuation">{</span>props<span class="token punctuation">.</span>request<span class="token punctuation">.</span>data<span class="token punctuation">.</span>login<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>In this case one of the properties that Github gives us is <code>login</code>, so I'll render that onto the screen.</p>
<p>Finally, we can deal with the failure case by logging an error. In this case, <code>request.data</code> will be the HTTP error, and we can output the <code>message</code> property:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">failure</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>p<span class="token operator">></span>Error<span class="token operator">:</span> <span class="token punctuation">{</span>props<span class="token punctuation">.</span>request<span class="token punctuation">.</span>data<span class="token punctuation">.</span>message<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>And with that we now have all the properties required to create the <code>RemoteData</code> instance:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> RemoteData <span class="token keyword">from</span> <span class="token string">'react-remote-data-js'</span><span class="token punctuation">;</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">GithubData</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>RemoteData<br> url<span class="token operator">=</span><span class="token string">"http://api.github.com/users/jackfranklin"</span><br> notAsked<span class="token operator">=</span><span class="token punctuation">{</span>notAsked<span class="token punctuation">}</span><br> pending<span class="token operator">=</span><span class="token punctuation">{</span>pending<span class="token punctuation">}</span><br> success<span class="token operator">=</span><span class="token punctuation">{</span>success<span class="token punctuation">}</span><br> failure<span class="token operator">=</span><span class="token punctuation">{</span>failure<span class="token punctuation">}</span><br> <span class="token operator">/</span><span class="token operator">></span><br><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Under the hood, <code>RemoteData</code> keeps track of the request's state and ensures that the component renders the correct function depending on the state of the HTTP request.</p>
<h2>Thoughts on creating <code>ReactRemoteData</code> and abstracting with React</h2>
<p>I think that this library also shows just how powerful React is and how we can use it to abstract libraries behind components. The <a href="https://github.com/jackfranklin/react-remote-data/blob/master/src/index.js">entire source of the library</a> is only 55 lines long, and I've come to really enjoy using React in this way. Hiding complexity in components that are then easily reused is a great way to help developers build applications quicker and with more clarity, because you can read the components being used in the code and take an educated guess on what they do.</p>
<p>Another benefit of creating components like this is that it's very easy for you to create customised versions of them. Let's say you have a standard <code>HttpError</code> component, that takes an error and shows a nice message to the user. You want to add <code>ReactRemoteData</code> to your app, and you want every single instance of it to render your <code>HttpError</code> component when something goes wrong. You can simply wrap <code>ReactRemoteData</code> with your own version:</p>
<pre><code>import HttpError from 'your/app/components'
const MyRemoteData = props => (
<ReactRemoteData {...props} failure={props => <HttpError {...props} />} />
)
export default MyRemoteData
</code></pre>
<p>This makes it easy to deal with errors in one place, and be able to change it in just one place if your requirements change later on.</p>
<h2>Conclusion</h2>
<p>If you'd like an easy library that takes all the hassle out of remote HTTP requests, then I think <code>ReactRemoteData</code> might be for you. You can find further instructions on its usage <a href="https://github.com/jackfranklin/react-remote-data">on the GitHub repository</a> and I'd love to hear any of your thoughts via Twitter or as a GitHub issue.</p>
Functional Stateless Components in React2017-03-07T00:00:00+00:00http://www.jackfranklin.co.uk/blog/functional-stateless-components-react/<h2>What are functional, stateless components?</h2>
<p><a href="https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html#stateless-functional-components">React 0.14 introduced functional, stateless components</a> as a way to define React components as a function, rather than as an ES2015 class or via <code>React.createClass</code>.</p>
<p>Prior to React 0.14, writing a presentational component (that is, one that just renders props, and doesn't have state), could be fairly verbose:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> Username <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">createClass</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>The logged <span class="token keyword">in</span> user is<span class="token operator">:</span> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>username<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token comment">// OR:</span><br><span class="token keyword">class</span> <span class="token class-name">Username</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>The logged <span class="token keyword">in</span> user is<span class="token operator">:</span> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>username<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>React 0.14 introduced functional stateless components (or, from now on, FSCs), which lets you express the above more succinctly:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">Username</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>The logged <span class="token keyword">in</span> user is<span class="token operator">:</span> <span class="token punctuation">{</span>props<span class="token punctuation">.</span>username<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Which, via ES2015 arrow functions, destructuring and implicit returns can be cut down really nicely:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">Username</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> username <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>p<span class="token operator">></span>The logged <span class="token keyword">in</span> user is<span class="token operator">:</span> <span class="token punctuation">{</span>username<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span></code></pre>
<p>FSCs not only provide a cleaner syntax but also have some other benefits that I'd like to talk about today, along with a couple of gotchas and things to look out for.</p>
<p>It's also important to note that you can have stateless class components, and that in the future we might be able to have functional, <em>stateful</em> components. <a href="https://tylermcginnis.com/functional-components-vs-stateless-functional-components-vs-stateless-components/">Tyler McGinnis' post on the different types of components</a> does a great job of laying out all the different terminology.</p>
<p>I think the primary benefit of FSCs is simplicity, and to me they act as a visual signal: "this component is solely props in, rendered UI out". If I see a class component, I do have to scan through to see what lifecycle methods it may be using, and what callbacks it may have. If I see an FSC, I know it isn't doing anything fancy. There are definitely times I'll write a stateless class component so I can define callback methods as class properties (especially if I'm passing prop values into a callback prop), but I'll write FSCs to signal that "this is a very straightforward rendering component".</p>
<h2>FSCs lead to simplicity and offer visual cues</h2>
<p><a href="http://www.twitter.com/acemarke">Mark</a>, who I asked to review this post, made a <a href="https://github.com/jackfranklin/javascriptplayground.com/pull/70#issuecomment-284192694">great point in his review</a> that FSCs offer visual cues that a component is solely taking some props and rendering output. If you have a class component, you have to read through the code to see if it deals with state, has lifecycle hooks, and so on. FSCs by definition have to be simple and that can save you time as a developer.</p>
<p>If you do have a component that doesn't have any state, but needs to define lifecycle methods, or have many event handlers, you should still prefer class components, even if they don't use state, but for presentational components FSCs are a perfect fit.</p>
<h2>The syntax of FSCs encourages stateless components</h2>
<p>Stateless components (also known as presentational components) should make up the bulk of your React applications. As a general rule of thumb, the less stateful components your application has, the better. Stateless components are easier to test, because you never have to interact or set up state. You can pass them props and assert on their output, and never have to test user interactions. They will generally have fewer bugs in them; in my experience components that have and change state over time are where most bugs will occur.</p>
<h2>It's hard to convert a FSC to a stateful component</h2>
<p>Imagine you have a component that you think you might need to add state to. It's actually a fair bit of manual work to convert a FSC to a stateful component, regardless of if you're using ES2015 classes or <code>React.createClass</code>. Although this used to really frustrate me, I've come to appreciate this because it makes you think about if you really want to add state to the component. When you have a class component with just a <code>render</code> method, it's trivial to add state, but with a FSC it needs to be converted. Making it harder to quickly add state to a component is a good thing; you should carefully consider if you really need to.</p>
<p>To be clear; there are times when you can convert a FSC to a stateful component with good reason, but make sure you have that reason first and you've fully thought it through.</p>
<h2>FSCs are not bound to React</h2>
<p>In the world of JavaScript a new framework comes and goes every day; we've all seen the satirical blog posts about frameworks and version numbers of frameworks. But a FSC is not tied to React at all, other than the fact that it uses the JSX syntax. If you wanted to switch to another framework, or one day React stopped being worked on, it would be easy for another framework to add support for FSCs and make the adoption path easy. There's no reason React will cease to exist - but in general I've found the less code in your app that's bound to a specific framework, the better.</p>
<h2>FSCs are great for styling (particularly on smaller projects)</h2>
<p>In smaller projects, or small hack days, I've found that I will often use FSCs to very quickly create components that are used purely for styling:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">MyBlueButton</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> styles <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">background</span><span class="token operator">:</span> <span class="token string">'blue'</span><span class="token punctuation">,</span> <span class="token literal-property property">color</span><span class="token operator">:</span> <span class="token string">'white'</span> <span class="token punctuation">}</span><span class="token punctuation">;</span><br><br> <span class="token keyword">return</span> <span class="token operator"><</span>button <span class="token punctuation">{</span><span class="token operator">...</span>props<span class="token punctuation">}</span> style<span class="token operator">=</span><span class="token punctuation">{</span>styles<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h2>In the future, FSCs may be optimised for performance by React</h2>
<p>In the release for React 0.14, it was noted that in the future there are potential optimisations that React can make for FSCs:</p>
<blockquote>
<p>In the future, we’ll also be able to make performance optimizations specific to these components by avoiding unnecessary checks and memory allocations.</p>
</blockquote>
<p>Whilst this is still work that is on going, clearly the React team are heavily behind FSCs as the building blocks of your applications:</p>
<blockquote>
<p>This pattern is designed to encourage the creation of these simple components that should comprise large portions of your apps.</p>
</blockquote>
<p>Not only should you use FSCs because the React team encourages it, but in a future release of React you may see good performance increases by doing so. <strong>Note that currently there is no optimisations done on FSCs</strong>. Whilst it is planned after the work on React Fiber, there is currently no difference in performance.</p>
<h2>Event handlers and FSCs</h2>
<p>It's a bit of a misconception that FSCs don't allow you to define event handlers. You can just define them in-line:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">SomeButton</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token function-variable function">onClick</span> <span class="token operator">=</span> <span class="token parameter">e</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token operator">...</span><span class="token punctuation">)</span><br><br> <span class="token keyword">return</span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span>onClick<span class="token punctuation">}</span><span class="token operator">></span>Click me<span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span><br><span class="token punctuation">}</span></code></pre>
<p>It's important to note that this isn't the most efficient way of doing this; every time the component is run to potentially be rerendered, the <code>onClick</code> function will be redefined. This is work that you might want to avoid - and in some performance critical applications you might see this make a small difference. You'll find many blog posts online saying you should never do this, but the reality is for most applications that the optimisations will not be noticed. You should be aware of this and know that in certain situations it might really hurt performance, but don't shy away from adding an event handler in an FSC because of it.</p>
<p>If you do really want to avoid this, you have two choices. You either need to turn the component into a full component, or you can pull the event handler out of the FSC (only if you don't want to refer to the component's <code>props</code>, which means this often isn't feasible):</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">onClick</span> <span class="token operator">=</span> <span class="token parameter">e</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token operator">...</span><span class="token punctuation">)</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">SomeButton</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span>onClick<span class="token punctuation">}</span><span class="token operator">></span>Click me<span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span><br><span class="token punctuation">}</span></code></pre>
<h2>You can still define <code>propTypes</code> and <code>defaultProps</code> in FSCs</h2>
<p>When using FSCs, you define <code>propTypes</code> and <code>defaultProps</code> on the function itself:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">Username</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token operator"><</span>p<span class="token operator">></span><span class="token operator">...</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br><br>Username<span class="token punctuation">.</span>propTypes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">username</span><span class="token operator">:</span> React<span class="token punctuation">.</span>PropTypes<span class="token punctuation">.</span>string<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br>Username<span class="token punctuation">.</span>defaultProps <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">username</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h2>Context in FSCs</h2>
<p>Although you should generally be wary of context in React, <a href="http://javascriptplayground.com/blog/2017/02/context-in-reactjs-applications/">as I blogged about recently</a>, FSCs do still support context if you need them to. When using context, it's simply passed in as the second argument:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">Username</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">props<span class="token punctuation">,</span> context</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token operator"><</span>p<span class="token operator">></span>Username is <span class="token punctuation">{</span>context<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br><br>FooComponent<span class="token punctuation">.</span>contextTypes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">name</span><span class="token operator">:</span> React<span class="token punctuation">.</span>PropTypes<span class="token punctuation">.</span>string<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>On the whole I advise mostly against context, for reasons documented in the above blog post, but it's good to know that if you need it, you are able to use it.</p>
<h2>Conclusion</h2>
<p>To conclude, I would actively encourage you to think about using FSCs for as much of your application as you can. They are cleaner, have the potential to be more performant as React develops, and encourage good patterns in your React codebase that will lead to a more maintainable application as it grows.</p>
<p><em>Huge thanks to <a href="https://twitter.com/acemarke">Mark Erikson</a> for taking time to review this blog post.</em></p>
Building Langton's Ant in Elm2017-03-14T00:00:00+00:00http://www.jackfranklin.co.uk/blog/langtons-ant-elm-lang/<p>Last week I attended the <a href="https://www.meetup.com/Elm-London-Meetup/">Elm London meetup</a>, arranged by <a href="http://twitter.com/krisajenkins">Kris Jenkins</a>, who always produces a great selection of challenges for people to take on for all skill levels. Along with <a href="http://twitter.com/isaacseymour">Isaac</a>, we decided to take on Kris' challenge to build Langton's Ant in Elm.</p>
<h2>Langton's Ant</h2>
<p>Langton's Ant is a game similar to <a href="https://en.wikipedia.org/wiki/Conway's_Game_of_Life">Conway's Game of Life</a> in that cells on a game board change from being alive to dead based on their surroundings and certain criteria. In Langton's Ant there is a small ant on the board that moves and changes squares as it goes. The ant starts on any random square, and on each move it:</p>
<ol>
<li>Based on the colour of the square, it either turns 90 degrees right, or 90 degrees left.</li>
<li>Changes the colour of the square it's on from black to white, or vice versa.</li>
<li>Moves forward one square in the direction it's facing.</li>
</ol>
<p>The fact that the game has well defined rules makes it perfect for a short hack event, so we set about building it in Elm.</p>
<h2>Getting started</h2>
<p>I used <a href="https://github.com/halfzebra/create-elm-app">create-elm-app</a> to quickly get the app going. It's a really handy way to get a working application and local server up without having to think about it, and I highly recommend it.</p>
<h2>Defining types</h2>
<p>When working in Elm the first thing I always do is define the types for the key concepts of the application. Looking through Langton's ant, we could see we'd need to model:</p>
<ul>
<li>The concept of an <code>Ant</code>.</li>
<li><code>Cell</code>s on a game <code>Board</code>.</li>
<li><code>Coord</code>s which cells are positioned at on the board.</li>
<li>The <code>Direction</code> of the ant.</li>
<li>The <code>Colour</code> of a cell.</li>
</ul>
<p>Starting with the easier ones, a <code>Direction</code> is a union type that can be one of <code>Up</code>, <code>Down</code>, <code>Left</code> or <code>Right</code>:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token keyword">type</span> <span class="token constant">Direction</span><br> <span class="token operator">=</span> <span class="token constant">Up</span><br> <span class="token operator">|</span> <span class="token constant">Down</span><br> <span class="token operator">|</span> <span class="token constant">Left</span><br> <span class="token operator">|</span> <span class="token constant">Right</span></code></pre>
<p>And similarly, a <code>Colour</code> is either <code>White</code> or <code>Black</code>:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token keyword">type</span> <span class="token constant">Colour</span><br> <span class="token operator">=</span> <span class="token constant">White</span><br> <span class="token operator">|</span> <span class="token constant">Black</span></code></pre>
<p>And a coordinate, or <code>Coord</code>, is a tuple of <code>(x, y)</code>:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token keyword">type</span> <span class="token hvariable">alias</span> <span class="token constant">Coord</span> <span class="token operator">=</span><br> <span class="token punctuation">(</span> <span class="token constant">Int</span><span class="token punctuation">,</span> <span class="token constant">Int</span> <span class="token punctuation">)</span></code></pre>
<p>Once you have these, it's easy to combine them to make up the "bigger" types. A <code>cell</code> is a record that has a coordinate pair and a colour:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token keyword">type</span> <span class="token hvariable">alias</span> <span class="token constant">Cell</span> <span class="token operator">=</span><br> <span class="token punctuation">{</span> <span class="token hvariable">position</span> <span class="token operator">:</span> <span class="token constant">Coord</span><br> <span class="token punctuation">,</span> <span class="token hvariable">colour</span> <span class="token operator">:</span> <span class="token constant">Colour</span><br> <span class="token punctuation">}</span></code></pre>
<p>And the <code>Ant</code> is a record with a position and a direction:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token keyword">type</span> <span class="token hvariable">alias</span> <span class="token constant">Ant</span> <span class="token operator">=</span><br> <span class="token punctuation">{</span> <span class="token hvariable">position</span> <span class="token operator">:</span> <span class="token constant">Coord</span><br> <span class="token punctuation">,</span> <span class="token hvariable">direction</span> <span class="token operator">:</span> <span class="token constant">Direction</span><br> <span class="token punctuation">}</span></code></pre>
<p>The board is then a dictionary (quite similar to a JavaScript object, or a Ruby hash) that has coordinates as its keys, and then <code>Cell</code>s as its values. There's a bit of duplication here because you're using the coordinates for the keys of the dictionary, and then storing the keys in the cell, but we left it like that because it's nice to be able to have a cell tell you its position, without having to keep a reference to the coordinates around.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token keyword">type</span> <span class="token hvariable">alias</span> <span class="token constant">Board</span> <span class="token operator">=</span><br> <span class="token constant">Dict</span> <span class="token constant">Coord</span> <span class="token constant">Cell</span></code></pre>
<p>Finally, the <code>Model</code> has a <code>board</code> and an <code>ant</code>:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token keyword">type</span> <span class="token hvariable">alias</span> <span class="token constant">Model</span> <span class="token operator">=</span><br> <span class="token punctuation">{</span> <span class="token hvariable">board</span> <span class="token operator">:</span> <span class="token constant">Board</span><br> <span class="token punctuation">,</span> <span class="token hvariable">ant</span> <span class="token operator">:</span> <span class="token constant">Ant</span><br> <span class="token punctuation">}</span></code></pre>
<p>This method of defining the types is such a good way to think about your application and I highly recommend doing so. Even if you realise that you haven't quite modelled your types right later, it's easy to change them and let the compiler walk you through fixing them. They say if you define your types right, the rest of your application easily falls into place, and I'd say that's definitely true of Elm.</p>
<h2>Initial State</h2>
<p>The initial state of the world is an ant at position <code>(0, 0)</code> facing <code>Left</code> (you could pick any direction, it doesn't matter) and an empty list of cells:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">initialCells</span> <span class="token operator">:</span> <span class="token constant">Board</span><br><span class="token hvariable">initialCells</span> <span class="token operator">=</span><br> <span class="token hvariable">Dict<span class="token punctuation">.</span>empty</span><br><br><br><span class="token hvariable">initialAnt</span> <span class="token operator">:</span> <span class="token constant">Ant</span><br><span class="token hvariable">initialAnt</span> <span class="token operator">=</span><br> <span class="token constant">Ant</span> <span class="token punctuation">(</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token constant">Left</span><br><br><br><span class="token builtin">init</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token constant">Model</span><span class="token punctuation">,</span> <span class="token constant">Cmd</span> <span class="token constant">Msg</span> <span class="token punctuation">)</span><br><span class="token builtin">init</span> <span class="token operator">=</span><br> <span class="token punctuation">(</span> <span class="token constant">Model</span> <span class="token hvariable">initialCells</span> <span class="token hvariable">initialAnt</span><span class="token punctuation">,</span> <span class="token hvariable">Cmd<span class="token punctuation">.</span>none</span> <span class="token punctuation">)</span></code></pre>
<p>The reason we have no cells to start with is because we don't actually need a cell to exist until the ant moves off it. When an ant reaches a square, it will turn the cell black if it's white, or white if it's black, and by default all cells are white. That means if there's no cell under the ant, we can just create a white one, and go from there.</p>
<h2>Moving on a tick</h2>
<p>There is no user input in Langton's Ant, and as such we needed a way to run the game every millisecond to advance it to the next stage. We can use subscriptions in Elm to do this.</p>
<p>In The Elm Architecture we define a <code>subscriptions</code> function which we can use to subscribe to events. Elm's <code>Time</code> module provides a way to send a <code>Msg</code> at defined time intervals:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">subscriptions</span> <span class="token operator">:</span> <span class="token constant">Model</span> <span class="token operator">-></span> <span class="token constant">Sub</span> <span class="token constant">Msg</span><br><span class="token hvariable">subscriptions</span> <span class="token hvariable">model</span> <span class="token operator">=</span><br> <span class="token hvariable">Time<span class="token punctuation">.</span>every</span> <span class="token punctuation">(</span><span class="token hvariable">Time<span class="token punctuation">.</span>millisecond</span><span class="token punctuation">)</span> <span class="token constant">Tick</span></code></pre>
<p>This instructs Elm's runtime to send a <code>Tick</code> message every millisecond.</p>
<h2>Dealing with a Tick</h2>
<p>The first thing to do is define our <code>Msg</code> type, that is, the types of messages we expect to flow through our system. In our case it's just one, <code>Tick</code>:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token keyword">type</span> <span class="token constant">Msg</span><br> <span class="token operator">=</span> <span class="token constant">Tick</span> <span class="token constant">Time</span></code></pre>
<p>When <code>Time.every</code> sends a <code>Tick</code> it will also send the current time with it, which we'll ignore, but we have to define our <code>Msg</code> type as <code>Tick Time</code> to keep the compiler happy. In our <code>update</code> function we'll simply hand off to a <code>tick</code> function that will run the actual game:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">update</span> <span class="token operator">:</span> <span class="token constant">Msg</span> <span class="token operator">-></span> <span class="token constant">Model</span> <span class="token operator">-></span> <span class="token punctuation">(</span> <span class="token constant">Model</span><span class="token punctuation">,</span> <span class="token constant">Cmd</span> <span class="token constant">Msg</span> <span class="token punctuation">)</span><br><span class="token hvariable">update</span> <span class="token hvariable">msg</span> <span class="token hvariable">model</span> <span class="token operator">=</span><br> <span class="token keyword">case</span> <span class="token hvariable">msg</span> <span class="token keyword">of</span><br> <span class="token constant">Tick</span> <span class="token hvariable">_</span> <span class="token operator">-></span><br> <span class="token punctuation">(</span> <span class="token hvariable">tick</span> <span class="token hvariable">model</span><span class="token punctuation">,</span> <span class="token hvariable">Cmd<span class="token punctuation">.</span>none</span> <span class="token punctuation">)</span></code></pre>
<h2>Defining <code>tick</code></h2>
<p>Recall that there are three parts to a move in Langton's Ant:</p>
<ol>
<li>Based on the colour of the square, it either turns 90 degrees right, or 90 degrees left.</li>
<li>Changes the colour of the square it's on from black to white, or vice versa.</li>
<li>Moves forward one square in the direction it's facing.</li>
</ol>
<p>Breaking that into code, the first thing we need to do is get the current cell that the ant is on. We can do that because an <code>Ant</code> has a <code>position</code> key that is a coordinate pair, so we can write a function that gets the cell for the ant:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">getCell</span> <span class="token operator">:</span> <span class="token constant">Board</span> <span class="token operator">-></span> <span class="token constant">Coord</span> <span class="token operator">-></span> <span class="token constant">Cell</span><br><span class="token hvariable">getCell</span> <span class="token hvariable">board</span> <span class="token hvariable">coord</span> <span class="token operator">=</span><br> <span class="token hvariable">Dict<span class="token punctuation">.</span>get</span> <span class="token hvariable">coord</span> <span class="token hvariable">board</span> <span class="token operator">|></span> <span class="token hvariable">Maybe<span class="token punctuation">.</span>withDefault</span> <span class="token punctuation">(</span><span class="token constant">Cell</span> <span class="token hvariable">coord</span> <span class="token constant">White</span><span class="token punctuation">)</span></code></pre>
<p>We try to get the cell for the given coordinates, and if it doesn't exist, we'll just default to a <code>White</code> cell at those coordinates.</p>
<p>Once we have that cell, we need to flip it's colour:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">tick</span> <span class="token operator">:</span> <span class="token constant">Model</span> <span class="token operator">-></span> <span class="token constant">Model</span><br><span class="token hvariable">tick</span> <span class="token punctuation">{</span> <span class="token hvariable">ant</span><span class="token punctuation">,</span> <span class="token hvariable">board</span> <span class="token punctuation">}</span> <span class="token operator">=</span><br> <span class="token keyword">let</span><br> <span class="token hvariable">currentCell</span> <span class="token operator">=</span><br> <span class="token hvariable">getCell</span> <span class="token hvariable">board</span> <span class="token hvariable">ant</span><span class="token punctuation">.</span><span class="token hvariable">position</span><br><br> <span class="token hvariable">newCell</span> <span class="token operator">=</span><br> <span class="token punctuation">{</span> <span class="token hvariable">currentCell</span> <span class="token operator">|</span> <span class="token hvariable">colour</span> <span class="token operator">=</span> <span class="token hvariable">flipColour</span> <span class="token hvariable">currentCell</span><span class="token punctuation">.</span><span class="token hvariable">colour</span> <span class="token punctuation">}</span><br> <span class="token operator">...</span></code></pre>
<p>Where <code>flipColour</code> just swaps <code>Black</code> to <code>White</code> and vice-versa:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">flipColour</span> <span class="token operator">:</span> <span class="token constant">Colour</span> <span class="token operator">-></span> <span class="token constant">Colour</span><br><span class="token hvariable">flipColour</span> <span class="token hvariable">colour</span> <span class="token operator">=</span><br> <span class="token keyword">case</span> <span class="token hvariable">colour</span> <span class="token keyword">of</span><br> <span class="token constant">Black</span> <span class="token operator">-></span><br> <span class="token constant">White</span><br><br> <span class="token constant">White</span> <span class="token operator">-></span><br> <span class="token constant">Black</span></code></pre>
<p>Once we have the new cell we use <code>Dict.insert</code> to insert it back onto our board. <code>Dict.insert</code> will overwrite a cell if one already exists, so it's perfect because we don't need any custom logic depending on if the cell exists or not.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">newCell</span> <span class="token operator">=</span><br> <span class="token punctuation">{</span> <span class="token hvariable">currentCell</span> <span class="token operator">|</span> <span class="token hvariable">colour</span> <span class="token operator">=</span> <span class="token hvariable">flipColour</span> <span class="token hvariable">currentCell</span><span class="token punctuation">.</span><span class="token hvariable">colour</span> <span class="token punctuation">}</span><br><br><span class="token hvariable">newBoard</span> <span class="token operator">=</span><br> <span class="token hvariable">Dict<span class="token punctuation">.</span>insert</span> <span class="token hvariable">ant</span><span class="token punctuation">.</span><span class="token hvariable">position</span> <span class="token hvariable">newCell</span> <span class="token hvariable">board</span></code></pre>
<p>Next, we need to deal with the ant. Depending on the colour of the cell when the ant arrived on it, it needs to either flip itself 90 degrees left or right, so we can update the ant and change its direction:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">newAnt1</span> <span class="token operator">=</span><br> <span class="token punctuation">{</span> <span class="token hvariable">ant</span> <span class="token operator">|</span> <span class="token hvariable">direction</span> <span class="token operator">=</span> <span class="token hvariable">getNextDirection</span> <span class="token hvariable">ant</span> <span class="token hvariable">currentCell</span> <span class="token punctuation">}</span></code></pre>
<p>Where <code>getNextDirection</code> looks like so:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">getNextDirection</span> <span class="token operator">:</span> <span class="token constant">Ant</span> <span class="token operator">-></span> <span class="token constant">Cell</span> <span class="token operator">-></span> <span class="token constant">Direction</span><br><span class="token hvariable">getNextDirection</span> <span class="token punctuation">{</span> <span class="token hvariable">direction</span> <span class="token punctuation">}</span> <span class="token punctuation">{</span> <span class="token hvariable">colour</span> <span class="token punctuation">}</span> <span class="token operator">=</span><br> <span class="token keyword">case</span> <span class="token punctuation">(</span> <span class="token hvariable">colour</span><span class="token punctuation">,</span> <span class="token hvariable">direction</span> <span class="token punctuation">)</span> <span class="token keyword">of</span><br> <span class="token punctuation">(</span> <span class="token constant">White</span><span class="token punctuation">,</span> <span class="token constant">Up</span> <span class="token punctuation">)</span> <span class="token operator">-></span><br> <span class="token constant">Right</span><br><br> <span class="token punctuation">(</span> <span class="token constant">White</span><span class="token punctuation">,</span> <span class="token constant">Right</span> <span class="token punctuation">)</span> <span class="token operator">-></span><br> <span class="token constant">Down</span><br><br> <span class="token punctuation">(</span> <span class="token constant">White</span><span class="token punctuation">,</span> <span class="token constant">Down</span> <span class="token punctuation">)</span> <span class="token operator">-></span><br> <span class="token constant">Left</span><br><br> <span class="token punctuation">(</span> <span class="token constant">White</span><span class="token punctuation">,</span> <span class="token constant">Left</span> <span class="token punctuation">)</span> <span class="token operator">-></span><br> <span class="token constant">Up</span><br><br> <span class="token punctuation">(</span> <span class="token constant">Black</span><span class="token punctuation">,</span> <span class="token constant">Up</span> <span class="token punctuation">)</span> <span class="token operator">-></span><br> <span class="token constant">Left</span><br><br> <span class="token punctuation">(</span> <span class="token constant">Black</span><span class="token punctuation">,</span> <span class="token constant">Right</span> <span class="token punctuation">)</span> <span class="token operator">-></span><br> <span class="token constant">Up</span><br><br> <span class="token punctuation">(</span> <span class="token constant">Black</span><span class="token punctuation">,</span> <span class="token constant">Down</span> <span class="token punctuation">)</span> <span class="token operator">-></span><br> <span class="token constant">Right</span><br><br> <span class="token punctuation">(</span> <span class="token constant">Black</span><span class="token punctuation">,</span> <span class="token constant">Left</span> <span class="token punctuation">)</span> <span class="token operator">-></span><br> <span class="token constant">Down</span></code></pre>
<p>In the arguments note how we destructure the ant, pulling out just the <code>direction</code>, and do the same with the cell to pull its <code>direction</code>. We then combine them into a tuple and pattern match on them, encoding the rules of the ant and how it flips based on the colour.</p>
<p>Finally, now we have the ant facing the right direction, we need to update its positional coordinates to move it in the right direction:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">newAnt2</span> <span class="token operator">=</span><br> <span class="token punctuation">{</span> <span class="token hvariable">newAnt1</span> <span class="token operator">|</span> <span class="token hvariable">position</span> <span class="token operator">=</span> <span class="token hvariable">getCoordInFront</span> <span class="token hvariable">newAnt1</span> <span class="token punctuation">}</span></code></pre>
<p>Where <code>getCoordInFront</code> maps the ant's positional coordinates, changing either the <code>x</code> or <code>y</code> by one, positively or negatively depending on the direction:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">getCoordInFront</span> <span class="token operator">:</span> <span class="token constant">Ant</span> <span class="token operator">-></span> <span class="token constant">Coord</span><br><span class="token hvariable">getCoordInFront</span> <span class="token punctuation">{</span> <span class="token hvariable">direction</span><span class="token punctuation">,</span> <span class="token hvariable">position</span> <span class="token punctuation">}</span> <span class="token operator">=</span><br> <span class="token keyword">case</span> <span class="token hvariable">direction</span> <span class="token keyword">of</span><br> <span class="token constant">Up</span> <span class="token operator">-></span><br> <span class="token hvariable">Tuple<span class="token punctuation">.</span>mapSecond</span> <span class="token punctuation">(</span><span class="token operator">\</span><span class="token hvariable">x</span> <span class="token operator">-></span> <span class="token hvariable">x</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token hvariable">position</span><br><br> <span class="token constant">Down</span> <span class="token operator">-></span><br> <span class="token hvariable">Tuple<span class="token punctuation">.</span>mapSecond</span> <span class="token punctuation">(</span><span class="token operator">\</span><span class="token hvariable">x</span> <span class="token operator">-></span> <span class="token hvariable">x</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token hvariable">position</span><br><br> <span class="token constant">Left</span> <span class="token operator">-></span><br> <span class="token hvariable">Tuple<span class="token punctuation">.</span>mapFirst</span> <span class="token punctuation">(</span><span class="token operator">\</span><span class="token hvariable">x</span> <span class="token operator">-></span> <span class="token hvariable">x</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token hvariable">position</span><br><br> <span class="token constant">Right</span> <span class="token operator">-></span><br> <span class="token hvariable">Tuple<span class="token punctuation">.</span>mapFirst</span> <span class="token punctuation">(</span><span class="token operator">\</span><span class="token hvariable">x</span> <span class="token operator">-></span> <span class="token hvariable">x</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token hvariable">position</span></code></pre>
<p>Here <code>Tuple.mapFirst</code> and <code>Tuple.mapSecond</code> come in really handy to tidy this code up and keep it nice and succinct. We could have written <code>(\x -> x + 1)</code> as <code>((+) 1)</code>, but we didn't because doing <code>((-1) x)</code> ends up as <code>-1 + x</code> which is not what we want, so here we prefer the longer form to keep it clear.</p>
<p>With that, our <code>tick</code> function is done and we have the new model being generated. Next up, we'll render it onto the page.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">tick</span> <span class="token operator">:</span> <span class="token constant">Model</span> <span class="token operator">-></span> <span class="token constant">Model</span><br><span class="token hvariable">tick</span> <span class="token punctuation">{</span> <span class="token hvariable">ant</span><span class="token punctuation">,</span> <span class="token hvariable">board</span> <span class="token punctuation">}</span> <span class="token operator">=</span><br> <span class="token keyword">let</span><br> <span class="token hvariable">currentCell</span> <span class="token operator">=</span><br> <span class="token hvariable">getCell</span> <span class="token hvariable">board</span> <span class="token hvariable">ant</span><span class="token punctuation">.</span><span class="token hvariable">position</span><br><br> <span class="token hvariable">newCell</span> <span class="token operator">=</span><br> <span class="token punctuation">{</span> <span class="token hvariable">currentCell</span> <span class="token operator">|</span> <span class="token hvariable">colour</span> <span class="token operator">=</span> <span class="token hvariable">flipColour</span> <span class="token hvariable">currentCell</span><span class="token punctuation">.</span><span class="token hvariable">colour</span> <span class="token punctuation">}</span><br><br> <span class="token hvariable">newBoard</span> <span class="token operator">=</span><br> <span class="token hvariable">Dict<span class="token punctuation">.</span>insert</span> <span class="token hvariable">ant</span><span class="token punctuation">.</span><span class="token hvariable">position</span> <span class="token hvariable">newCell</span> <span class="token hvariable">board</span><br><br> <span class="token hvariable">newAnt1</span> <span class="token operator">=</span><br> <span class="token punctuation">{</span> <span class="token hvariable">ant</span> <span class="token operator">|</span> <span class="token hvariable">direction</span> <span class="token operator">=</span> <span class="token hvariable">getNextDirection</span> <span class="token hvariable">ant</span> <span class="token hvariable">currentCell</span> <span class="token punctuation">}</span><br><br> <span class="token hvariable">newAnt2</span> <span class="token operator">=</span><br> <span class="token punctuation">{</span> <span class="token hvariable">newAnt1</span> <span class="token operator">|</span> <span class="token hvariable">position</span> <span class="token operator">=</span> <span class="token hvariable">getCoordInFront</span> <span class="token hvariable">newAnt1</span> <span class="token punctuation">}</span><br> <span class="token keyword">in</span><br> <span class="token constant">Model</span> <span class="token hvariable">newBoard</span> <span class="token hvariable">newAnt2</span></code></pre>
<h2>Rendering the board</h2>
<p>Rather than use HTML, we chose to use <a href="http://package.elm-lang.org/packages/elm-lang/svg/latest/Svg">elm-lang/svg</a> for our board.</p>
<p>Our <code>view</code> function looks like so:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">view</span> <span class="token operator">:</span> <span class="token constant">Model</span> <span class="token operator">-></span> <span class="token constant">Html</span> <span class="token constant">Msg</span><br><span class="token hvariable">view</span> <span class="token punctuation">{</span> <span class="token hvariable">board</span><span class="token punctuation">,</span> <span class="token hvariable">ant</span> <span class="token punctuation">}</span> <span class="token operator">=</span><br> <span class="token hvariable">svg</span> <span class="token punctuation">[</span> <span class="token hvariable">width</span> <span class="token string">"600"</span><span class="token punctuation">,</span> <span class="token hvariable">height</span> <span class="token string">"600"</span><span class="token punctuation">,</span> <span class="token hvariable">viewBox</span> <span class="token string">"-500 -500 1000 1000"</span> <span class="token punctuation">]</span><br> <span class="token punctuation">[</span> <span class="token hvariable">renderCells</span> <span class="token hvariable">board</span><br> <span class="token punctuation">,</span> <span class="token hvariable">renderAnt</span> <span class="token hvariable">ant</span><br> <span class="token punctuation">]</span></code></pre>
<p>By creating the SVG with a <code>viewBox</code> attribute of <code>-500 -500 1000 1000</code> we create an SVG element that puts an element with <code>x "0", y "0"</code> in the middle of the box. This means when we render our first cell at <code>(0, 0)</code>, it will go in the middle of the SVG. <a href="https://css-tricks.com/scale-svg/">You can read more about scaling SVGs on CSS Tricks</a>.</p>
<h2>Rendering the cells</h2>
<p>To render the cells, we map over all the values using <code>Dict.values</code> and render each one:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">renderCell</span> <span class="token operator">:</span> <span class="token constant">Cell</span> <span class="token operator">-></span> <span class="token constant">Svg</span> <span class="token constant">Msg</span><br><span class="token hvariable">renderCell</span> <span class="token punctuation">{</span> <span class="token hvariable">position</span><span class="token punctuation">,</span> <span class="token hvariable">colour</span> <span class="token punctuation">}</span> <span class="token operator">=</span><br> <span class="token hvariable">renderItem</span> <span class="token hvariable">position</span> <span class="token punctuation">(</span><span class="token hvariable">colourToSvgFill</span> <span class="token hvariable">colour</span><span class="token punctuation">)</span><br><br><br><span class="token hvariable">renderCells</span> <span class="token operator">:</span> <span class="token constant">Board</span> <span class="token operator">-></span> <span class="token constant">Svg</span> <span class="token constant">Msg</span><br><span class="token hvariable">renderCells</span> <span class="token hvariable">board</span> <span class="token operator">=</span><br> <span class="token hvariable">g</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">(</span><span class="token hvariable">Dict<span class="token punctuation">.</span>values</span> <span class="token hvariable">board</span> <span class="token operator">|></span> <span class="token constant">List</span><span class="token punctuation">.</span><span class="token builtin">map</span> <span class="token hvariable">renderCell</span><span class="token punctuation">)</span></code></pre>
<p>Notice how we use the SVG element <code>g</code> to group elements up. <code>g</code> is really handy for grouping related elements without it applying any extra styling or behaviour. It's akin to a <code>div</code> in HTML.</p>
<p><code>renderCell</code> calls the generic <code>renderItem</code> function, passing in the position of the cell and the colour. <code>colourToSvgFill</code> just maps the type <code>Black</code> to <code>"black"</code>, and the same with <code>White</code>.</p>
<p><code>renderCell</code> produces an SVG <code>rect</code>element with the right width, height and positions applied:</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">renderItem</span> <span class="token operator">:</span> <span class="token constant">Coord</span> <span class="token operator">-></span> <span class="token constant">String</span> <span class="token operator">-></span> <span class="token constant">Svg</span> <span class="token constant">Msg</span><br><span class="token hvariable">renderItem</span> <span class="token punctuation">(</span> <span class="token hvariable">xPos</span><span class="token punctuation">,</span> <span class="token hvariable">yPos</span> <span class="token punctuation">)</span> <span class="token hvariable">colour</span> <span class="token operator">=</span><br> <span class="token hvariable">rect</span><br> <span class="token punctuation">[</span> <span class="token hvariable">stroke</span> <span class="token string">"black"</span><br> <span class="token punctuation">,</span> <span class="token hvariable">fill</span> <span class="token hvariable">colour</span><br> <span class="token punctuation">,</span> <span class="token hvariable">x</span> <span class="token punctuation">(</span><span class="token hvariable">toString</span> <span class="token punctuation">(</span><span class="token hvariable">xPos</span> <span class="token operator">*</span> <span class="token number">10</span> <span class="token operator">-</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token punctuation">,</span> <span class="token hvariable">y</span> <span class="token punctuation">(</span><span class="token hvariable">toString</span> <span class="token punctuation">(</span><span class="token hvariable">yPos</span> <span class="token operator">*</span> <span class="token number">10</span> <span class="token operator">-</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token punctuation">,</span> <span class="token hvariable">width</span> <span class="token string">"10"</span><br> <span class="token punctuation">,</span> <span class="token hvariable">height</span> <span class="token string">"10"</span><br> <span class="token punctuation">]</span><br> <span class="token punctuation">[</span><span class="token punctuation">]</span></code></pre>
<p>The <code>renderAnt</code> function also uses <code>renderItem</code>, just passing in a different colour depending on the ant's direction (which you don't need to do, we just did it so we could see the direction the ant was heading). <code>colourForAnt</code> just maps the ant's colour to a direction.</p>
<pre class="language-haskell"><code class="language-haskell"><span class="token hvariable">renderAnt</span> <span class="token operator">:</span> <span class="token constant">Ant</span> <span class="token operator">-></span> <span class="token constant">Svg</span> <span class="token constant">Msg</span><br><span class="token hvariable">renderAnt</span> <span class="token punctuation">{</span> <span class="token hvariable">position</span><span class="token punctuation">,</span> <span class="token hvariable">direction</span> <span class="token punctuation">}</span> <span class="token operator">=</span><br> <span class="token hvariable">renderItem</span> <span class="token hvariable">position</span> <span class="token punctuation">(</span><span class="token hvariable">colourForAnt</span> <span class="token hvariable">direction</span><span class="token punctuation">)</span></code></pre>
<h2>Fin</h2>
<p>And with that, we have our ant!</p>
<p><img src="http://www.jackfranklin.co.uk/img/posts/langtons-ant/langtons-ant.png" alt=""></p>
<p>If you'd like to find the full code, you can <a href="https://github.com/jackfranklin/langtons-ant-elm">find it on Github</a>. I'd encourage you to have a try at building Langton's Ant, it's a well defined, contained challenge that has some really interesting parts. Elm's type system makes it a perfect fit for a challenge like this, and it was a neat way to explore and learn more about the language.</p>
Getting started with TypeScript and React2017-04-24T00:00:00+00:00http://www.jackfranklin.co.uk/blog/react-typescript/<p>I've recently been getting into TypeScript following a lot of positive blogs about it from <a href="https://medium.com/@tomdale/glimmer-js-whats-the-deal-with-typescript-f666d1a3aad0">Tom Dale</a> and others. Today I'll show you how I've set up a TypeScript project from scratch that uses React, and Webpack for managing the build process. I'll also discuss my initial impressions of TypeScript and in particular working with TypeScript and ReactJS.</p>
<p>I won't be going into detail on the specifics of TypeScript's syntax, but you can read either the <a href="https://www.typescriptlang.org/docs/tutorial.html">TypeScript handbook</a> or the free book <a href="https://basarat.gitbooks.io/typescript/content/docs/getting-started.html">TypeScript Deep Dive</a> which will also give you a great introduction to the language.</p>
<p><strong>Update:</strong> If you'd like to read this post in German, you can do so <a href="https://reactx.de/artikel/reactjs-typescript/">thanks to the awesome folks at Reactx.de</a>.</p>
<h2>Installing TypeScript and configuring it</h2>
<p>The first thing to do was install TypeScript locally into my <code>node_modules</code> directory, which I did using Yarn, first using <code>yarn init</code> to create a new project:</p>
<pre><code>yarn init
yarn add typescript
</code></pre>
<p>When you install TypeScript you get the <code>tsc</code> command line tool which can compile TypeScript but also create a starting <code>tsconfig.json</code> for you to edit. You can get this by running <code>tsc --init</code> - if you've installed TypeScript locally you'll need to run <code>./node_modules/.bin/tsc --init</code>.</p>
<p><strong>Note:</strong> I have the <code>./node_modules/.bin</code> directory on my <code>$PATH</code>, <a href="https://github.com/jackfranklin/dotfiles/blob/master/zsh/zshrc#L101">which you can find in my dotfiles</a>. This is <em>slightly</em> risky, as I could accidentally run any executable that's in that directory, but I'm willing to take that risk because I know what's installed locally and it saves a lot of typing!</p>
<p><code>tsc --init</code> generates a <code>tsconfig.json</code> which is where all the config for TypeScript's compiler lives. There's a few changes I've made to the default config, and the one I'm using is below:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br> <span class="token string-property property">"compilerOptions"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">"module"</span><span class="token operator">:</span> <span class="token string">"es6"</span><span class="token punctuation">,</span> <span class="token comment">// use ES2015 modules</span><br> <span class="token string-property property">"target"</span><span class="token operator">:</span> <span class="token string">"es6"</span><span class="token punctuation">,</span> <span class="token comment">// compile to ES2015 (Babel will do the rest)</span><br> <span class="token string-property property">"allowSyntheticDefaultImports"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// see below</span><br> <span class="token string-property property">"baseUrl"</span><span class="token operator">:</span> <span class="token string">"src"</span><span class="token punctuation">,</span> <span class="token comment">// enables you to import relative to this folder</span><br> <span class="token string-property property">"sourceMap"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// make TypeScript generate sourcemaps</span><br> <span class="token string-property property">"outDir"</span><span class="token operator">:</span> <span class="token string">"ts-build"</span><span class="token punctuation">,</span> <span class="token comment">// output directory to build to (irrelevant because we use Webpack most of the time)</span><br> <span class="token string-property property">"jsx"</span><span class="token operator">:</span> <span class="token string">"preserve"</span><span class="token punctuation">,</span> <span class="token comment">// enable JSX mode, but "preserve" tells TypeScript to not transform it (we'll use Babel)</span><br> <span class="token string-property property">"strict"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token string-property property">"exclude"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token string">"node_modules"</span> <span class="token comment">// don't run on any code in the node_modules directory</span><br> <span class="token punctuation">]</span><br><span class="token punctuation">}</span></code></pre>
<h3><code>allowSyntheticDefaultImports</code></h3>
<p>This rule allows you to use ES2015 style default imports even when the code you're importing doesn't have an ES2015 default export.</p>
<p>This happens when you import, for example, React, whose code is not written in ES2015 (the source code is, but React ships a built version). This means that it technically doesn't have an ES2015 default export, so TypeScript will tell you so when you import it. However, build tools like Webpack are able to import the right thing, so I turn this option on because I prefer <code>import React from 'react'</code> over <code>import * as React from 'react'</code>.</p>
<h3><code>strict</code>: true</h3>
<p><a href="https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#new---strict-master-option">TypeScript version 2.3</a> introduced a new config option, <code>strict</code>. When turned on this configures TypeScript's compiler to be as strict as possible - this might not be what you want if you're porting some JS to TS, but for new projects it makes sense to be as strict as possible out of the box. This turns on a few different settings, the most notable of which are <code>noImplicitAny</code> and <code>strictNullChecks</code>:</p>
<h4><code>noImplicitAny</code></h4>
<p>Often when you want to add TypeScript to an existing project TypeScript makes it easy by not throwing an error when you don't declare the types of variables. However, when I'm creating a new TypeScript project from scratch I'd like the compiler to be as strict as possible.</p>
<p>One of the things TypeScript does by default is implicitly add the <code>any</code> type to variables. <code>any</code> is effectively an escape hatch in TypeScript to say "don't type-check this, it can be any value". That's useful when you're porting JavaScript, but it's better to be strict when you can. With this setting set to <code>true</code>, you can't miss any declarations. For example, this code will error when <code>noImplicitAny</code> is set to <code>true</code>:</p>
<pre><code>function log(thing) {
console.log('thing', thing)
}
</code></pre>
<p>You can read more about this in the <a href="https://basarat.gitbooks.io/typescript/docs/options/noImplicitAny.html">TypeScript Deep Dive</a>.</p>
<h4><code>strictNullChecks</code></h4>
<p>This is another option that makes TypeScript's compiler stricter. The TypeScript Deep Dive book has a <a href="https://basarat.gitbooks.io/typescript/docs/options/strictNullChecks.html">great section on this option</a>. With this option on, TypeScript will spot more occasions where you're referencing a value that might be undefined, it will error at you. For example:</p>
<pre class="language-js"><code class="language-js">person<span class="token punctuation">.</span>age<span class="token punctuation">.</span><span class="token function">increment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>With <code>strictNullChecks</code>, if TypeScript thinks that <code>person</code> or <code>person.age</code> might be <code>undefined</code>, it will error and make sure you deal with it. This prevents runtime errors so it seems like a pretty good option to enable from the get go.</p>
<h2>Setting up Webpack, Babel and TypeScript</h2>
<p>I'm a big Webpack fan; I enjoy the ecosystem of plugins available, I like the developer workflow and it's good at managing complex applications and their build pipeline. Therefore, even though we could just use TypeScript's compiler, I'd still like to add Webpack in. We'll also need Babel because the TypeScript compiler is going to output ES2015 + React for us, so we'll get Babel to do the work. Let's install Webpack, Babel and the relevant presets, along with <a href="https://github.com/TypeStrong/ts-loader">ts-loader</a>, the Webpack plugin for TypeScript.</p>
<p>There is also <a href="https://github.com/s-panferov/awesome-typescript-loader">awesome-typescript-loader</a>, but I found <code>ts-loader</code> first and so far it's been great. I would love to hear from anyone who uses the <code>awesome-typescript-loader</code>, and how it compares.</p>
<pre><code>yarn add webpack babel-core babel-loader babel-preset-es2015 babel-preset-react ts-loader webpack-dev-server
</code></pre>
<p>At this point I have to thank Tom Duncalf, whose <a href="http://blog.tomduncalf.com/posts/setting-up-typescript-and-react/">blog post on TypeScript 1.9 + React</a> was a brilliant starting point for me and I highly recommend it.</p>
<p>There's nothing too surprising in the Webpack config, but I've left some comments in the code to explain it:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> webpack <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'webpack'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'path'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br>module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token comment">// put sourcemaps inline</span><br> <span class="token literal-property property">devtool</span><span class="token operator">:</span> <span class="token string">'eval'</span><span class="token punctuation">,</span><br><br> <span class="token comment">// entry point of our application, within the `src` directory (which we add to resolve.modules below):</span><br> <span class="token literal-property property">entry</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'index.tsx'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br><br> <span class="token comment">// configure the output directory and publicPath for the devServer</span><br> <span class="token literal-property property">output</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">filename</span><span class="token operator">:</span> <span class="token string">'app.js'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">publicPath</span><span class="token operator">:</span> <span class="token string">'dist'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">path</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'dist'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><br> <span class="token comment">// configure the dev server to run</span><br> <span class="token literal-property property">devServer</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">port</span><span class="token operator">:</span> <span class="token number">3000</span><span class="token punctuation">,</span><br> <span class="token literal-property property">historyApiFallback</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br> <span class="token literal-property property">inline</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><br> <span class="token comment">// tell Webpack to load TypeScript files</span><br> <span class="token literal-property property">resolve</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token comment">// Look for modules in .ts(x) files first, then .js</span><br> <span class="token literal-property property">extensions</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'.ts'</span><span class="token punctuation">,</span> <span class="token string">'.tsx'</span><span class="token punctuation">,</span> <span class="token string">'.js'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br><br> <span class="token comment">// add 'src' to the modules, so that when you import files you can do so with 'src' as the relative route</span><br> <span class="token literal-property property">modules</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'src'</span><span class="token punctuation">,</span> <span class="token string">'node_modules'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><br> <span class="token literal-property property">module</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">loaders</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token comment">// .ts(x) files should first pass through the Typescript loader, and then through babel</span><br> <span class="token punctuation">{</span><br> <span class="token literal-property property">test</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.tsx?$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span><br> <span class="token literal-property property">loaders</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'babel-loader'</span><span class="token punctuation">,</span> <span class="token string">'ts-loader'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token literal-property property">include</span><span class="token operator">:</span> path<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">'src'</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>We configure the loaders so that any <code>.ts(x)</code> file is first passed through <code>ts-loader</code>. This compiles it with TypeScript using the settings in our <code>tsconfig.json</code> - and emits <code>ES2015</code>. We then use Babel to convert that down to ES5. To do this I create a <code>.babelrc</code> that contains the presets that we need:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br> <span class="token string-property property">"presets"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"es2015"</span><span class="token punctuation">,</span> <span class="token string">"react"</span><span class="token punctuation">]</span><br><span class="token punctuation">}</span></code></pre>
<p>And with that, we're now ready to write our TypeScript application.</p>
<h2>Writing a TypeScript React component</h2>
<p>Now we are ready to create <code>src/index.tsx</code>, which will be our application's entry point. For now we can create a dummy component and render it to check it's all working.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> ReactDOM <span class="token keyword">from</span> <span class="token string">'react-dom'</span><span class="token punctuation">;</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>p<span class="token operator">></span>Hello world<span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br>ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token operator"><</span>App <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'app'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>If you run Webpack now against this code you'll see some errors:</p>
<pre><code>ERROR in ./src/index.tsx
(1,19): error TS2307: Cannot find module 'react'.
ERROR in ./src/index.tsx
(2,22): error TS2307: Cannot find module 'react-dom'.
</code></pre>
<p>This happens because TypeScript is trying to figure out the type of React, and what it exports, and is trying to do the same for React DOM. React isn't authored in TypeScript so it doesn't contain that information, but thankfully for this situation the community has created <a href="https://github.com/DefinitelyTyped/DefinitelyTyped">DefinitelyTyped</a>, a large repository of types for modules.</p>
<p>The installation mechanism changed recently; all the types are published under the npm <code>@types</code> scope, so to get the types for React and ReactDOM we run:</p>
<pre><code>yarn add @types/react
yarn add @types/react-dom
</code></pre>
<p>And with that the errors go away. Whenever you install a dependency you can always try installing the <code>@types</code> package too, or if you want to see if it has types available, you can use the <a href="https://microsoft.github.io/TypeSearch/">TypeSearch</a> website to do so.</p>
<h2>Running the app locally</h2>
<p>To run the app locally we just run the <code>webpack-dev-server</code> command. I set up a script, <code>start</code>, that will do just that:</p>
<pre class="language-js"><code class="language-js"><span class="token string-property property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">"start"</span><span class="token operator">:</span> <span class="token string">"webpack-dev-server"</span><br><span class="token punctuation">}</span></code></pre>
<p>The dev server will find the <code>webpack.config.json</code> file and use it to build our application.</p>
<p>If you run <code>yarn start</code> you will see the output from the server, including the <code>ts-loader</code> output that confirms it's all working.</p>
<pre><code>$ webpack-dev-server
Project is running at http://localhost:3000/
webpack output is served from /dist
404s will fallback to /index.html
ts-loader: Using typescript@2.3.0 and /Users/jackfranklin/git/interactive-react-introduction/tsconfig.json
Version: webpack 2.4.1
Time: 6077ms
Asset Size Chunks Chunk Names
app.js 1.14 MB 0 [emitted] [big] main
webpack: Compiled successfully.
</code></pre>
<p>To view it locally I just create an <code>index.html</code> file that loads our compiled code:</p>
<pre class="language-html"><code class="language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>My Typescript App<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>app<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>dist/app.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span></code></pre>
<p>You should see <code>Hello world!</code> on port 3000, and we have TypeScript working!</p>
<h2>Typing a module</h2>
<p>For a project I was working on I wanted to use the <a href="https://github.com/securingsincity/react-ace">React Ace module</a> to include a code editor in my project. However, the module doesn't provide types for it, and there is no <code>@types/react-ace</code> either. In this case, we have to add the types to our application so TypeScript knows how to type it. Whilst this can seem annoying, the benefits of having TypeScript at least know a little about all your third party dependencies will save you debugging time.</p>
<p>To define a file that has just types in, you suffix it <code>.d.ts</code> (the 'd' is for 'declaration') and you can read more about them on the <a href="https://www.typescriptlang.org/docs/handbook/declaration-files/introduction">TypeScript docs</a>. TypeScript will automatically find these files in your project, you don't need to explicitly import them.</p>
<p>I created the file <code>react-ace.d.ts</code>, and added the following code that creates the module and defines its default export as a React component:</p>
<pre class="language-js"><code class="language-js">declare module <span class="token string">'react-ace'</span> <span class="token punctuation">{</span><br> <span class="token keyword">interface</span> <span class="token class-name">ReactAceProps</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">mode</span><span class="token operator">:</span> string<br> <span class="token literal-property property">theme</span><span class="token operator">:</span> string<br> <span class="token literal-property property">name</span><span class="token operator">:</span> string<br> editorProps<span class="token operator">?</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><br> showPrintMargin<span class="token operator">?</span><span class="token operator">:</span> boolean<br> minLines<span class="token operator">?</span><span class="token operator">:</span> number<br> maxLines<span class="token operator">?</span><span class="token operator">:</span> number<br> wrapEnabled<span class="token operator">?</span><span class="token operator">:</span> boolean<br> <span class="token literal-property property">value</span><span class="token operator">:</span> string<br> highlightActiveLine<span class="token operator">?</span><span class="token operator">:</span> boolean<br> width<span class="token operator">?</span><span class="token operator">:</span> string<br> fontSize<span class="token operator">?</span><span class="token operator">:</span> number<br> <span class="token punctuation">}</span><br><br> <span class="token keyword">const</span> <span class="token literal-property property">ReactAce</span><span class="token operator">:</span> React<span class="token punctuation">.</span>ComponentClass<span class="token operator"><</span>ReactAceProps<span class="token operator">></span><br> <span class="token keyword">export</span> <span class="token operator">=</span> ReactAce<br><span class="token punctuation">}</span></code></pre>
<p>I first create a TypeScript interface for the properties that the component takes, and then the line <code>export = ReactAce</code> declares that the component is the object exported by the module. By typing the properties, TypeScript will tell me if I typo a property or forget to pass one, which is really valuable.</p>
<h2>Testing</h2>
<p>Finally, I also wanted to have a good testing set up with TypeScript. I'm a huge fan of Facebook's <a href="https://facebook.github.io/jest/">Jest</a>, and did some googling to find out if I could run it with TypeScript. Turns out it's very possible, and there's even the <a href="https://www.npmjs.com/package/ts-jest">ts-jest</a> package available which does all the heavy lifting. In addition, there is a <code>@types/jest</code> package so you can have all your tests type-checked too.</p>
<p>Huge thanks to RJ Zaworski, <a href="https://rjzaworski.com/2016/12/testing-typescript-with-jest">whose post on TypeScript and Jest</a> got me started on this topic. Once you install <code>ts-jest</code>, you just have to configure Jest, which is done in the <code>package.json</code>, with some settings:</p>
<pre class="language-js"><code class="language-js"><span class="token string-property property">"jest"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">"moduleFileExtensions"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token string">"ts"</span><span class="token punctuation">,</span><br> <span class="token string">"tsx"</span><span class="token punctuation">,</span><br> <span class="token string">"js"</span><br> <span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token string-property property">"transform"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">"\\.(ts|tsx)$"</span><span class="token operator">:</span> <span class="token string">"<rootDir>/node_modules/ts-jest/preprocessor.js"</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token string-property property">"testRegex"</span><span class="token operator">:</span> <span class="token string">"/*.spec.(ts|tsx|js)$"</span><br><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>The first setting tells Jest to look for <code>.ts</code> and <code>.tsx</code> files. The <code>transform</code> object tells Jest to run any TypeScript files through the ts-jest preprocessor, which runs them through the TypeScript compiler and produces JavaScript that Jest can consume. Finally, I updated the <code>testRegex</code> setting to look for any <code>*.spec.ts(x)</code> files, which is my preferred naming convention for tests.</p>
<p>With this, I can just run <code>jest</code> and have everything work as expected.</p>
<h2>Linting with TSLint</h2>
<p>Although TypeScript gives you a lot of checks on your code, I still wanted a linter to enforce some code style and quality checks. Much like ESLint to JavaScript, <a href="https://palantir.github.io/tslint/">TSLint</a> is the best option for checking TypeScript files. It works in the same way as ESLint - with a set of rules that you enable or disable, and there's also a <a href="https://github.com/palantir/tslint-react">TSLint-React</a> package to add React specific rules.</p>
<p>You can configure TSLint via a <code>tslint.json</code> file and mine is below. I use both the <code>tslint:latest</code> and <code>tslint-react</code> presets, which enables a bunch of rules. I disagree with some of the defaults though so I override them - you might choose to do differently - this is up to you!</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br> <span class="token string-property property">"defaultSeverity"</span><span class="token operator">:</span> <span class="token string">"error"</span><span class="token punctuation">,</span><br> <span class="token string-property property">"extends"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"tslint:latest"</span><span class="token punctuation">,</span> <span class="token string">"tslint-react"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token string-property property">"jsRules"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token string-property property">"rules"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token comment">// use single quotes, but enforce double quotes in JSX</span><br> <span class="token string-property property">"quotemark"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token string">"single"</span><span class="token punctuation">,</span> <span class="token string">"jsx-double"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token comment">// I prefer no semi colons :)</span><br> <span class="token string-property property">"semicolon"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token string">"never"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token comment">// This rule makes each Interface be prefixed with 'I' which I don't like</span><br> <span class="token string-property property">"interface-name"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token string">"never-prefix"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token comment">// This rule enforces objects to always have keys in alphabetical order</span><br> <span class="token string-property property">"object-literal-sort-keys"</span><span class="token operator">:</span> <span class="token boolean">false</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token string-property property">"rulesDirectory"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><br><span class="token punctuation">}</span></code></pre>
<p>I can then run <code>tslint --project tsconfig.json</code> to lint my project.</p>
<h2>Conclusion</h2>
<p>In summary, I've found TypeScript to be a joy to work with so far. I'll definitely be blogging more about the specifics of the language and how I'm using it, but in terms of setting up a build process, configuring all the tools and getting started with types, it's been a real joy. I'd highly recommend giving it a go if you're looking for a bit more structure in your JS applications and want a strong compiler to help you avoid mistakes and spend less time debugging.</p>
<p>If you'd like to browse the code or get started from what I created in this post, I <a href="https://github.com/javascript-playground/react-typescript-jest-demo">pushed an example repo to GitHub</a> that you can use as a starting point. Feel free to raise an issue on that repo if you have any questions about it.</p>
Refactoring React with Tests2017-06-30T00:00:00+00:00http://www.jackfranklin.co.uk/blog/refactoring-react-tests/<p>As you work on a React application it's highly likely that you'll encounter components that have grown over time. They may have started with just one particular use case in mind, but will have been added to since. This can lead to complex <code>render</code> methods and code that's hard to follow.</p>
<p>In this video you'll see how to spot components that need some work doing, how we test these components, and how we use the tests to guide us, splitting one component into two much more straightforward ones.</p>
<p>PS: it's definitely worth making the video fullscreen or viewing <a href="https://youtu.be/VTpMF7vbkFw">on Youtube</a> so you can see things more clearly.</p>
<iframe width="640" height="360" src="https://www.youtube.com/embed/VTpMF7vbkFw" frameborder="0" allowfullscreen=""></iframe>
<br>
<p>If you'd like to play with this code, <a href="https://github.com/javascript-playground/react-refactoring-with-tests">you can find the repository on GitHub</a>, and feel free to raise any questions via GitHub issues on that repository.</p>
Extracting Logic from React Components2017-07-17T00:00:00+00:00http://www.jackfranklin.co.uk/blog/react-extracting-logic/<p>In the <a href="https://javascriptplayground.com/blog/2017/06/refactoring-react-tests/">previous screencast</a> we took a React component that was doing too much and refactored it, splitting it into two components that are easier to maintain, use and test. Although I'd recommend watching that video first, you don't need to have watched it to read this blog post. <a href="https://github.com/javascript-playground/react-refactoring-with-tests">You can find all the code on GitHub</a> if you'd like to run it locally.</p>
<h2>The starting point</h2>
<p>Let's start by looking at the <code>Money</code> component, that takes some value and formats it onto the page:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">Money</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token keyword">static</span> propTypes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">currency</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>string<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br> <span class="token literal-property property">amount</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>number<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">;</span><br><br> <span class="token function">getCurrencyData</span><span class="token punctuation">(</span><span class="token parameter">currency</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span><br> <span class="token constant">GBP</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">base</span><span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token literal-property property">symbol</span><span class="token operator">:</span> <span class="token string">'£'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token constant">USD</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">base</span><span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token literal-property property">symbol</span><span class="token operator">:</span> <span class="token string">'$'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">[</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>currency<span class="token punctuation">]</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">formatAmount</span><span class="token punctuation">(</span><span class="token parameter">amount<span class="token punctuation">,</span> base</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">parseFloat</span><span class="token punctuation">(</span>amount <span class="token operator">/</span> base<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> currency <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getCurrencyData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>currency<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token punctuation">{</span> symbol<span class="token punctuation">,</span> base <span class="token punctuation">}</span> <span class="token operator">=</span> currency<span class="token punctuation">;</span><br> <span class="token keyword">const</span> formatted <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">formatAmount</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>amount<span class="token punctuation">,</span> base<span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>span<span class="token operator">></span><br> <span class="token punctuation">{</span>symbol<span class="token punctuation">}</span><br> <span class="token punctuation">{</span>formatted<span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><br> <span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>span<span class="token operator">></span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>amount<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>There's two parts of functionality here that I would look at extracting into a separate class:</p>
<ul>
<li><code>getCurrencyData</code> fetches information on the given currency that is used for formatting the output. In reality this would be much larger and support more languages; so this is a good candidate to pull into a separate module.</li>
<li><code>formatAmount</code> takes the amount and the base and produces a formatted value. Sure, the logic is straightforward for now, but once we expand our application to support more languages, you can imagine this getting much more complex.</li>
</ul>
<p>The reason that I want to extract these is so I can test them in complete isolation. Right now to test formatting of amounts I have to create and mount a React component, but I should be able to just call that function and check the result.</p>
<h2>Extracting amount formating</h2>
<p>Let's create <code>src/format-currency.js</code> which will house the <code>formatAmount</code> function that is currently in our <code>Money</code> component.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">formatAmount</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">amount<span class="token punctuation">,</span> base</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">parseFloat</span><span class="token punctuation">(</span>amount <span class="token operator">/</span> base<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toFixed</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>I've just lifted the function in its entirety to the new file and added an <code>export</code> to the beginning.</p>
<p>To test this, we can replace the body of <code>Money</code>'s <code>formatAmount</code> so that it just calls the new function from our <code>format-currency.js</code> module:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> formatAmount <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./format-currency'</span><br><br><span class="token keyword">class</span> <span class="token class-name">Money</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token operator">...</span><br> <span class="token function">formatAmount</span><span class="token punctuation">(</span><span class="token parameter">amount<span class="token punctuation">,</span> base</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">formatAmount</span><span class="token punctuation">(</span>amount<span class="token punctuation">,</span> base<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br> <span class="token operator">...</span><br><span class="token punctuation">}</span></code></pre>
<p>Notice that I've still left the <code>formatAmount</code> function defined on <code>Money</code>; when pulling code apart like this you should do it in small steps; doing it like this decreases the chance of inadvertently breaking the code and also makes it easier to retrace your steps if something does go wrong.</p>
<p>Because these components are well tested, I can run <code>yarn test</code> to ensure everything passes, which it does.</p>
<p>Next up, I'll remove the <code>formatAmount</code> function from <code>Money</code> and update the <code>render</code> function to call our external function directly:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// inside Money component</span><br><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> currency <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getCurrencyData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>currency<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token punctuation">{</span> symbol<span class="token punctuation">,</span> base <span class="token punctuation">}</span> <span class="token operator">=</span> currency<br> <span class="token comment">// this used to say this.formatAmount</span><br> <span class="token keyword">const</span> formatted <span class="token operator">=</span> <span class="token function">formatAmount</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>amount<span class="token punctuation">,</span> base<span class="token punctuation">)</span><br><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>span<span class="token operator">></span><span class="token punctuation">{</span>symbol<span class="token punctuation">}</span><span class="token punctuation">{</span>formatted<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>span<span class="token operator">></span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>amount<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Once again, <code>yarn test</code> confirms that we are good. Now all our original tests are passing, we can add some new tests to test `formatAmount in isolation. It's important to always do it this way round - get all your existing tests green before adding new ones.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> formatAmount <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./format-currency'</span><span class="token punctuation">;</span><br><br><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'it formats the amount to 2 dp'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">expect</span><span class="token punctuation">(</span><span class="token function">formatAmount</span><span class="token punctuation">(</span><span class="token number">2000</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">'20.00'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'respects the base'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">expect</span><span class="token punctuation">(</span><span class="token function">formatAmount</span><span class="token punctuation">(</span><span class="token number">2000</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">'200.00'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><br><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'it deals with decimal places correctly'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">expect</span><span class="token punctuation">(</span><span class="token function">formatAmount</span><span class="token punctuation">(</span><span class="token number">2050</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">'20.50'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>We now have thorough tests for formatting amounts that are not attached to our React component at all. Sure, the <code>formatAmount</code> function is very straightforward for now, but as it grows we can now test it very easily without any need to fire up a React component to do so.</p>
<h2>Extracting the currency data</h2>
<p>One down, one to go! Let's now pull out <code>getCurrencyData</code> using a very similar method to above. First, I'll create <code>currency-data.js</code> and pull our function over:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">getCurrencyData</span> <span class="token operator">=</span> <span class="token parameter">currency</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span><br> <span class="token constant">GBP</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">base</span><span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token literal-property property">symbol</span><span class="token operator">:</span> <span class="token string">'£'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token constant">USD</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">base</span><span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token literal-property property">symbol</span><span class="token operator">:</span> <span class="token string">'$'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">[</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>currency<span class="token punctuation">]</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>But wait! There's a bug - the function takes in a <code>currency</code> argument but actually completely ignores it in favour of <code>this.props.currency</code>. This is entirely accidental but shows the value of separating business logic from component UI logic. In a React component it's too easy to refer to <code>this.props</code> or <code>this.state</code> and it becomes hard to track which functions use which values. Pulling them out into their own modules forces you to pass arguments through, which in turn helps clarify the API and help you think about what data the function really needs.</p>
<p>Once I fix up that bug by making sure we call <code>getCurrencyData</code> with the right value, and update the function to refer to the <code>currency</code> argument, not <code>this.props.currency</code>, we can make <code>Money</code>'s <code>getCurrencyData</code> delegate to the new function:</p>
<pre class="language-js"><code class="language-js"><span class="token operator">...</span><br><span class="token keyword">import</span> <span class="token punctuation">{</span> getCurrencyData <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./currency-data'</span><br><br><span class="token keyword">class</span> <span class="token class-name">Money</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token operator">...</span><br> <span class="token function">getCurrencyData</span><span class="token punctuation">(</span><span class="token parameter">currency</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">getCurrencyData</span><span class="token punctuation">(</span>currency<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> currency <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getCurrencyData</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>currency<span class="token punctuation">)</span><br> <span class="token operator">...</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>And once again <code>yarn test</code> confirms that nothing has broken. Now we can make the next step of entirely deleting <code>getCurrencyData</code> in <code>Money</code> and just call the external function from <code>render</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> currency <span class="token operator">=</span> <span class="token function">getCurrencyData</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>currency<span class="token punctuation">)</span><br> <span class="token operator">...</span><br><span class="token punctuation">}</span></code></pre>
<p>Now let's write somet tests for <code>getCurrencyData</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> getCurrencyData <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./currency-data'</span><span class="token punctuation">;</span><br><br><span class="token function">test</span><span class="token punctuation">(</span><span class="token string">'for GBP it returns the right data'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">expect</span><span class="token punctuation">(</span><span class="token function">getCurrencyData</span><span class="token punctuation">(</span><span class="token string">'GBP'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">base</span><span class="token operator">:</span> <span class="token number">100</span><span class="token punctuation">,</span><br> <span class="token literal-property property">symbol</span><span class="token operator">:</span> <span class="token string">'£'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>For the sake of this tutorial - and also due to the data being simplified - I'll leave it there for tests for this function, but in a more complex situation we would write a full suite of tests as required.</p>
<h2>Slimming down the money component</h2>
<p>Now, with everything passing, take a look at the <code>Money</code> implementation:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> PropTypes <span class="token keyword">from</span> <span class="token string">'prop-types'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> <span class="token punctuation">{</span> formatAmount <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./format-currency'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> <span class="token punctuation">{</span> getCurrencyData <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./currency-data'</span><span class="token punctuation">;</span><br><br><span class="token keyword">class</span> <span class="token class-name">Money</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token keyword">static</span> propTypes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">currency</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>string<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br> <span class="token literal-property property">amount</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>number<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">;</span><br><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> currency <span class="token operator">=</span> <span class="token function">getCurrencyData</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>currency<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>currency<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token punctuation">{</span> symbol<span class="token punctuation">,</span> base <span class="token punctuation">}</span> <span class="token operator">=</span> currency<span class="token punctuation">;</span><br> <span class="token keyword">const</span> formatted <span class="token operator">=</span> <span class="token function">formatAmount</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>amount<span class="token punctuation">,</span> base<span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>span<span class="token operator">></span><br> <span class="token punctuation">{</span>symbol<span class="token punctuation">}</span><br> <span class="token punctuation">{</span>formatted<span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><br> <span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>span<span class="token operator">></span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>amount<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br><span class="token keyword">export</span> <span class="token keyword">default</span> Money<span class="token punctuation">;</span></code></pre>
<p><code>Money</code> has now just a single method, <code>render</code>, implemented. This is a great chance to move <code>Money</code> to a functional, stateless component (FSC). If you are not familiar with the how, whats and whys of FSCs, you can <a href="https://javascriptplayground.com/blog/2017/03/functional-stateless-components-react/">read a previous blog post on the subject</a>. I can now rewrite <code>Money</code> in this way:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> PropTypes <span class="token keyword">from</span> <span class="token string">'prop-types'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> <span class="token punctuation">{</span> formatAmount <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./format-currency'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> <span class="token punctuation">{</span> getCurrencyData <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./currency-data'</span><span class="token punctuation">;</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">Money</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> currency<span class="token punctuation">,</span> amount <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> currencyData <span class="token operator">=</span> <span class="token function">getCurrencyData</span><span class="token punctuation">(</span>currency<span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>currencyData<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token punctuation">{</span> symbol<span class="token punctuation">,</span> base <span class="token punctuation">}</span> <span class="token operator">=</span> currencyData<span class="token punctuation">;</span><br> <span class="token keyword">const</span> formatted <span class="token operator">=</span> <span class="token function">formatAmount</span><span class="token punctuation">(</span>amount<span class="token punctuation">,</span> base<span class="token punctuation">)</span><span class="token punctuation">;</span><br><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>span<span class="token operator">></span><br> <span class="token punctuation">{</span>symbol<span class="token punctuation">}</span><br> <span class="token punctuation">{</span>formatted<span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><br> <span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>span<span class="token operator">></span><span class="token punctuation">{</span>amount<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><span class="token punctuation">;</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br>Money<span class="token punctuation">.</span>propTypes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">currency</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>string<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br> <span class="token literal-property property">amount</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>number<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">export</span> <span class="token keyword">default</span> Money<span class="token punctuation">;</span></code></pre>
<p>I am a huge fan of FSCs; they encourage simple components and the separation of logic from UI, and it's no coincidence that by doing this refactoring today we've come to realise that our <code>Money</code> component can be written in this way.</p>
<h2>Conclusion</h2>
<p>By looking through our components and finding standalone functions that we can pull out, we've greatly simplified our component whilst increasing our test coverage and clarity of our application greatly. I highly encourage you to think twice about adding arbitrary methods onto React components; it's too easy to refer to <code>this.props.X</code>.</p>
<p>By pulling the functions into their own modules you are forced to consider which props are needed and how your function will work. It makes code clearer, it's easier to see which props are used where and it means as your business logic gets more complex you can test it without having to get your UI components involved.</p>
<p>If you'd like to play with the code yourself, <a href="https://github.com/javascript-playground/react-refactoring-with-tests">it's all on GitHub</a>. Feel free to raise an issue if you have any questions.</p>
Migrating complex JavaScript applications2017-08-08T00:00:00+00:00http://www.jackfranklin.co.uk/blog/migrating-complex-javascript-angular-react/<p>This blog post is a write up of a talk I've gave at Front Trends in Poland, May 2017. You can find the slides and video below, along with a full write up of the talk, if you'd rather read than watch.</p>
<iframe width="640" height="360" src="https://www.youtube.com/embed/QVna1-9yMuA" frameborder="0" allowfullscreen=""></iframe>
<p>You can also <a href="https://speakerdeck.com/jackfranklin/front-trends-migrating-complex-software">find the slides on SpeakerDeck</a>,</p>
<h2>Background</h2>
<p>The application I worked on was a business critical ticketing platform that sold tickets to music gigs. You don't need to know any more about it to enjoy this blog post; the most important thing to note is that we had to be in a position to deal with sudden bug reports and new features that might be needed. This immediately ruled out any big bang rewrite, and instead we decided to build new components in React, and migrate existing Angular ones to React one by one. Since starting this project a year ago, I've learned a lot across a lot of different areas and that's what the talk and this blog post are about.</p>
<p>It's split up into the four t's: Tech, Tests, Team and Talking.</p>
<h2>Tech</h2>
<p>The first decision we made was the one to move away from the existing Angular 1 codebase in the first place. We did not do this because we actively disliked Angular; I've worked with it before and very much enjoyed it, and Angular 2+ has made a lot of improvements. Our reasons for considering the migration were:</p>
<ul>
<li>Lack of expertise; both developers who had built the Angular app had moved on from the company.</li>
<li>Lack of confidence; because we hadn't built the app, it was hard to have confidence that when we changed code we weren't introducing new bugs or breaking other features.</li>
<li>Angular 1 is not the latest version of Angular and although it is going to be maintained by the Angular team for a while yet, it does not have the longevity we were looking for.</li>
</ul>
<p>We picked React primarily because we all knew it well, but also because it fits the component model that we were betting on; that we could build our app incrementally, starting with very small components and then moving into larger ones as we gained confidence.</p>
<h3>Strangling Angular</h3>
<p>We could either do a big bang rewrite, and start again entirely from scratch in React, or find some way to run Angular and React side by side as we migrated incrementally. As mentioned above, we had to do this because a big rewrite was out of the question.</p>
<p>There's another benefit of incremental migrations: you start to add value immediately. In a big rewrite, you only add value at the end of the migration, when everything is done. If you migrate piece by piece you add value every time you deploy some migrated code. This approach is known as the strangler approach, a term coined by Martin Fowler but one that I became aware of after a talk from <a href="https://www.youtube.com/watch?v=1QPEflWn1WU&list=PLBzScQzZ83I81fnpqX2AkYD5c5cKgrqc2&index=10">Sabrina Leandro at Lead Dev</a>.</p>
<p><img src="http://www.jackfranklin.co.uk/img/posts/migrating/value.png" alt=""></p>
<p>This approach of migrating from the inside out was made possible by <a href="https://github.com/ngReact/ngReact">ngReact</a>, an Angular plugin that lets you render React from within Angular applications. Our approach was to start with very small components, and then work our way up the tree of components, replacing each part as we went.</p>
<p><img src="http://www.jackfranklin.co.uk/img/posts/migrating/tree.png" alt=""></p>
<p>By taking this approach, we were able to ship aggressively - the first part of our codebase to be written in React was shipped on day two of the migration.</p>
<h2>Tests</h2>
<p>Throughout the process we needed to ensure that we didn't break the application. It's not possible to deploy migrated code multiple times a week without a suite of tests to confirm that functionality hasn't broken. The existing Angular app had a lot of tests which helped; and we were able to convert tests from Angular to React (written using Jest and Enzyme - <a href="https://www.sitepoint.com/test-react-components-jest/">which you can read more about here</a>). However, when you've migrated tests over, that doesn't confirm that you've not broken anything in the process of migrating. What was really valuable to us was a set of end to end tests, written using <a href="http://www.protractortest.org/#/">Protractor</a>.</p>
<p>We were even able to run these tests in IE11, checking that we were supporting IE correctly and not inadvertently causing cross browser bugs during the migration. The advantage of these tests is that they are entirely decoupled from the code; they care not if the UI they are interacting with is Angular or React based and that's the best thing about them. The downside of these tests is that they are slow - so we stuck to having five tests that covered the core user journey and interactions. It's important to find a balance of test coverage versus test speed.</p>
<h2>Team</h2>
<p>One of the biggest areas of learning for me in this project - and one that I don't tend to blog about much - was the lessons learned about working in a team on one project for such a long period of time. Working for an entire year on the same project was a new experience - normally I work on teams that work on a particular goal for 2-3 weeks and then move onto the next.</p>
<p>One of the most important aspects of this was knowing what to work on. We had a vast codebase to pick from and ultimately everything needed migrating. How should we pick and choose what parts to tackle first? The first step was to vet every single feature and check that it was still something that we needed to support. We found a fair few parts of the codebase that had never been used, or supported features we no longer needed, and this lead to us deleting a lot of code. This took time to go through and decide which features were needed, but that time was very effective compared to the alternative; migrating features that would never be used would have been no good to anyone.</p>
<p>After we'd got rid of all the code we didn't need, we based prioritising components on three factors:</p>
<ul>
<li>the bug rate - a buggier feature got higher priority as we could fix bugs as part of the migration.</li>
<li>the code quality - code that we didn't understand was higher priority; getting rid of code no one understood was a large motivation for the entire migration.</li>
<li>the churn rate - that is, how many times per week that a particular part of the codebase was used. Code that is touched more by more developers is more important to migrate - we want to spend as little time as possible working with or maintaining old Angular code.</li>
</ul>
<p>Given these three factors we could prioritise work:</p>
<p><img src="http://www.jackfranklin.co.uk/img/posts/migrating/churn.png" alt=""></p>
<p>We also made sure to mix up different types of work. Some parts of the migration were more visual based - moving one small Angular component to React - and some were more "under the hood", such as moving the HTTP layer from Angular's <code>$http</code> service to using the <code>fetch</code> API. Others were purely tooling based; we used the migration as a good excuse to bring the tooling up to speed and moved from Browserify to Webpack, and migrated tests from Karma to Jest. We made sure that as a team each developer got as much variety in the work as they could (based on their preferences, too) because otherwise we risked the work becoming very monotonous; there's only so many times you can migrate small components from Angular to React without feeling a bit bored!</p>
<p>One key to keeping the team motivated was to ensure we kept our momentum up at all times. To do this we would aggressively ship new React code on an almost daily basis, backed by our test suite to ensure no breakages as we deployed. This enabled us to really feel like we were making progress and even on larger pieces of work we would try to deploy in stages to keep things ticking over. This also reduces the risk significantly - if you're deploying small pieces one at a time and something breaks, you know exactly which deploy (and therefore which code change) caused it.</p>
<p>To help us visualise the change we had a variety of scripts that would give us very rough metrics on the codebase. One would grep the codebase for files that imported React, and another did the same for Angular. This gave us an (incredibly rough) overview of our progress, and whilst not scientific, it was great as a team to see the numbers change as we worked.</p>
<h2>Talking</h2>
<p>When we first started considering a large software migration we communicated throughout the tech team as to the reasons why and how long it would take. When communicating amongst the tech team, it's natural to use specific terminology and discuss to a fairly in-depth technical level. Where we made a mistake initially was not communicating clearly with the teams outside of engineering. These teams are arguably more important to get onside; they are the ones who deal with angry customers who couldn't buy tickets, or deal with management teams who want to use our product. They are the ones who get regular feedback on the negative aspects to our product, and they are the ones who get angry phone calls if a certain feature doesn't work right. Early on we didn't communicate our motivations for the migration in a clear manner, and as such didn't get much support outside of engineering. Most people were (understandably) frustrated when they were told that for a year we would primarily be keeping our product the same and just changing the underlying code.</p>
<p>To fix this it's important to switch your communication to be from their team's point of view; rather than discussing the pros of React versus the cons of Angular, it's important to explain the impact doing this migration will have on them. To do this we explained how bugs that are harder to fix now would be made easier when we moved to a framework and codebase we understood more; we explained how we could lose some of the bulky code that led to the product loading slowly on mobile devices, and we explained how we'll have greater confidence in the system and be able to react much more quickly to urgent requests, bug fixes and features. This really helped people outside of tech understand what we were doing and why we were doing it.</p>
<p>Our method for prioritising migrations based on bugs also paid off here - we were able to take long-standing bugs that had caused customer support (and our customers) pain, and fix them whilst migrating from Angular to React. One such bug that caused us issues constantly had existed for nearly a year, unable to be hunted down, and was eradicated when we migrated the relevant components over to React. This made us happy and made customer support even happier! Fixing bugs that caused other teams pain clearly presented to them the benefits of doing this work, and why the downside of not building as many new features was worth it in the long run.</p>
<p>Another area of communication that we put a lot of time and effort into was communicating when things went wrong. Ultimately on a complex project over a relatively long time period there would be bugs caused by the migration.</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">There are two types of ops people: those who have fucked up production, and those who are about to. <a href="https://twitter.com/petecheslock">@petecheslock</a> <a href="https://twitter.com/hashtag/monitorama?src=hash">#monitorama</a> <a href="https://t.co/TMpdvW1Wqs">pic.twitter.com/TMpdvW1Wqs</a></p>— (╯°□°)╯︵ ┻━┻ sdoɹǝǝq (@beerops) <a href="https://twitter.com/beerops/status/866808660030345218">May 23, 2017</a></blockquote>
<script async="" src="http://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>This is frustrating to everyone but the artist services team who get phone calls from angry clients about the site being down really get it more than anyone else, so would understandably be very upset when this happened. Every time we caused an issue we did a full internal retrospective and discussed how it happened. We asked:</p>
<ul>
<li><strong>What</strong> went wrong?</li>
<li><strong>Why</strong> did we not catch it before deployment?</li>
<li><strong>How</strong> did we fix it?</li>
<li><strong>How</strong> will we prevent this happening again?</li>
</ul>
<p>Importantly this was entirely blameless - if a bug made it out to production it wasn't the responsibility of the person who wrote the code, but the entire team. Often we'd find that bugs highlighted a gap in our testing, or some manual testing that needed to be done before certain deploys (one particular date bug only showed itself on the New York time zone, so tracking that down in London was hard!).</p>
<p>The lessons learned would then be communicated to the rest of the business, to show them that not only did we take issues on the platform very seriously, but we spent a lot of time and effort making sure the same bug never happened again.</p>
<h2>Conclusions</h2>
<p>In summary, there are 7 key lessons learned that you should have in mind if you're ever thinking of migrating a project:</p>
<ol>
<li>Never migrate just for the sake of it - if our only motivation had been because the product was on Angular 1, we wouldn't have done it. There were multiple factors that lead to us migrating. Don't take this decision lightly!</li>
<li>Plan, plan and plan again. We spent many hours in front of a whiteboard breaking the product down and prioritising features. Have the prioritised work visible to the team (we used Trello), so you don't ever lose focus, which is easily done on such a complex, long running project.</li>
<li>Cross business communication is vital.</li>
<li>Prioritise based on current pain points in your application, which helps with motivation and keeping the rest of the company onside.</li>
<li>Mix up different types of work to keep the work interesting for all team members.</li>
<li>Have some metrics, however rough, for the migration, so you can easily get a sense of where you are and your progress.</li>
<li>Don't expect to migrate perfectly the first time - you can refactor after migrating.</li>
</ol>
<p>If you have any questions, I'd love to answer them! Feel free to <a href="http://twitter.com/Jack_Franklin">grab me on Twitter</a> or <a href="https://github.com/jackfranklin/angular-react-talk">open an issue on GitHub</a>.</p>
An introduction to styled-components with Glen Maddern2017-08-29T00:00:00+00:00http://www.jackfranklin.co.uk/blog/introduction-to-styled-components-react/<p>CSS in JavaScript has been something I've been meaning to explore for a while now; it's also one the questions I get asked most when I talk about my experience with React.</p>
<p><a href="https://github.com/styled-components/styled-components">styled-components</a> by <a href="https://twitter.com/glenmaddern">Glen Maddern</a> and <a href="https://twitter.com/mxstbr">Max Stoiber</a> is a library aimed at making it really easy to use CSS in React components (and also supports Preact out of the box). Rather than tackle this post alone, I invited Glen to join me to record an introduction to using styled-components.</p>
<iframe width="640" height="360" src="https://www.youtube.com/embed/fmotV1PQac8?rel=0" frameborder="0" allowfullscreen=""></iframe>
<p>You can also <a href="https://www.youtube.com/watch?v=fmotV1PQac8">watch the video directly on YouTube</a> if you prefer.</p>
<p>A huge thanks to Glen for taking the time to talk to me. His videos on <a href="https://frontend.center/">Frontend Center</a> are absolutely excellent and I highly recommend subscribing.</p>
<p>You can find all the code from this video on <a href="https://github.com/javascript-playground/styled-components-screencast">the GitHub repository</a>; if you have any questions feel free to raise an issue there. If you have any thoughts on other videos you'd like to see, please let me know.</p>
Moving away from Vim for front-end development2017-09-10T00:00:00+00:00http://www.jackfranklin.co.uk/blog/editors-for-front-end-development/<p>I've been a Vim user now consistently for about 6 years. My extensive <a href="https://github.com/jackfranklin/dotfiles">dotfiles</a> repository and (now badly outdated) blog on <a href="http://tilvim.com/">TIL Vim</a> demonstrate pretty well that I've spent a lot of time using, learning and tweaking my Vim set up to be exactly how I'd like.</p>
<p>However, as I've moved more and more into almost exclusively front-end development I've been starting to be tempted by other developers. The simple reason why is that the front-end community isn't as active on Vim as it is on other editors such as VS Code and Atom. There are fewer developers in front-end using Vim, and therefore sometimes the plugins and eco-system around it aren't quite as plentiful as other editors. To that end, I've decided to spend some time trying out other editors to see how I get on.</p>
<p>I tried VSCode a couple of months ago and didn't find it quite how I wanted - although I'm willing to give it another go - so for now I've picked <a href="https://atom.io/">Atom</a> to trial for a few weeks. If you're an Atom user, I'd love to hear from you with any recommended settings, plugins and so on. Here's the ones I've picked up so far:</p>
<ul>
<li>
<p>I will never not edit text without Vim keybindings, so <a href="https://github.com/t9md/atom-vim-mode-plus">vim-mode-plus</a> was the first plugin I installed. So far it seems very solid - I haven't found anything I can't do yet.</p>
</li>
<li>
<p>I've also set up <a href="https://atom.io/packages/sync-settings">sync-settings</a> so I can keep everything synced across my work and personal computer. I wish I could do this directly via my dotfiles repo (I may well be able to) but for now this is a low friction way to get it set up.</p>
</li>
<li>
<p><a href="https://atom.io/packages/language-babel">language-babel</a> seems like a no brainer - it improves and adds syntax highlighting for a bunch of languages, including Flow and a bunch of JSX features.</p>
</li>
<li>
<p><a href="https://atom.io/packages/git-plus">git plus</a> looks like it will make it much easier to do all my <code>git</code>ing from within Atom - complemented by <a href="https://atom.io/packages/split-diff">split-diff</a> to easily see file changes.</p>
</li>
</ul>
<p>There's many more that I've installed, including the obvious ones like plugins for linting code with Prettier, Flow and ESLint.</p>
<p>I've also managed to completely hide scrollbars from this <a href="https://coderwall.com/p/h_zpfa/hide-scrollbars-in-atom">handy tip on Coderwall</a>, and have applied this CSS to remove all the linting output from the gutters (I prefer a more narrow gutter and the linting tools also mostly underline the suspect code anyway):</p>
<pre class="language-css"><code class="language-css"><span class="token selector">.gutter[gutter-name='linter-ui-default']</span> <span class="token punctuation">{</span><br> <span class="token property">display</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span><br><span class="token punctuation">}</span></code></pre>
<p>The main challenge for me is getting used to not having the terminal so accessible to me - normally I run Vim within a terminal so I can easily run commands in the background. However, most of the time I just run <code>yarn run dev</code> and leave it, so I think I just need to adjust to this over time.</p>
<p>I'll try to blog again in a few weeks once I've had more time to explore Atom and learn its quirks, but in the mean time if you have any recommendations please do let me know!</p>
Adding URL support to an Elm app with elm-lang/navigation2017-10-03T00:00:00+00:00http://www.jackfranklin.co.uk/blog/navigation-routing-in-elm/<p>In today's video I took an existing Elm application and add first class URL support via <a href="https://github.com/elm-lang/navigation">Elm's Navigation package</a>.</p>
<iframe width="640" height="360" src="https://www.youtube.com/embed/ZgAwrJ3EdT4?rel=0" frameborder="0" allowfullscreen=""></iframe>
<p>You can find all the source code <a href="https://github.com/jackfranklin/do-you-even-elm">on the GitHub repo</a>, and <a href="https://github.com/jackfranklin/do-you-even-elm/pull/5">the pull request I made after this video</a> is also available.</p>
<p>If you have any questions feel free to raise them on that GitHub PR and I'll get back to you.</p>
An introduction to testing React components with Enzyme 32017-12-12T00:00:00+00:00http://www.jackfranklin.co.uk/blog/introduction-to-react-tests-enzyme/<p>In today's post we'll introduce the AirBnB library Enzyme for testing React
applications. We'll do this using a test driven development (TDD) approach. That
is, we'll write the tests first, watch them fail, and then build the React
component out to fix the tests, before then writing more. We'll then consider
how we can refactor code whilst running the tests to confirm we haven't made any
errors.</p>
<blockquote>
<p>In reality, I don't often write components from scratch in a TDD way, however
I will often use TDD to replicate an existing bug in a component to first see
the bug in action, and then fixing it. Feedback via test results on the
command line is often much quicker than browser refreshes and manual
interactions, so writing tests can be a very productive way to improve or fix
a component's behaviour.</p>
</blockquote>
<h2>Set up</h2>
<p>I'll be using a brand new React app for this tutorial, which I've created with
<a href="https://github.com/facebookincubator/create-react-app">create-react-app</a>. This
comes complete with <a href="https://facebook.github.io/jest/">Jest</a>, a test runner
built and maintained by Facebook.</p>
<p>There's one more dependency we'll need for now -
<a href="https://github.com/airbnb/enzyme">Enzyme</a>. Enzyme is a suite of test utilities
for testing React that makes it incredibly easy to render, search and make
assertions on your components, and we'll use it extensively today. Enzyme also
needs <code>react-test-renderer</code> to be installed (it doesn't have it as an explicit
dependency because it only needs it for apps using React 15.5 or above, which we
are). In addition, the newest version of Enzyme uses an adapter based system
where we have to install the adapter for our version of React. We're rocking
React 16 so I'll install the adapter too:</p>
<pre><code>yarn add -D enzyme react-test-renderer enzyme-adapter-react-16
</code></pre>
<blockquote>
<p>The <code>-D</code> argument tells Yarn to save these dependencies as developer
dependencies.</p>
</blockquote>
<p>You can read more about
<a href="http://airbnb.io/enzyme/docs/installation/index.html">installing Enzyme in the docs</a>.</p>
<h2>Enzyme setup</h2>
<p>You also need to perform a small amount of setup for Enzyme to configure it to
use the right adapter. This is all documented in the link above; but when we're
working with an application created by create-react-app, all we have to do is
create the file <code>src/setupTests.js</code>. create-react-app is automatically
configured to run this file before any of our tests.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> configure <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'enzyme'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> Adapter <span class="token keyword">from</span> <span class="token string">'enzyme-adapter-react-16'</span><span class="token punctuation">;</span><br><br><span class="token function">configure</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">adapter</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Adapter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<blockquote>
<p>If you're using an older version of React in your projects but still want to
use Enzyme, make sure you use the right Enzyme adapter for the version of
React you're using. You can find more on the
<a href="https://github.com/airbnb/enzyme#installation">Enzyme installation docs</a>.</p>
</blockquote>
<p>create-react-app is configured to run this file for us automatically when we run
<code>yarn test</code>, so before our tests are run it will be executed and set up Enzyme
correctly.</p>
<blockquote>
<p>If you're not using create-react-app, you can configure Jest yourself to run
this file using the
<a href="https://facebook.github.io/jest/docs/en/configuration.html#setuptestframeworkscriptfile-string"><code>setupTestFrameworkScriptFile</code></a>
configuration option.</p>
</blockquote>
<h2>The <code>Hello</code> component</h2>
<p>Let's build a component that takes a <code>name</code> prop and renders <code><p>Hello, name!</p></code> onto the screen. As we're writing tests first, I'll create
<code>src/Hello.test.js</code>, following the convention for test files that
<code>create-react-app</code> uses (in your own apps you can use whichever convention you
prefer). Here's our first test:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> Hello <span class="token keyword">from</span> <span class="token string">'./Hello'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> <span class="token punctuation">{</span> shallow <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'enzyme'</span><span class="token punctuation">;</span><br><br><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'renders'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> wrapper <span class="token operator">=</span> <span class="token function">shallow</span><span class="token punctuation">(</span><span class="token operator"><</span>Hello name<span class="token operator">=</span><span class="token string">"Jack"</span> <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>wrapper<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">'Hello, Jack!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>We use Enzyme's
<a href="https://github.com/airbnb/enzyme/blob/master/docs/api/shallow.md">shallow rendering API</a>.
Shallow rendering will only render one level of components deep (that is, if our
<code>Hello</code> component rendered the <code>Foo</code> component, it would not be rendered). This
helps you test in isolation and should be your first point of call for testing
React components.</p>
<p>You can run <code>yarn test</code> in a React app to run it and have it rerun on changes.
If you do that now, you'll see our first error:</p>
<pre><code>Cannot find module './Hello' from 'Hello.test.js'
</code></pre>
<p>So let's at least define the component and give it a shell that renders nothing:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">Hello</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">export</span> <span class="token keyword">default</span> Hello<span class="token punctuation">;</span></code></pre>
<p>Now we get a slightly cryptic error:</p>
<pre class="language-js"><code class="language-js">Method “text” is only meant to be run on a single node<span class="token punctuation">.</span> <span class="token number">0</span> found instead<span class="token punctuation">.</span></code></pre>
<p>Once you've used Enzyme a couple of times this becomes much clearer; this is
happening because we're calling <code>wrapper.find('p')</code> and then calling <code>text()</code> on
that to get the text, but the component is not rendering a paragraph. Let's fix
that:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">Hello</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>Hello World<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Now we're much closer!</p>
<pre><code>expect(received).toEqual(expected)
Expected value to equal:
"Hello, Jack!"
Received:
"Hello World"
</code></pre>
<p>And we can make the final leap to a green test:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">Hello</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>Hello<span class="token punctuation">,</span> <span class="token punctuation">{</span>props<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>Next up, let's write a test to ensure that if we don't pass in a name, it
defaults to "Unknown". At this point I'll also update our first test, because
<code>it('renders', ...)</code> is not very descriptive. It's good to not care too much
about the name of the first test you write, and focus on the implementation, but
once you're more comfortable with what you're testing and beginning to expand
your test suite, you should make sure you keep things organised.</p>
<p>With our second test, we're failing again:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'renders the name given'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span><span class="token punctuation">)</span><br><br><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'uses "Unknown" if no name is passed in'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> wrapper <span class="token operator">=</span> <span class="token function">shallow</span><span class="token punctuation">(</span><span class="token operator"><</span>Hello <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>wrapper<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">'Hello, Unknown!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<pre><code>expect(received).toEqual(expected)
Expected value to equal:
"Hello, Unknown!"
Received:
"Hello, !"
</code></pre>
<p>But we can now write our first pass at the implementation to fix it:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">Hello</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>Hello<span class="token punctuation">,</span> <span class="token punctuation">{</span>props<span class="token punctuation">.</span>name <span class="token operator">||</span> <span class="token string">'Unknown'</span><span class="token punctuation">}</span><span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>And now the test is green we're free to refactor. The above is perfectly fine
but not the way it's usually done in React. Some might choose to destructure the
<code>props</code> argument and give <code>name</code> a default value:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> Hello <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> name <span class="token operator">=</span> <span class="token string">'Unknown'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>Hello<span class="token punctuation">,</span> <span class="token punctuation">{</span>name<span class="token punctuation">}</span><span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>But most of the time when working with React components I'll use the
<code>defaultProps</code> object to define the defaults. I'll also set the component's
<code>propTypes</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span><span class="token punctuation">;</span><br><span class="token keyword">import</span> PropTypes <span class="token keyword">from</span> <span class="token string">'prop-types'</span><span class="token punctuation">;</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">Hello</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>Hello<span class="token punctuation">,</span> <span class="token punctuation">{</span>props<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token operator">!</span><span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br>Hello<span class="token punctuation">.</span>propTypes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">name</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>string<span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br>Hello<span class="token punctuation">.</span>defaultProps <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Unknown'</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">export</span> <span class="token keyword">default</span> Hello<span class="token punctuation">;</span></code></pre>
<p>And all our tests are still passing.</p>
<h2>Conclusion</h2>
<p>That brings our first look at testing React with Enzyme 3 to an end. In future
tutorials we'll dive further into what Enzyme has to offer and see how we can
test components of increasing complexity.</p>
Using React Fragments for the first time2017-12-18T00:00:00+00:00http://www.jackfranklin.co.uk/blog/react-fragments/<p>React v16 was a very exciting release for React, and included many new features. In the recent <a href="https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html">React 16.2 release</a>, improved support for Fragments was announced, and it's this feature that I want to talk about today.</p>
<h2>The problem that fragments solve</h2>
<p>Up until React 16 each component had to return a single element:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// will error</span><br><span class="token keyword">class</span> <span class="token class-name">Demo</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token operator"><</span>p<span class="token operator">></span>foo<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token operator"><</span>p<span class="token operator">></span>bar<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<pre class="language-js"><code class="language-js"><span class="token comment">// OK!</span><br><span class="token keyword">class</span> <span class="token class-name">Demo</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>p<span class="token operator">></span>foo<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br> <span class="token operator"><</span>p<span class="token operator">></span>bar<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>With the release of React 16, you were able to return an array of elements that a component would render:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// allowed in React 16</span><br><span class="token comment">// but you'll get a warning about keys</span><br><span class="token keyword">class</span> <span class="token class-name">Demo</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token operator"><</span>p<span class="token operator">></span>foo<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">,</span> <span class="token operator"><</span>p<span class="token operator">></span>bar<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><span class="token punctuation">]</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>This is OK; but it has two problems:</p>
<ol>
<li>It breaks the JSX abstraction; it's odd to now have a component returning an array containing JSX elements. Whenever I do this I always forget the commas after each array item because I'm not used to using them in JSX.</li>
<li>You have to add a <code>key</code> property to each element to avoid React warnings, which can make the <code>render</code> function verbose and less easy to follow.</li>
</ol>
<p>Because returning arrays didn't feel that natural in React 16, it was far more common to eschew them in favour of wrapping elements in one containing element; most normally a <code>div</code> or a <code>span</code>.</p>
<p>On a large application with a suite of components this can very quickly lead to a set of wrapping elements that can produce a big set of HTML soup. Fragments solve this problem.</p>
<h2>Fragments in React 16.2</h2>
<p>React 16.2 introduced the <code>Fragment</code>:</p>
<blockquote>
<p>Fragments look like empty JSX tags. They let you group a list of children without adding extra nodes to the DOM:</p>
</blockquote>
<p>-- <a href="https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html">React 16.2 release</a></p>
<p>The <code>Fragment</code> element is imported from the <code>react</code> module, and can be used just like any other JSX element. The difference is that a <code>Fragment</code> component doesn't end up adding any extra markup into the DOM:</p>
<h2>Using a Fragment</h2>
<p>First, we import <code>Fragment</code> just like we import <code>Component</code> from <code>react</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> Fragment <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span></code></pre>
<p>And then we use it just like any other React component:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>Fragment<span class="token operator">></span><br> <span class="token operator"><</span>p<span class="token operator">></span>foo<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br> <span class="token operator"><</span>p<span class="token operator">></span>bar<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>Fragment<span class="token operator">></span><br><span class="token punctuation">)</span></code></pre>
<p>The key here is that the resulting DOM from the <code>App</code> component will look like so:</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>foo<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>bar<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span></code></pre>
<h2>A special fragment syntax</h2>
<p>React 16.2 also introduced a syntactical sugar for <code>Fragment</code>s. For example, the code below creates the exact same result as the <code>App</code> component above:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br> <span class="token operator"><</span><span class="token operator">></span><br> <span class="token operator"><</span>p<span class="token operator">></span>foo<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br> <span class="token operator"><</span>p<span class="token operator">></span>bar<span class="token operator"><</span><span class="token operator">/</span>p<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span><br><span class="token punctuation">)</span></code></pre>
<p>I'm not sure if I'll use this syntax over the more explicit <code>Fragment</code> syntax; but I think this comes down to personal preference.</p>
<p>It's worth noting that if you need to pass a <code>Fragment</code> any props (most likely a <code>key</code> prop if you're iterating over a list), you can't use this special syntax; if you have to pass props you need to use <code>Fragment</code>.</p>
<h2>A use case for fragments</h2>
<p>At <a href="https://thread.com/">Thread</a> we're building a site for finding and buying clothing and I was working on a component that allows users to select their size from a dropdown. If the item is out of stock or low on stock, we wanted to show that along side their size. So a dropdown might look like so:</p>
<pre><code>- S
- M - Low stock
- L - Out of stock
</code></pre>
<p>So we're looping over an array of data to generate the <code>option</code>s for the <code>select</code> dropdown. The data looks like so:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> sizes <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'S'</span><span class="token punctuation">,</span> <span class="token literal-property property">stockDisplay</span><span class="token operator">:</span> <span class="token string">'In stock'</span><span class="token punctuation">,</span> <span class="token literal-property property">stockLevel</span><span class="token operator">:</span> <span class="token string">'IN_STOCK'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span><span class="token punctuation">,</span> <span class="token literal-property property">stockDisplay</span><span class="token operator">:</span> <span class="token string">'Low stock'</span><span class="token punctuation">,</span> <span class="token literal-property property">stockLevel</span><span class="token operator">:</span> <span class="token string">'LOW_STOCK'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">3</span><span class="token punctuation">,</span><br> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'L'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">stockDisplay</span><span class="token operator">:</span> <span class="token string">'Out of stock'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">stockLevel</span><span class="token operator">:</span> <span class="token string">'OUT_OF_STOCK'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">]</span></code></pre>
<p>Initially the code for this looked like so:</p>
<pre class="language-js"><code class="language-js"><span class="token function-variable function">generateOptionForSize</span> <span class="token operator">=</span> <span class="token parameter">size</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>option<br> key<span class="token operator">=</span><span class="token punctuation">{</span>size<span class="token punctuation">.</span>id<span class="token punctuation">}</span><br> value<span class="token operator">=</span><span class="token punctuation">{</span>size<span class="token punctuation">.</span>size<span class="token punctuation">}</span><br> disabled<span class="token operator">=</span><span class="token punctuation">{</span>size<span class="token punctuation">.</span>stockLevel <span class="token operator">===</span> <span class="token string">'OUT_OF_STOCK'</span><span class="token punctuation">}</span><br> <span class="token operator">></span><br> <span class="token punctuation">{</span>size<span class="token punctuation">.</span>stockLevel <span class="token operator">===</span> <span class="token string">'IN_STOCK'</span><br> <span class="token operator">?</span> size<span class="token punctuation">.</span>size<br> <span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>size<span class="token punctuation">.</span>size<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> - </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>size<span class="token punctuation">.</span>stockDisplay<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span><br><span class="token punctuation">)</span></code></pre>
<p>This worked fine but I felt like it could be a little cleaner, particularly the conditional for deciding if to show the extra information or not. In addition, I wanted to replace the hyphen with an <a href="http://www.html.am/html-codes/character-codes/html-em-dash-code.cfm"><code>mdash</code></a>, and because I was returning the contents of the <code>option</code> as a string, that was hard to do. If I did:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br> size<span class="token punctuation">.</span>stockLevel <span class="token operator">===</span> <span class="token string">'IN_STOCK'</span><br> <span class="token operator">?</span> size<span class="token punctuation">.</span>size<br> <span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>size<span class="token punctuation">.</span>size<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> &mdash; </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>size<span class="token punctuation">.</span>stockDisplay<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br><span class="token punctuation">}</span></code></pre>
<p>React would sanitise the string and output the literal <code>&mdash;</code> text into the page.</p>
<p>However, swapping out the string interpolation using ES2015 template strings for a React <code>Fragment</code> suddenly made the entire code easier to follow, and allowed me to use an HTML entity:</p>
<pre class="language-js"><code class="language-js"><span class="token function-variable function">generateOptionForSize</span> <span class="token operator">=</span> <span class="token parameter">size</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>option<br> key<span class="token operator">=</span><span class="token punctuation">{</span>size<span class="token punctuation">.</span>id<span class="token punctuation">}</span><br> value<span class="token operator">=</span><span class="token punctuation">{</span>size<span class="token punctuation">.</span>size<span class="token punctuation">}</span><br> disabled<span class="token operator">=</span><span class="token punctuation">{</span>size<span class="token punctuation">.</span>stockLevel <span class="token operator">===</span> <span class="token string">'OUT_OF_STOCK'</span><span class="token punctuation">}</span><br> <span class="token operator">></span><br> <span class="token punctuation">{</span>size<span class="token punctuation">.</span>stockLevel <span class="token operator">===</span> <span class="token string">'IN_STOCK'</span> <span class="token operator">?</span> <span class="token punctuation">(</span><br> size<span class="token punctuation">.</span>size<br> <span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>Fragment<span class="token operator">></span><br> <span class="token punctuation">{</span>size<span class="token punctuation">.</span>size<span class="token punctuation">}</span> <span class="token operator">&</span>mdash<span class="token punctuation">;</span> <span class="token punctuation">{</span>size<span class="token punctuation">.</span>stockDisplay<span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>Fragment<span class="token operator">></span><br> <span class="token punctuation">)</span><span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>option<span class="token operator">></span><br><span class="token punctuation">)</span></code></pre>
<p>This is now easier to follow and allows me to use HTML entities and have them work as expected.</p>
<blockquote>
<p>You could have used a literal mdash here but we prefer to use the <code>&mdash;</code> version and hence Fragments provided a nice solution for us.</p>
</blockquote>
<h2>Conclusion</h2>
<p>I can already see many more places through our app which could be made more straightforward and easier to work with as a result of <code>Fragment</code>s and I'm excited to continue using them. Not only do they clear up a lot of component code, but the fact that they have no output into the DOM should lead to fewer superfluous <code>div</code> and <code>span</code> elements that a lot of React applications are littered with.</p>
Moving the JS Playground from GitHub Pages to Netlify2018-01-08T00:00:00+00:00http://www.jackfranklin.co.uk/blog/moving-to-netlify/<p>Over the weekend I moved this blog from GitHub Pages to Netlify and in this blog
post I want to talk about why.</p>
<h2>Github Pages and the JavaScript Playground</h2>
<p>Ever since the first blog post on this site in April 2012 I've used GitHub Pages
to host the site and it's served me well. The site is a pretty standard
<a href="https://jekyllrb.com/">Jekyll website</a> and as such I've never needed more power
than GitHub provided.</p>
<p>In the future that may not be the case. I have some big plans for this blog this
year (firstly a video series on testing React) and I was beginning to feel that
GitHub Pages was limiting me; you are able to depend on a small subset of Jekyll
plugins and that you couldn't configure redirects, extra headers or any of your
server's behaviour.</p>
<p>Couple the above frustrations with the fact that
<a href="https://twitter.com/philhawksworth">Phil Hawksworth</a>, who I've been lucky
enough to share a stage with at a conference, joined
<a href="https://www.netlify.com/">Netlify</a>, and I felt that the time was right to try
something different.</p>
<p>Netlify takes the idea of publishing static code but wraps it in a powerful
application that supports continuous deployment, redirect, headers control, and
much more out of the box. Even better, you pay for more features, rather than
per users on your site, and so the free plan is more than enough for this site.</p>
<p><em>(There is a soft limit of 100GB per month on the free accounts; but as this is
a text based blog, that's not going to be an issue.)</em></p>
<h2>Moving to Netlify</h2>
<p>If you want to follow along fully, you can see the
<a href="https://github.com/jackfranklin/javascriptplayground.com/pull/89">changes I made on GitHub</a>.</p>
<p>Moving to Netlify involved the following steps:</p>
<ol>
<li>
<p>Update the blog's <code>Gemfile</code> to remove the <code>github-pages</code> gem in favour of
<code>jekyll</code> directly.</p>
</li>
<li>
<p>Sign up / in with Netlify and configure it to build this repository. Netlify
lets you specify the build command (in this case, <code>jekyll build</code>) and the
folder to deploy (<code>_site</code>).</p>
</li>
<li>
<p>Tell Netlify which branches to deploy. You can have it deploy lots of
branches but I told Netlify to track the <code>master</code> branch for now.</p>
</li>
</ol>
<p>And with that, I had Netlify deploying the blog!</p>
<h2>Updating the custom domain</h2>
<p>As part of the free Netlify package you are also able to add custom domains. The
process of moving the domain to being hosted by Netlify was straight forward:</p>
<ol>
<li>
<p>Disable Cloudflare on the domain. I used this for SSL, but Netlify provides
that out of the box too (via <a href="https://letsencrypt.org/">Let's Encrypt</a>). In
hindsight I should have done this last because it meant for a while there
were security warnings on the site.</p>
</li>
<li>
<p>Use Netlify's admin panel to create a DNS zone for the domain, which allows
Netlify to fully control the domain.</p>
</li>
<li>
<p>Netlify then provides the new nameservers, which I was able to login to my
domain provider and update.</p>
</li>
</ol>
<p>And that's about it! Bar the time spent waiting for DNS propagation, that was me
done.</p>
<h2>Simplifying URLs and Netlify redirects</h2>
<p>I also took some extra steps as I decided to simplify down the URL structure of
the blog. Rather than the URL for posts being:</p>
<pre><code>/blog/2018/01/moving-to-netlify
</code></pre>
<p>I wanted to instead change it to:</p>
<pre><code>/moving-to-netlify
</code></pre>
<p>Making this change on the Jekyll site was easy; I updated my <code>_config.yml</code> to
include <code>permalink: /:title/</code>.</p>
<p>If I left it like this and deployed, any links on the web to any of my previous
blog posts would break, which isn't ideal for users. Netlify offers the ability
to <a href="https://www.netlify.com/docs/redirects/">configure redirects</a> to prevent
this from happening.</p>
<p>To do this I created a <code>_redirects</code> file and put the following line into it:</p>
<pre><code>/blog/:year/:month/:title /:title
</code></pre>
<p>This will set up an HTTP 301 redirect from any URL that matches
<code>/blog/:year/:month/:title</code> to <code>/:title</code>. By using the <code>:title</code> syntax Netlify
matches the text and can generate the right URL to redirect the user to.</p>
<p>Whilst I hope to not have to be changing my URLs on a regular basis having the
ability to do so with Netlify is fantastic.</p>
<h2>The future of JS Playground</h2>
<p>Moving to a platform that gives more control will enable much more on this site,
and along with some of the upcoming video and written content, I'm hopeful that
it will be a great year for this blog.</p>
Testing React with Enzyme and Jest: a new video course2018-02-12T00:00:00+00:00http://www.jackfranklin.co.uk/blog/testing-react/<p>Today I'm releasing my brand new video series titled "Testing React with Jest
and Enzyme".</p>
<p>I've been working with, writing tutorials, and speaking about React for a few
years now and something that I get asked more often than not is how to test
React components.</p>
<p>There are many great courses out there to help you learn React, but this course
is specifically for those who have written React components and would like to know
how best to test them. Not only the specifics of <em>how</em> to test, configuring
Jest, using Enzyme's API, but also <em>what</em> to test.</p>
<p>When is is right to reach for a snapshot test? When should we pull logic out of
components and test it separately? How do I test components that are connected
to Redux?</p>
<p>This series consists of eleven videos, each ranging from 5-10 minutes in length.
They are purposefully designed to be easily watchable on a commute, on a quick
break from work or when you've got a spare half hour over a weekend. The first
five videos in the series are free and you can purchase the rest for $20.</p>
<p>By purchasing the videos you'll also get access to all the source code, any
updates over time and the ability to email me with questions about the course.</p>
<p>If this sounds interesting, you can watch the first video below, and head to the
<a href="http://www.jackfranklin.co.uk/testing-react-enzyme-jest">Testing React page</a> for the rest of the videos and
to buy the full package.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/aSQ8v9JH5C8" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen=""></iframe>
Preferring code over comments2018-02-15T00:00:00+00:00http://www.jackfranklin.co.uk/blog/prefer-code-over-comments/<p>I think we'd all agree that code comments are a good way to document code that
is otherwise hard to follow. Sometimes there's just no way to make the code as
clear as you'd like and a comment is a good solution.</p>
<p>That said, comments have one large issue: they can get out of date. An outdated
comment that is incorrect could cause you to lose a lot of time to debugging.
You may set out with the best intentions of keeping the code and comment in sync
but realistically over time it won't happen.</p>
<p>Whenever possible it's best to remove comments if you can make the code more
explicit. I came across a nice example of this recently that shows this in
action.</p>
<h2>The problem with comments in action</h2>
<p>I was working with an API that would respond with a custom <code>code</code> property on
each response. This API was taking a query and returning search results, and the
<code>code</code> in the response would signify if the response was successful, or if no
results were found, or if there was an API error. I wrote a first pass at a
small JavaScript module to wrap this API and ended up with code that looked like
so:</p>
<pre class="language-js"><code class="language-js"><span class="token function">makeRequestToLibrary</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> code <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>code <span class="token operator">===</span> <span class="token number">2000</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// 2000 is the success code</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token operator">...</span> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>code <span class="token operator">===</span> <span class="token number">4040</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// 4040 = our request returned no results</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token operator">...</span> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>code <span class="token operator">===</span> <span class="token number">4020</span> <span class="token operator">||</span> code <span class="token operator">===</span> <span class="token number">4021</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// 4020 and 4021 are API issues - invalid key, invalid request, etc</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token operator">...</span> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>This works well, and is reasonably clear, but is leaving itself wide open to the
outdated comments problem. It would be very easy for a developer to add in a new
code we need to deal with and not update the comments, or the API to change its
codes, or a combination of both of them. You'd be in danger of ending up with
something that looked like this:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>code <span class="token operator">===</span> <span class="token number">4030</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// 4020 and 4021 are API issues - invalid key, invalid request, etc</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token operator">...</span> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Here the comment bears no relation to the error - is it the case that <code>4030</code> is
the new error code, or is it the case that we should handle <code>4020</code> instead of
<code>4030</code> and we made a typo with the number? It's impossible to tell.</p>
<h2>Removing comments for code</h2>
<p>Instead of comments we can encode the knowledge that maps status codes to
responses such that the code becomes self documenting and we can remove the
comments whilst maintaining the clarity that we were aiming for.</p>
<p>To do this we can create an object that maps a response type to the code:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token constant">API_RESPONSES</span> <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token constant">SUCCESS</span><span class="token operator">:</span> <span class="token number">2000</span><span class="token punctuation">,</span><br> <span class="token constant">NO_RESULTS</span><span class="token operator">:</span> <span class="token number">4040</span><span class="token punctuation">,</span><br> <span class="token constant">INVALID_KEY</span><span class="token operator">:</span> <span class="token number">4020</span><span class="token punctuation">,</span><br> <span class="token constant">INVALID_REQUEST</span><span class="token operator">:</span> <span class="token number">4021</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span></code></pre>
<p>And now update our code (for now I've left the comments in place):</p>
<pre class="language-js"><code class="language-js"><span class="token function">makeRequestToLibrary</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> code <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>code <span class="token operator">===</span> <span class="token constant">API_RESPONSES</span><span class="token punctuation">.</span><span class="token constant">SUCCESS</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// 2000 is the success code</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token operator">...</span> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>code <span class="token operator">===</span> <span class="token constant">API_RESPONSES</span><span class="token punctuation">.</span><span class="token constant">NO_RESULTS</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// 4040 = our request returned no results</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token operator">...</span> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>code <span class="token operator">===</span> <span class="token constant">API_RESPONSES</span><span class="token punctuation">.</span><span class="token constant">INVALID_KEY</span> <span class="token operator">||</span> code <span class="token operator">===</span> <span class="token constant">API_RESPONSES</span><span class="token punctuation">.</span><span class="token constant">INVALID_REQUEST</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// 4020 and 4021 are API issues - invalid key, invalid request, etc</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token operator">...</span> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>Notice how now our comments are effectively duplicating what the code is telling
the reader. Any person curious to learn the code that maps to each response type
need only jump to the definition of <code>API_RESPONSES</code> and find it. We can remove
the comments and not lose any clarity:</p>
<pre class="language-js"><code class="language-js"><span class="token function">makeRequestToLibrary</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> code <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>code <span class="token operator">===</span> <span class="token constant">API_RESPONSES</span><span class="token punctuation">.</span><span class="token constant">SUCCESS</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token operator">...</span> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>code <span class="token operator">===</span> <span class="token constant">API_RESPONSES</span><span class="token punctuation">.</span><span class="token constant">NO_RESULTS</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token operator">...</span> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>code <span class="token operator">===</span> <span class="token constant">API_RESPONSES</span><span class="token punctuation">.</span><span class="token constant">INVALID_KEY</span> <span class="token operator">||</span> code <span class="token operator">===</span> <span class="token constant">API_RESPONSES</span><span class="token punctuation">.</span><span class="token constant">INVALID_REQUEST</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token literal-property property">success</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token operator">...</span> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<h2>Comments aren't always bad</h2>
<p>Please don't misunderstand me; I'm not saying that all comments are bad.
Sometimes the nature of code is that it a comment can make it much clearer.
Sometimes though a feeling of wanting to add an explanatory comment can be a
hint of a change to your code that could make things clearer and more self
documenting.</p>
<p>Use comments when you need to, but first take a moment to think if you can make
a code change first.</p>
Habits of Successful React components2018-03-07T00:00:00+00:00http://www.jackfranklin.co.uk/blog/habits-of-successful-react-components/<p>One of the best features of React, and one of the reasons I think so many people
love using it, is that it gives you the freedom to choose what approach you're
going to take. As a primarily view based library, React provides no out-the-box
opinions on how you make HTTP requests, how you style your components, what
naming conventions to use, and so on. It leaves all those decisions up to you.
This is a good thing in my experience; often a set of conventions that worked
well for one of your applications might not work so well for another and having
that flexibility is something I've come to appreciate.</p>
<p>That said, over the last few years of writing React components I've come up with
a set of guidelines that I tend to follow, and in this post I wanted to share
those below. I'd love to hear if you disagree with any of these (all of these
are personal preference) or if you have any more to add to the list.</p>
<h2>1. Has a single job or responsibility</h2>
<p>If you picked one rule out of this list to follow, it would be this one. The
approach I try to take here is to have as many React components as I need and to
never feel like I've got too many. Components are made to be composed together
and as such you should compose them whenever it makes sense to avoid any one
component doing too much.</p>
<p>A good indication of this in action is if a component has a very long <code>render</code>
method (see Point 5 for more). That will often hint that it's doing too much
that could be delegated. A similar indicator is a component with a lot of state
or props. If you're having to store a huge amount of data on a component, or
take 10 props to ensure it can be configured correctly, then maybe you should
instead have more components that take fewer props.</p>
<p>Take for example, a component that fetches users from an API, lists them and
lets you click on them to see the active user. It would have three distinct
functions that would make up the component. Firstly, the HTTP logic in
<code>componentDidMount</code> (I've left out error handling for the example but imagine
it's there):</p>
<pre class="language-js"><code class="language-js"><span class="token function">componentDidMount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">fetchUsersFromMyApi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">users</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> users <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>You'd then have the code to list these users, either directly in <code>render</code> or in
another method that you call from <code>render</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token function">renderUsers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>ul<span class="token operator">></span><br> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>users<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">user</span> <span class="token operator">=></span><br> <span class="token operator"><</span>li key<span class="token operator">=</span><span class="token punctuation">{</span>user<span class="token punctuation">.</span>id<span class="token punctuation">}</span> onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">viewUser</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">{</span>user<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span><br> <span class="token punctuation">)</span><span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>ul<span class="token operator">></span><br> <span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>And then you'd need the logic for setting the active user in the state:</p>
<pre class="language-js"><code class="language-js"><span class="token function">viewUser</span><span class="token punctuation">(</span><span class="token parameter">userId</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">activeUser</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>users<span class="token punctuation">[</span>userId<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>And the relevant logic in the <code>render</code> function:</p>
<pre class="language-js"><code class="language-js"><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">renderUsers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><br> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>activeUser <span class="token operator">&&</span> <span class="token operator"><</span>div<span class="token operator">></span>output user things here<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>This component is now doing a lot of work! Imagine having to write tests for
this component, you'd have to mock out the HTTP call, test that it handles with
success and error cases, check that it lists the right users, and test that it
can show a user when you click on them. That's a lot to test. Instead, let's
imagine we had a suite of components that we could compose together.</p>
<p>The first component, named something like <code>UsersContainer</code>, could be responsible
for fetching the users and then passing them down into <code>UserList</code>, which in turn
could render a <code>User</code> component.</p>
<p>By doing this you end up with a tree of components, where each one has one job
and then passes the rest of the work down to the child:</p>
<ul>
<li><code>UsersContainer</code>: fetch data, show loading spinner / errors, pass data down</li>
<li><code>UserList</code>: lists the users, delegating the rendering to <code>User</code>. Keeps track
of the active user.</li>
<li><code>User</code> can render an individual user and deal with UI interactions.</li>
</ul>
<h2>2. Delegates data processing to an external module</h2>
<p>As a general rule I like to keep my React components as succinct as they can be,
and one of the best ways of doing that is to pull logic out into external
modules. Taking the list of users example from above, imagine the component had
to make the request and then process the data:</p>
<pre class="language-js"><code class="language-js"><span class="token function">componentDidMount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">fetchUsers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">users</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">processUsersFromApi</span><span class="token punctuation">(</span>users<span class="token punctuation">)</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><br><br><span class="token function">processUsersFromApi</span><span class="token punctuation">(</span><span class="token parameter">users</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// some data processing here</span><br><span class="token punctuation">}</span><br><br><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// render some things!</span><br><span class="token punctuation">}</span></code></pre>
<p>To test this code we have to always go through the component. It's also harder
if we want to reuse this processing logic (you could imagine more than one place
in our code having to process data from our users API), and makes the React
component contain a substantial amount of code that isn't specific to UI.</p>
<p>Instead, we're much better off extracting that code into a separate module:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> processUsersFromApi <span class="token keyword">from</span> <span class="token string">'./process-users-from-api'</span><br><br><span class="token function">componentDidMount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">fetchUsers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>processUsersFromApi<span class="token punctuation">)</span><br><span class="token punctuation">}</span><br><br><span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// render some things!</span><br><span class="token punctuation">}</span></code></pre>
<p>And now the component is shorter and contains much less logic that we have to
understand to work on it. Another advantage is that we can test our business
logic in isolation now without having to mount React components in test to do
so.</p>
<h2>3. Uses PropTypes consistently (or TypeScript/Flow)</h2>
<p>It's tempting when you're writing a component to not use PropTypes. They involve
extra effort both to write initially, and then to maintain as you develop your
component. However, they offer a lot of value to people who use your component,
and other people on your team who have to maintain the code. You'll thank
yourself if you come back to a component in six months and have to figure out
how to use it!</p>
<p>Documenting the prop types also means a typo is spotted much quicker than it
would be otherwise:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">UserComponent</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><br>UserComponent<span class="token punctuation">.</span>propTypes <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">isAuthenticated</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>bool<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br><span class="token punctuation">}</span><br><br><span class="token comment">// later...</span><br><br><span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// causes error about missing prop isAuthenticated in console</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>UserComponent isAuthenticatd<span class="token operator">=</span><span class="token punctuation">{</span><span class="token boolean">true</span><span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<h2>4. Has a concise <code>render</code> method</h2>
<p>A good sign that a component is taking on too much responsibility is if its
render method becomes hard to understand. A component should ideally render a
small amount of DOM, or delegate parts of its rendering to other components.</p>
<p>For example, let's take a component that shows a user form. It shows a few text
fields (to keep the example a bit shorter I've omitted some of the fields) and a
search button. The search button's outputs and classes depend on if we've
submitted the form or not, and we make use of the excellent
<a href="https://github.com/JedWatson/classnames">classnames</a> package to conditionally
set classes.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>onSubmit<span class="token punctuation">}</span><span class="token operator">></span><br> <span class="token operator"><</span>label<span class="token operator">></span><br> Your name<br> <span class="token operator"><</span>input<br> type<span class="token operator">=</span><span class="token string">"text"</span><br> value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>input<span class="token punctuation">}</span><br> placeholder<span class="token operator">=</span><span class="token string">"Enter your name"</span><br> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>onChange<span class="token punctuation">}</span><br> <span class="token operator">/</span><span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span><br> <span class="token punctuation">{</span><span class="token comment">/* imagine a few more text fields, labels, and so on...*/</span><span class="token punctuation">}</span><br> <span class="token operator"><</span>button<br> type<span class="token operator">=</span><span class="token string">"submit"</span><br> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token function">classNames</span><span class="token punctuation">(</span><span class="token string">'btn'</span><span class="token punctuation">,</span> <span class="token string">'btn-primary'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">loading</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>loading<span class="token punctuation">,</span><br> <span class="token literal-property property">disabled</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>input <span class="token operator">===</span> <span class="token string">''</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><br> <span class="token operator">></span><br> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>loading <span class="token operator">?</span> <span class="token string">'Loading...'</span> <span class="token operator">:</span> <span class="token string">'Go'</span><span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Already, even in this example, this component takes some effort to understand.
And this is with some of the code omitted to avoid this blog post being too
long! React and JSX is very expressive and on the whole easy to follow, but once
your render method has some extra functionality or conditionals, they can
occasionally become hard to follow.</p>
<p>As a first pass you could pull out another render function to just handle the
button:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">renderSubmit</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>button<br> type<span class="token operator">=</span><span class="token string">"submit"</span><br> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token function">classNames</span><span class="token punctuation">(</span><span class="token string">'btn'</span><span class="token punctuation">,</span> <span class="token string">'btn-primary'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">loading</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>loading<span class="token punctuation">,</span><br> <span class="token literal-property property">disabled</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>input <span class="token operator">===</span> <span class="token string">''</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><br> <span class="token operator">></span><br> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>loading <span class="token operator">?</span> <span class="token string">'Loading...'</span> <span class="token operator">:</span> <span class="token string">'Go'</span><span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>onSubmit<span class="token punctuation">}</span><span class="token operator">></span><br> <span class="token operator"><</span>label<span class="token operator">></span><br> Your name<br> <span class="token operator"><</span>input<br> type<span class="token operator">=</span><span class="token string">"text"</span><br> value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>input<span class="token punctuation">}</span><br> placeholder<span class="token operator">=</span><span class="token string">"Enter your name"</span><br> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>onChange<span class="token punctuation">}</span><br> <span class="token operator">/</span><span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span><br> <span class="token punctuation">{</span><span class="token comment">/* imagine a few more text fields, labels, and so on...*/</span><span class="token punctuation">}</span><br> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">renderSubmit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>This works, and is a valid step to take, but now whilst the <code>render</code> method is
smaller, all you've done is move some of it into another function. There are
times where this is enough to add clarity, but one confusing aspect is that it's
harder to see what props and/or state the submit button uses. So to make that
clearer we could pass them in as arguments:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">renderSubmit</span><span class="token punctuation">(</span><span class="token parameter">loading<span class="token punctuation">,</span> inputValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>button<br> type<span class="token operator">=</span><span class="token string">"submit"</span><br> className<span class="token operator">=</span><span class="token punctuation">{</span><span class="token function">classNames</span><span class="token punctuation">(</span><span class="token string">'btn'</span><span class="token punctuation">,</span> <span class="token string">'btn-primary'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">loading</span><span class="token operator">:</span> loading<span class="token punctuation">,</span><br> <span class="token literal-property property">disabled</span><span class="token operator">:</span> inputValue <span class="token operator">===</span> <span class="token string">''</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><br> <span class="token operator">></span><br> <span class="token punctuation">{</span>loading <span class="token operator">?</span> <span class="token string">'Loading...'</span> <span class="token operator">:</span> <span class="token string">'Go'</span><span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>onSubmit<span class="token punctuation">}</span><span class="token operator">></span><br> <span class="token operator"><</span>label<span class="token operator">></span><br> Your name<br> <span class="token operator"><</span>input<br> type<span class="token operator">=</span><span class="token string">"text"</span><br> value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>input<span class="token punctuation">}</span><br> placeholder<span class="token operator">=</span><span class="token string">"Enter your name"</span><br> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>onChange<span class="token punctuation">}</span><br> <span class="token operator">/</span><span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span><br> <span class="token punctuation">{</span><span class="token comment">/* imagine a few more text fields, labels, and so on...*/</span><span class="token punctuation">}</span><br> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">renderSubmit</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>loading<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>input<span class="token punctuation">)</span><span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>This is certainly nicer because it's explicit about the values the submit button
needs, but there's nothing to stop a developer by-passing this mechanism and
just referring to <code>this.props</code> or <code>this.state</code> directly.</p>
<p>The final, best step, is to instead embrace React to the fullest and extract a
submit button component.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">App</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>form onSubmit<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>onSubmit<span class="token punctuation">}</span><span class="token operator">></span><br> <span class="token operator"><</span>label<span class="token operator">></span><br> Your name<br> <span class="token operator"><</span>input<br> type<span class="token operator">=</span><span class="token string">"text"</span><br> value<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>input<span class="token punctuation">}</span><br> placeholder<span class="token operator">=</span><span class="token string">"Enter your name"</span><br> onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>onChange<span class="token punctuation">}</span><br> <span class="token operator">/</span><span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>label<span class="token operator">></span><br> <span class="token operator"><</span>Button<br> loading<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>loading<span class="token punctuation">}</span><br> disabled<span class="token operator">=</span><span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>input <span class="token operator">===</span> <span class="token string">''</span><span class="token punctuation">}</span><br> <span class="token operator">/</span><span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>form<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Now we have a smaller component and we've ended up with a reusable button
component that should be save us time the next time we build out a form.</p>
<h2>5. Does not store state that can be calculated from <code>props</code></h2>
<p>One common mistake that beginners make with React is to set far too many
attributes onto the state and spend a lot of effort keeping them in sync. A good
hint that you're doing this is that you find yourself continuously having to use
<a href="https://reactjs.org/docs/react-component.html#componentwillreceiveprops"><code>componentWillReceiveProps</code></a>
to react to property changes and update your state. To be clear: there are times
when you will need to use this method, but on the whole you should be trying to
avoid it.</p>
<p>If you need to do some async work (such as making HTTP requests) when the
component does update, you should use
<a href="https://reactjs.org/docs/react-component.html#componentdidupdate"><code>componentDidUpdate</code></a>.</p>
<p>There are a couple of rules I try to follow that help to avoid these issues:</p>
<ul>
<li>If a piece of data can be computed purely from properties, it should not be
kept in state.</li>
<li>Any data that a component has as its state should be data that <em>the component
itself changes</em>. A hint that you might not have quite the right state is if
you find yourself referring to <code>this.state.userName</code> without ever having a
<code>this.setState</code> call within a component.</li>
</ul>
<p>For the first case, a good example here is a component that takes <code>firstName</code>
and <code>lastName</code> properties:</p>
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>UserProfileLink firstName<span class="token operator">=</span><span class="token string">"Jack"</span> lastName<span class="token operator">=</span><span class="token string">"Franklin"</span> <span class="token operator">/</span><span class="token operator">></span></code></pre>
<p>Inside this component we might decide to store a <code>fullName</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">UserProfileLink</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><br><br> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">fullName</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>firstName <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>lastName <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Now in our render method we can refer to <code>this.state.fullName</code> to show the
user's full name, and we now have state that is never changed within our
component, and we'll have to use <code>componentWillReceiveProps</code> to keep it in sync.</p>
<p>Keeping data in sync is hard; and it's a problem that the framework should solve
for you. Rather than trying to manually do this work, we can instead just
compute the <code>fullName</code> in our <code>render</code> call:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">UserProfileLink</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> fullName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>firstName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>lastName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br><br> <span class="token keyword">return</span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{</span>fullName<span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>If the computation is more expensive, and you want to ensure you're not
regenerating the value even if the properties that make it up haven't changed,
you could look into a technique called "memoization". This
<a href="https://addyosmani.com/blog/faster-javascript-memoization/">old but still excellent blog post</a>
by Addy Osmani is a good introduction into it. There are plenty of libraries
available to you too on npm that will help with this.</p>
<h2>6. Has consistently named event handlers</h2>
<p>A short point, but one that I've fallen foul to many times! It's very easy to
pick names for event handling methods in your React component with no real
convention and on a smaller component or app that would not be an issue, but on
larger apps you'll thank yourself for coming up with a convention that makes
things easier.</p>
<p>I've taken to prefixing all my event handling methods with <code>on</code>, so that it's
clear when looking through a component which methods are event handlers. It also
means you can search a file for <code>on</code> and find the methods fairly easily.</p>
<p>This is a small point but one that will add up each time you use it in a
component that you're working on. Having a variety of event handler names (I've
written components that use <code>onUserClick</code> and <code>userSubmittedForm</code>, for example)
makes it harder to work on the code. The exact convention doesn't matter, but
having one will definitely improve your component's maintainability.</p>
<h2>7. Uses class properties for event handlers</h2>
<p>With the <a href="https://github.com/tc39/proposal-class-fields">class fields proposal</a>
now at Stage 3 of the ECMA process (meaning it's very likely to end up as part
of JavaScript) and there being a
<a href="https://babeljs.io/docs/plugins/transform-class-properties/">babel plugin available for this proposal</a>,
it's become very common in the React community to define event handlers as arrow
functions. This helps differentiate them from regular methods (which compliments
Point 6 nicely) and ensures that they are bound correctly, so you don't have to
explicitly call <code>.bind(this)</code> to ensure that they are called with the right
scope.</p>
<p>Coupled with a solid naming convention, this makes event handlers very easy to
distinguish:</p>
<pre class="language-js"><code class="language-js"><span class="token function-variable function">onUserSubmitForm</span> <span class="token operator">=</span> <span class="token parameter">event</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token comment">// do things</span><br><span class="token punctuation">}</span><br><br><span class="token function">otherNonEventMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// do other things</span><br><span class="token punctuation">}</span></code></pre>
<p>It's worth noting that there
<a href="https://medium.com/@charpeni/arrow-functions-in-class-properties-might-not-be-as-great-as-we-think-3b3551c440b1">are some issues with arrow functions that it's worth being aware of</a>,
but in my opinion they present the best option available to us now. If and when
the <a href="https://tc39.github.io/proposal-decorators/">Decorator Proposal</a> makes it
into the language, we may end up being able to use a decorator on event handlers
to bind them to the right scope, but until then arrow functions are a good
alternative.</p>
<h2>Conclusion</h2>
<p>By no means an exhaustive list; these are seven traits that I think represent
React components that tend to be more reliable, more maintainable, more testable
and more fun to work on. I'd love to know if you have any to add to this list,
or if you have any that you do differently. The great thing about React is that
it gives you a lot of alternative approaches, so it's always great to see how
others are doing it.</p>
Getting started with JSON Decoding in Elm2018-04-19T00:00:00+00:00http://www.jackfranklin.co.uk/blog/json-decoding-in-elm/<p><em>This post was first published on ElmPlayground.com but has now been updated and
moved to this blog.</em></p>
<p>Something that continually trips beginners up in Elm is dealing with JSON
responses from a third party API. I think this is because it's a completely new
concept to those picking up Elm from JavaScript. It certainly took me a long
time to get comfortable with Elm.</p>
<p>Today, we'll look at using JSON decoders in Elm to deal with data from an API.
I've purposefully made some of the data awkward to show some of the more complex
parts of decoding JSON. Hopefully the APIs you're working with are much better
than my fake one, but this post should have you covered if not!</p>
<p>Before we get into that though, let's go through the basics of Elm decoders.</p>
<h2>What is an Elm JSON decoder?</h2>
<p>A decoder is a function that can take a piece of JSON and decode it into an Elm
value, with a type that matches a type that Elm knows about. For example, if we
have this JSON:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span> <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"Jack"</span> <span class="token punctuation">}</span></code></pre>
<p>Then I need to tell Elm that the value at the <code>name</code> field is a string, so it
can parse the JSON value <code>"Jack"</code> and turn it into the Elm string <code>"Jack"</code>. Elm
ships with many decoders for all of the built in types in Elm, and also the
ability for us to make our own decoders, which is of more interest to us, as
more often than not you'll be taking an object and converting it into an Elm
record.</p>
<h2>Layering decoders</h2>
<p>The real power of Elm's decoders, which is also why they can be pretty
complicated to work with, is that you can combine them to make other decoders.
This is something Brian Hicks wrote about in his
<a href="https://www.brianthicks.com/post/2016/10/17/composing-decoders-like-lego/">post on Elm decoders being like Lego</a>,
which I highly recommend reading. For example, Elm ships with a decoder for
decoding an object with one field, called <code>JSON.Decode.map</code>. Its type signature
is:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">map</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token hvariable">a</span> <span class="token operator">-></span> <span class="token hvariable">value</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token constant">Decoder</span> <span class="token hvariable">a</span> <span class="token operator">-></span> <span class="token constant">Decoder</span> <span class="token hvariable">value</span></code></pre>
<p>What's important to remember is that all these decoder functions <em>return new
decoders</em>. You have to layer the decoders together to match your JSON. In the
case of <code>map</code>, its arguments are as follows:</p>
<ul>
<li><code>(a -> value)</code> a function that will take the decoded value, and should return
data of the type <code>value</code>, which is the Elm data you want to get out of your
JSON.</li>
<li><code>Decoder a</code> is a decoder that can decode the given JSON and pull out a value
of type <code>a</code>, which will be passed into the function given as the first
argument.</li>
</ul>
<p>For example, taking the JSON that we had earlier:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span> <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"Jack"</span> <span class="token punctuation">}</span></code></pre>
<p>Let's say we want to decode this into the following Elm record:</p>
<pre class="language-elm"><code class="language-elm"><span class="token punctuation">{</span> <span class="token hvariable">name</span> <span class="token operator">=</span> <span class="token string">"Jack"</span> <span class="token punctuation">}</span></code></pre>
<p>The first step is to create our decoder. We're going to use <code>map</code>, because we
want to decode a JSON object where we only care about one field. The JSON we're
decoding could have <em>any number of fields</em>, but we use <code>map</code> because <em>we only
care about one field</em>.</p>
<p><strong>Note</strong>: through the following code examples I've imported the JSON decoding
module as <code>import Json.Decode as Decode</code>, so I'll refer to functions as
<code>Decode.map</code>, <code>Decode.string</code>, and so on.</p>
<p>First I'll define my decoder. The first argument is an object that takes the
decoded value and turns it into the thing I want to end up with. The second is a
decoder that can take a value at a particular field, and decode it. To do that I
use <code>Decode.at</code>, which plucks an item out of the object and applies the given
decoder to it:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">userDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">map</span> <span class="token punctuation">(</span>\<span class="token hvariable">name</span> <span class="token operator">-></span> <span class="token punctuation">{</span> <span class="token hvariable">name</span> <span class="token operator">=</span> <span class="token hvariable">name</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span><span class="token string">"name"</span><span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span></code></pre>
<p>Before we go on, can you guess what the type of <code>userDecoder</code> is here?</p>
<p>It is:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">userDecoder</span> <span class="token operator">:</span> <span class="token constant">Decode.Decoder</span> <span class="token punctuation">{</span> <span class="token hvariable">name</span> <span class="token operator">:</span> <span class="token constant">String</span> <span class="token punctuation">}</span></code></pre>
<p>Because it's a decoder that returns an Elm record with a <code>name</code> property of type
<code>String</code>.</p>
<p>Now let's run this decoder and see what we get. We can run a decoder using
<code>Decode.decodeString</code>, which takes a decoder and input. It returns an Elm
result, which will be <code>Ok</code> if we were successful, or <code>Err</code> if we had an issue.
Normally, if you're decoding HTTP responses and so on, you won't ever call this
function manually, the library you're using will do it for you. It is really
useful for testing decoders though!</p>
<p><strong>Note</strong>: if you're more familiar with Elm decoding you might be aware of some
extra Elm packages that exist to make JSON decoding easier. We'll cover those in
a future tutorial; for now I'm sticking to the core Elm library only.</p>
<p>I can run my decoder like so:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">Decode.decodeString</span> <span class="token hvariable">userDecoder</span> <span class="token string">"""{"name": "Jack"}"""</span></code></pre>
<p>By wrapping the JSON input with three quotes on each side, I avoid having to
escape the quotes in the JSON (three quotes is a multiline string in Elm where
you can use double quotes without escaping them). This gives us back:</p>
<pre class="language-elm"><code class="language-elm"><span class="token constant">Ok</span> <span class="token punctuation">{</span> <span class="token hvariable">name</span> <span class="token operator">=</span> <span class="token string">"Jack"</span> <span class="token punctuation">}</span></code></pre>
<p>Which is perfect, and exactly what we want!</p>
<h2>Type aliasing</h2>
<p>It's pretty dull to have to repeat the type <code>{ name : String }</code> throughout this
imaginary example, so I can instead type alias it:</p>
<pre class="language-elm"><code class="language-elm"><span class="token keyword">type</span> <span class="token keyword">alias</span> <span class="token constant">User</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token hvariable">name</span> <span class="token operator">:</span> <span class="token constant">String</span> <span class="token punctuation">}</span></code></pre>
<p>When you define a type alias in Elm, you not only get the alias but <code>User</code> is a
constructor function:</p>
<pre class="language-elm"><code class="language-elm"><span class="token constant">User</span> <span class="token operator">:</span> <span class="token constant">String</span> <span class="token operator">-></span> <span class="token constant">User</span></code></pre>
<p>This means that I can call:</p>
<pre class="language-elm"><code class="language-elm"><span class="token constant">User</span> <span class="token string">"jack"</span></code></pre>
<p>And get back:</p>
<pre class="language-elm"><code class="language-elm"><span class="token punctuation">{</span> <span class="token hvariable">name</span> <span class="token operator">=</span> <span class="token string">"Jack"</span> <span class="token punctuation">}</span></code></pre>
<p>We can use this to our advantage. Recall that our <code>userDecoder</code> looks like so:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">userDecoder</span> <span class="token operator">:</span> <span class="token constant">Decode.Decoder</span> <span class="token punctuation">{</span> <span class="token hvariable">name</span> <span class="token operator">:</span> <span class="token constant">String</span> <span class="token punctuation">}</span><br><span class="token hvariable">userDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">Decode.map</span> <span class="token punctuation">(</span>\<span class="token hvariable">name</span> <span class="token operator">-></span> <span class="token punctuation">{</span> <span class="token hvariable">name</span> <span class="token operator">=</span> <span class="token hvariable">name</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"name"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span></code></pre>
<p>Firstly, we can change the type annotation:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">userDecoder</span> <span class="token operator">:</span> <span class="token constant">Decode.Decoder</span> <span class="token constant">User</span><br><span class="token hvariable">userDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">Decode.map</span> <span class="token punctuation">(</span>\<span class="token hvariable">name</span> <span class="token operator">-></span> <span class="token punctuation">{</span> <span class="token hvariable">name</span> <span class="token operator">=</span> <span class="token hvariable">name</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"name"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span></code></pre>
<p>And then we can update the function that creates our <code>User</code>:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">userDecoder</span> <span class="token operator">:</span> <span class="token constant">Decode.Decoder</span> <span class="token constant">User</span><br><span class="token hvariable">userDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">Decode.map</span> <span class="token punctuation">(</span>\<span class="token hvariable">name</span> <span class="token operator">-></span> <span class="token constant">User</span> <span class="token hvariable">name</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"name"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span></code></pre>
<p>But whenever you have something of the form:</p>
<pre class="language-elm"><code class="language-elm"><span class="token punctuation">(</span>\<span class="token hvariable">name</span> <span class="token operator">-></span> <span class="token constant">User</span> <span class="token hvariable">name</span><span class="token punctuation">)</span></code></pre>
<p>Or, more generically:</p>
<pre class="language-elm"><code class="language-elm"><span class="token punctuation">(</span>\<span class="token hvariable">x</span> <span class="token operator">-></span> <span class="token hvariable">y</span> <span class="token hvariable">x</span><span class="token punctuation">)</span></code></pre>
<p>We can replace that by just passing the function we're calling directly, leaving
us with the decoder:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">userDecoder</span> <span class="token operator">:</span> <span class="token constant">Decode.Decoder</span> <span class="token constant">User</span><br><span class="token hvariable">userDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">Decode.map</span> <span class="token constant">User</span> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"name"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span></code></pre>
<p>This is the most common pattern you'll see when dealing with decoding in Elm.
The first argument to an object decoder is nearly always a constructor for a
type alias. Just remember, it's a function that takes all the decoded values and
turns them into the thing we want to end up with.</p>
<h2>An alternative to <code>Decode.at</code></h2>
<p>The decoding library also provides <code>Decode.field</code>, which reads out the value in
a particular field.</p>
<p><code>Decode.field "foo" Decode.string</code> is the equivalent of
<code>Decode.at ["foo"] Decode.string</code>, but some find it reads a bit nicer.
<code>Decode.at</code> has the advantage of accepting a list to access nested fields, but
if you don't need that you could use <code>Decode.field</code>.</p>
<pre class="language-elm"><code class="language-elm"><span class="token comment">-- these two decoders are equivalent</span><br><br><span class="token hvariable">userDecoder</span> <span class="token operator">:</span> <span class="token constant">Decode.Decoder</span> <span class="token constant">User</span><br><span class="token hvariable">userDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">Decode.map</span> <span class="token constant">User</span> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"name"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span><br><br><span class="token hvariable">userDecoder</span> <span class="token operator">:</span> <span class="token constant">Decode.Decoder</span> <span class="token constant">User</span><br><span class="token hvariable">userDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">Decode.map</span> <span class="token constant">User</span> <span class="token punctuation">(</span><span class="token hvariable">Decode.field</span> <span class="token string">"name"</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span></code></pre>
<h2>Decoding a more complex JSON structure</h2>
<p>Now we're a bit more familiar with decoders, let's look at our API and dealing
with the data it gives us.</p>
<h2>The User Type</h2>
<p>Our application is dealing with a <code>User</code> type that looks like so:</p>
<pre class="language-elm"><code class="language-elm"><span class="token keyword">type</span> <span class="token keyword">alias</span> <span class="token constant">User</span> <span class="token operator">=</span><br> <span class="token punctuation">{</span> <span class="token hvariable">name</span> <span class="token operator">:</span> <span class="token constant">String</span><br> <span class="token punctuation">,</span> <span class="token hvariable">age</span> <span class="token operator">:</span> <span class="token constant">Int</span><br> <span class="token punctuation">,</span> <span class="token hvariable">description</span> <span class="token operator">:</span> <span class="token constant">Maybe</span> <span class="token constant">String</span><br> <span class="token punctuation">,</span> <span class="token hvariable">languages</span> <span class="token operator">:</span> <span class="token constant">List</span> <span class="token constant">String</span><br> <span class="token punctuation">,</span> <span class="token hvariable">playsFootball</span> <span class="token operator">:</span> <span class="token constant">Bool</span><br> <span class="token punctuation">}</span></code></pre>
<p>The only piece of data a user might be missing is <code>description</code>, which is why
it's modelled as a <code>Maybe String</code>.</p>
<h2>The Data</h2>
<p>Keeping in mind the above type we've got, here's the API response we're working
with:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span><br> <span class="token string-property property">"users"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span><br> <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"Jack"</span><span class="token punctuation">,</span><br> <span class="token string-property property">"age"</span><span class="token operator">:</span> <span class="token number">24</span><span class="token punctuation">,</span><br> <span class="token string-property property">"description"</span><span class="token operator">:</span> <span class="token string">"A person who writes Elm"</span><span class="token punctuation">,</span><br> <span class="token string-property property">"languages"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"elm"</span><span class="token punctuation">,</span> <span class="token string">"javascript"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token string-property property">"sports"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">"football"</span><span class="token operator">:</span> <span class="token boolean">true</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span><br> <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"Bob"</span><span class="token punctuation">,</span><br> <span class="token string-property property">"age"</span><span class="token operator">:</span> <span class="token number">25</span><span class="token punctuation">,</span><br> <span class="token string-property property">"languages"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"ruby"</span><span class="token punctuation">,</span> <span class="token string">"scala"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token string-property property">"sports"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span><br> <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"Alice"</span><span class="token punctuation">,</span><br> <span class="token string-property property">"age"</span><span class="token operator">:</span> <span class="token number">23</span><span class="token punctuation">,</span><br> <span class="token string-property property">"description"</span><span class="token operator">:</span> <span class="token string">"Alice sends secrets to Bob"</span><span class="token punctuation">,</span><br> <span class="token string-property property">"languages"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"C"</span><span class="token punctuation">,</span> <span class="token string">"scala"</span><span class="token punctuation">,</span> <span class="token string">"elm"</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token string-property property">"sports"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">"football"</span><span class="token operator">:</span> <span class="token boolean">false</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">]</span><br><span class="token punctuation">}</span></code></pre>
<p>Immediately you should notice some important features of this response:</p>
<ul>
<li>All the data is nested under the <code>users</code> key</li>
<li>Not every user has a <code>description</code> field.</li>
<li>Every user has a <code>sports</code> object, but it doesn't always have the <code>football</code>
key.</li>
</ul>
<p>Granted, this example is a little extreme, but it's not that common to see APIs
that have data like this. The good news is that if you have a nice, friendly,
consistent API, then this blog post will hopefully still help, and you'll have
less work!</p>
<p>When dealing with data like this, I like to start with the simplest piece of the
puzzle and work up to the most complicated. Looking at the data we have, most of
the fields are always present, and always of the same type, so let's start with
that and ignore the rest of the fields.</p>
<p>Let's create the <code>userDecoder</code> that can decode a user object. We know we have
five fields, so we can use <code>Decode.map5</code> to do that. The first argument we'll
give it is the <code>User</code> type, which will be the function that constructs a user
for us. We can easily decode the <code>name</code> field, which is always a string:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">userDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">Decode.map5</span><br> <span class="token constant">User</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"name"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span><br> <span class="token comment">-- more fields to come here</span></code></pre>
<p>And we can do the same for <code>age</code>, which is an integer:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">userDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">Decode.map5</span><br> <span class="token constant">User</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"name"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"age"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.int</span><span class="token punctuation">)</span><br> <span class="token comment">-- other fields to come, hold tight!</span></code></pre>
<p>And we can do the same for <code>languages</code>. <code>languages</code> is a list of strings, and we
can decode that by using the <code>Decode.list</code> decoder, which takes another decoder
which it will use for each individual item. So <code>Decode.list Decode.string</code>
creates a decoder that can decode a list of strings:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">userDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">Decode.map5</span><br> <span class="token constant">User</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"name"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"age"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.int</span><span class="token punctuation">)</span><br> <span class="token comment">-- we'll decode the description field here in a mo</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"languages"</span> <span class="token punctuation">]</span> <span class="token punctuation">(</span><span class="token hvariable">Decode.list</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token comment">-- we'll decode the sports object here in a mo</span></code></pre>
<p>A top tip when you want to test decoders incrementally is that you can use
<code>Decode.succeed</code> to have a decoder pay no attention to the actual JSON and just
succeed with the given value. So to finish our decoder we can simply fill in our
missing fields with <code>Decode.succeed</code>:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">userDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">Decode.map5</span><br> <span class="token constant">User</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"name"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"age"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.int</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.succeed</span> <span class="token constant">Nothing</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"languages"</span> <span class="token punctuation">]</span> <span class="token punctuation">(</span><span class="token hvariable">Decode.list</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.succeed</span> <span class="token constant">False</span><span class="token punctuation">)</span></code></pre>
<p>That makes our decoded <code>description</code> value always <code>Nothing</code> (recall that
<code>description</code> is a <code>Maybe</code>), and our <code>playsFootball</code> value always <code>False</code>.</p>
<h2>Order of decoders</h2>
<p>Something that I failed to realise early on when I was getting used to JSON
decoding is why the decoders above are ordered as such. It's because they match
the ordering of values in the <code>User</code> type alias.</p>
<p>Because the <code>User</code> fields are defined in this order:</p>
<pre class="language-elm"><code class="language-elm"><span class="token keyword">type</span> <span class="token keyword">alias</span> <span class="token constant">User</span> <span class="token operator">=</span><br> <span class="token punctuation">{</span> <span class="token hvariable">name</span> <span class="token operator">:</span> <span class="token constant">String</span><br> <span class="token punctuation">,</span> <span class="token hvariable">age</span> <span class="token operator">:</span> <span class="token constant">Int</span><br> <span class="token punctuation">,</span> <span class="token hvariable">description</span> <span class="token operator">:</span> <span class="token constant">Maybe</span> <span class="token constant">String</span><br> <span class="token punctuation">,</span> <span class="token hvariable">languages</span> <span class="token operator">:</span> <span class="token constant">List</span> <span class="token constant">String</span><br> <span class="token punctuation">,</span> <span class="token hvariable">playsFootball</span> <span class="token operator">:</span> <span class="token constant">Bool</span><br> <span class="token punctuation">}</span></code></pre>
<p>We have to decode in that order, too.</p>
<h2>Decoding maybe values</h2>
<p>If we have a key that is not always present, we can decode that with
<code>Decode.maybe</code>. This takes another decoder, and if that decoder fails because
the key it's looking for isn't present, it will be decoded to <code>Nothing</code>. Else,
it will be decoded to <code>Just val</code>, where <code>val</code> is the value that was decoded.</p>
<p>What this means in practice is that to decode a <code>maybe</code> you simply write the
decoder you would write if the field was always present, in our case:</p>
<pre class="language-elm"><code class="language-elm"><span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"description"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span></code></pre>
<p>And we then wrap it in <code>Decode.maybe</code>:</p>
<pre class="language-elm"><code class="language-elm"><span class="token punctuation">(</span><span class="token hvariable">Decode.maybe</span> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"description"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<p>And that's it! We're now nearly done with our decoder:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">userDecoder</span> <span class="token operator">:</span> <span class="token constant">Decode.Decoder</span> <span class="token constant">User</span><br><span class="token hvariable">userDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">Decode.map5</span><br> <span class="token constant">User</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"name"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"age"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.int</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.maybe</span> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"description"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"languages"</span> <span class="token punctuation">]</span> <span class="token punctuation">(</span><span class="token hvariable">Decode.list</span> <span class="token hvariable">Decode.string</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.succeed</span> <span class="token constant">False</span><span class="token punctuation">)</span> <span class="token comment">-- just this one to go!</span></code></pre>
<h2><code>Decode.map</code></h2>
<p>It's time to get a bit more complex and decode the sports object. Remember that
we just want to pull out the <code>football</code> field, if it's present, but set it to
<code>False</code> if it's not present.</p>
<p>The <code>sports</code> key will be one of three values:</p>
<ul>
<li><code>{}</code></li>
<li><code>{ "football": true }</code></li>
<li><code>{ "football": false }</code></li>
</ul>
<p>And we use it to set the <code>playsFootball</code> boolean to <code>True</code> or <code>False</code>. In the
case where the <code>football</code> key isn't set, we want to default it to <code>False</code>.</p>
<p>Before dealing with the case where it's missing, let's pretend it's always
present, and see how we would decode that. We'd create a decoder that pulls out
the <code>football</code> field, and decodes it as a boolean:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"sports"</span><span class="token punctuation">,</span> <span class="token string">"football"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.bool</span></code></pre>
<p>That would pull out the <code>football</code> key in the <code>sports</code> object, and decode it as
a boolean. However, we need to deal with the <code>football</code> key being missing. The
first thing I'm going to do is define another decoder, <code>sportsDecoder</code>, which
will take the <code>sports</code> object and decode it:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"sports"</span> <span class="token punctuation">]</span> <span class="token hvariable">sportsDecoder</span><br><br><span class="token hvariable">sportsDecoder</span> <span class="token operator">=</span><br> <span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"football"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.bool</span></code></pre>
<p>This is equivalent to the previous example but we've now split the code up a
little. Remember earlier that we used <code>Decode.succeed</code> to make a JSON decoder
succeed with a given value? That's what we need to use here. We effectively want
to try to decode it first, but if it goes wrong, just return <code>False</code>. If we were
writing our decoder out in English, we'd say:</p>
<ol>
<li>Try to find the value in the <code>football</code> field and decode it as boolean.</li>
<li>If something goes wrong, don't worry about it, just set the value to <code>False</code>.</li>
</ol>
<p>It turns out that Elm gives us <code>Decode.oneOf</code>, which does exactly that!
<code>Decode.oneOf</code> takes a list of decoders and will try each of them in turn. If
anything goes wrong it will try the next decoder in the list. Only if none of
the decoders work will it fail.</p>
<p>So the first thing we can do is wrap our existing <code>sportsDecoder</code> in a
<code>Decode.oneOf</code> call:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">sportsDecoder</span> <span class="token operator">=</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.oneOf</span><br> <span class="token punctuation">[</span> <span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"football"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.bool</span> <span class="token punctuation">]</span><br> <span class="token punctuation">)</span></code></pre>
<p>That will work when the field is present, but now we need to cover the other
case and always return <code>False</code>:</p>
<pre class="language-elm"><code class="language-elm"><span class="token hvariable">sportsDecoder</span> <span class="token operator">=</span><br> <span class="token punctuation">(</span><span class="token hvariable">Decode.oneOf</span><br> <span class="token punctuation">[</span> <span class="token hvariable">Decode.at</span> <span class="token punctuation">[</span> <span class="token string">"football"</span> <span class="token punctuation">]</span> <span class="token hvariable">Decode.bool</span><br> <span class="token punctuation">,</span> <span class="token hvariable">Decode.succeed</span> <span class="token constant">False</span><br> <span class="token punctuation">]</span><br> <span class="token punctuation">)</span></code></pre>
<p>With that change, we decode the value if it exists, or we set it to <code>False</code>.
We're done!</p>
<h2>Conclusion</h2>
<p>I hope this article has gone some way to showing that Elm's decoding isn't quite
as scary as it first seems. Yes, it's not always immediately intuitive, and
takes time to get used to, but once you get the hang of it I think you'll find
it really nice to be able to so explicitly deal with JSON and decode it into
your application's types.</p>
<p>If you'd like to look at the code, I've
<a href="https://github.com/jackfranklin/elm-json-decoding">got a small app on Github</a>
that uses the decoders in this article, and you can
<a href="http://twitter.com/Jack_Franklin">find me on Twitter</a> (or the Elm slack
channel!) if you have any questions.</p>
Enabling VSCode's "Go to Definition" for JSX imports2018-06-13T00:00:00+00:00http://www.jackfranklin.co.uk/blog/vscode-go-to-definition-jsx/<p>I have recently been trialling using Microsoft's VSCode editor as my primary code editor, and so far I've been very happy with it. One feature that I've particularly enjoyed is "Go to Definition". This lets you hover over any variable/class/object/etc and be taken to the place where it is defined, even if it's in another file.</p>
<p>This is particularly useful for me in JavaScript imports. If I have this line:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Foo <span class="token keyword">from</span> <span class="token string">'./foo'</span></code></pre>
<p>I can right click on <code>Foo</code> (or hit the shortcut, <code>F12</code> by default), and click "Go to Definition", and be taken to <code>foo.js</code>.</p>
<p>One problem I found though is that by default, if the file is <code>foo.jsx</code>, not <code>foo.js</code> (at work we put React components in <code>.jsx</code> to differentiate them easily from plain JS files), this won't work. We have Webpack configured to look for both <code>.js</code> and <code>.jsx</code> files, but need to tell VSCode to do the same.</p>
<p>The solution here is to define a <a href="https://code.visualstudio.com/docs/languages/jsconfig"><code>jsconfig.json</code></a>, which is a file that you can define to configure how VSCode understands your projects. We can tell VSCode that we're working with JSX by adding <code>"jsx": "react"</code> to our <code>jsconfig.json</code>:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span><br> <span class="token property">"compilerOptions"</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token property">"baseUrl"</span><span class="token operator">:</span> <span class="token string">"."</span><span class="token punctuation">,</span><br> <span class="token property">"jsx"</span><span class="token operator">:</span> <span class="token string">"react"</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token property">"exclude"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"node_modules"</span><span class="token punctuation">,</span> <span class="token string">"build"</span><span class="token punctuation">]</span><br><span class="token punctuation">}</span></code></pre>
<blockquote>
<p>Note that <code>exclude</code> is important: here I've defined <code>node_modules</code> and also <code>build</code>, which is the directory that Webpack builds to. I'm doing this to stop VSCode wasting time trying to parse files in these directories.</p>
</blockquote>
<p>Once you've updated this, you'll find that "Go to Definition" works just fine on imports from <code>.jsx</code> files, as well as <code>.js</code> files.</p>
Introducing VSCode GoToFile2018-06-21T00:00:00+00:00http://www.jackfranklin.co.uk/blog/vscode-go-to-file-extension/<p>As mentioned in <a href="http://www.jackfranklin.co.uk/vscode-go-to-definition-jsx/">my last post on VSCode</a>, I've
recently been trialling it as my editor of choice and so far have found the
experience to be excellent. Coupled with the
<a href="https://github.com/aioutecism/amVim-for-VSCode">amVim plugin</a>, it's really
suited me well.</p>
<blockquote>
<p>I know many people use <a href="https://github.com/VSCodeVim/Vim">VSCodeVim</a>, but I
was never able to get it running as smoothly as amVim.</p>
</blockquote>
<p>One of the features that amVim doesn't provide is <code>gf</code>, which in Vim means "go
to file". If your cursor was over a string, and you hit <code>gf</code> on the keyboard,
Vim would try to go to that file.</p>
<h2>Existing Plugins</h2>
<p>I started searching for a plugin that might do this, and came across
<a href="https://github.com/fr43nk/seito-openfile">seito-openfile</a>, which worked for
most of my cases, but I really wanted one that I could customise more to work
for me. In particular we use a lot of aliases on our large codebase at work, and
I wanted to build a plugin that could support them.</p>
<p>I couldn't quite find one that did exactly what I wanted, so I decided to bite
the bullet and build one!</p>
<h2>Presenting vscode-go-to-file</h2>
<p><a href="https://github.com/jackfranklin/vscode-go-to-file">VSCode GoToFile</a> is my
attempt at recreating Vim's <code>gf</code> functionality in VSCode. It will also parse
aliases from your <code>jsconfig.json</code>, and is clever enough to try a few common
extensions if the file path doesn't have one (<code>.js</code>, <code>.jsx</code>, <code>.css</code> and
<code>.scss</code>). Working on this plugin also enabled me to experience plugin
development for the first time and I've been really impressed, VSCode offers a
great
<a href="https://code.visualstudio.com/docs/extensionAPI/vscode-api">API that is really well documented</a>
and a
<a href="https://code.visualstudio.com/docs/extensions/overview">great tutorial for getting started</a>.</p>
<h2>Reporting issues</h2>
<p>If you'd like to give this plugin a try, I'd be grateful for any feedback you
may have. I'm sure there are many improvements to be made and I'd love you to
<a href="https://github.com/jackfranklin/vscode-go-to-file/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc">open an issue</a>
if you find a problem.</p>
Reading and updating query params with URLSearchParams2018-07-23T00:00:00+00:00http://www.jackfranklin.co.uk/blog/url-search-params/<p>One of the most common tasks in building a frontend application is to update
query parameters. A quick search for
<a href="https://www.npmjs.com/search?q=query%20string">query string on npm</a> reveals
many options that people have built for tackling this task. But what fewer
people seem to be aware of is that there is now an API for working with query
parameters baked right into the browser and it's called
<a href="https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams"><code>URLSearchParams</code></a>.
In this post we'll have a quick play with the API to see how easy it makes
working with query params.</p>
<h2>Browser Support</h2>
<p>At the time of writing,
<a href="https://caniuse.com/#feat=urlsearchparams">browser support for <code>URLSearchParams</code></a>
is very good. IE11 is the main offender, along with Opera Mini. The good news is
that there is an
<a href="https://github.com/WebReflection/url-search-params">excellent polyfill</a> that
you can use to ensure your application will continue to work in browsers that
don't support it natively 👍.</p>
<h2>Using <code>URLSearchParams</code></h2>
<p><code>URLSearchParams</code> expects to be given a string of query parameters (with or
without the initial <code>?</code>). If you've got a full URL that you'd like to parse
query params from, you can use <code>location.search</code> to pull those out:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// Working with the current URL</span><br><span class="token comment">// URL: buy-shirts-here.com/filter?size=M&colour=red&sleeves=short</span><br>location<span class="token punctuation">.</span>search <span class="token comment">//=> ?size=M&colour=red&sleeves=short</span><br><br><span class="token comment">// Creating an instance of new URL from scratch works too...</span><br><span class="token keyword">const</span> url <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URL</span><span class="token punctuation">(</span><span class="token string">"https://buy-shirts-here.com/filter?filter?size=M&colour=red&sleeves=short"</span><span class="token punctuation">)</span><br>url<span class="token punctuation">.</span>search <span class="token comment">//=> ?size=M&colour=red&sleeves=short</span></code></pre>
<p>We can now that that <code>location.search</code> and pass it to the <code>URLSearchParams</code>
constructor:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> params <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span>location<span class="token punctuation">.</span>search<span class="token punctuation">)</span></code></pre>
<h3>Querying for parameters</h3>
<p>We can use <code>has</code> to see if a particular query param is present:</p>
<pre class="language-js"><code class="language-js">params<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span><span class="token string">'size'</span><span class="token punctuation">)</span> <span class="token comment">// => true</span><br>params<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span><span class="token string">'button-style'</span><span class="token punctuation">)</span> <span class="token comment">// => false</span></code></pre>
<p>If you want to read the values out of a query parameter, you can use <code>get</code>. If
no query parameter exists, you'll get <code>null</code> back.</p>
<pre class="language-js"><code class="language-js">params<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'size'</span><span class="token punctuation">)</span> <span class="token comment">// => 'M'</span><br>params<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'button-style'</span><span class="token punctuation">)</span> <span class="token comment">// => null</span></code></pre>
<p>I often find rather than use <code>has</code> to check, and then <code>get</code> to fetch the value,
I can just use <code>get</code> and check that the value is not <code>null</code>.</p>
<h3><code>get</code> vs <code>getAll</code></h3>
<p>There's one gotcha with <code>get</code> that you need to be aware of. One of the
behaviours of query parameters is that they can have multiple values:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// URL: buy-shirts-here.com/filter?size=M&size=L</span></code></pre>
<p>This is a perfectly valid URL. When we pass that into <code>URLSearchParams</code>, it will
understand that <code>size</code> has multiple values. This is where the behaviour of <code>get</code>
is important: <code>get</code> will <em>only return the first value for the query parameter</em>.
If you want all of them, you need to use <code>getAll</code> which always returns an array:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// URL: buy-shirts-here.com/filter?size=M&size=L</span><br><span class="token keyword">const</span> params <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span>location<span class="token punctuation">.</span>search<span class="token punctuation">)</span><br>params<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'size'</span><span class="token punctuation">)</span> <span class="token comment">//=> 'M'</span><br>params<span class="token punctuation">.</span><span class="token function">getAll</span><span class="token punctuation">(</span><span class="token string">'size'</span><span class="token punctuation">)</span> <span class="token comment">//=> ['M', 'L']</span></code></pre>
<h3>Iterating on parameters</h3>
<p>You can iterate through all the parameters in a few different ways. The first if
using <code>for of</code>. Once again, be wary of parameters will multiple values, they
will appear twice!</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// URL: buy-shirts-here.com/filter?size=M&size=L&colour=red</span><br><span class="token keyword">const</span> params <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span>location<span class="token punctuation">.</span>search<span class="token punctuation">)</span><br><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> p <span class="token keyword">of</span> params<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span><br><span class="token punctuation">}</span><br><span class="token comment">// => ['size', 'M']</span><br><span class="token comment">// => ['size', 'L']</span><br><span class="token comment">// => ['colour', 'red']</span></code></pre>
<p>You can also use <code>.keys()</code> to get an iterator of all the keys in the params, or
<code>.values()</code> to get all the values:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// URL: buy-shirts-here.com/filter?size=M&size=L&colour=red</span><br><span class="token keyword">const</span> params <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span>location<span class="token punctuation">.</span>search<span class="token punctuation">)</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>params<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// => ['size', 'size', 'colour']</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>params<span class="token punctuation">.</span><span class="token function">values</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// => ['M', 'L', 'red']</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>params<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// => [['size', 'M'], ['size', 'L'], ['colour', 'red']]</span></code></pre>
<h3>Modifying parameters</h3>
<p>The first thing to note is that all these methods mutate the existing
<code>URLSearchParams</code> object, rather than return a new one.</p>
<p>You can use <code>.delete()</code> to delete a query parameter. Note that this deletes all
values of it, if it has multiple:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// URL: buy-shirts-here.com/filter?size=M&size=L&colour=red</span><br><span class="token keyword">const</span> params <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span>location<span class="token punctuation">.</span>search<span class="token punctuation">)</span><br>params<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token string">'size'</span><span class="token punctuation">)</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>params<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// => ['colour']</span></code></pre>
<p>We can use <code>.append()</code> to add a new key/value pair. If the value already exists,
<code>append</code> will append the new one on, as its name suggests:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// URL: buy-shirts-here.com/filter?size=M&colour=red</span><br><span class="token keyword">const</span> params <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span>location<span class="token punctuation">.</span>search<span class="token punctuation">)</span><br>params<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token string">'size'</span><span class="token punctuation">,</span> <span class="token string">'L'</span><span class="token punctuation">)</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>params<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// => ['size', 'size', 'colour']</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>params<span class="token punctuation">.</span><span class="token function">values</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// => ['M', 'L', 'red']</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>params<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// => [['size', 'M'], ['size', 'L'], ['colour', 'red']]</span></code></pre>
<p>If you want to set a new value for the parameter and remove all other existing
values, you can use <code>.set</code> to do just that:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// URL: buy-shirts-here.com/filter?size=M&colour=red</span><br><span class="token keyword">const</span> params <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span>location<span class="token punctuation">.</span>search<span class="token punctuation">)</span><br>params<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'size'</span><span class="token punctuation">,</span> <span class="token string">'L'</span><span class="token punctuation">)</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>params<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// => ['size', 'colour']</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>params<span class="token punctuation">.</span><span class="token function">values</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// => ['L', 'red']</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>params<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token comment">// => [['size', 'L'], ['colour', 'red']]</span></code></pre>
<h3>Getting the URL back out</h3>
<p>After you've done all this reading and updating of query parameters, you'll
probably want to pull it back out as a URL so you can update the URL in the
browser. To do this, just call <code>.toString()</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// URL: buy-shirts-here.com/filter?size=M&colour=red</span><br><span class="token keyword">const</span> params <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">URLSearchParams</span><span class="token punctuation">(</span>location<span class="token punctuation">.</span>search<span class="token punctuation">)</span><br>params<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'size'</span><span class="token punctuation">,</span> <span class="token string">'L'</span><span class="token punctuation">)</span><br>params<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token string">'colour'</span><span class="token punctuation">)</span><br>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>params<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// => 'size=L'</span></code></pre>
<p>Note that <code>toString</code> does not add the <code>?</code> at the beginning, so make sure you
remember to add that if you need it.</p>
<h2>Conclusion</h2>
<p><code>URLSearchParams</code> is a great API that you can use to clearly update your query
parameters without having to worry about any additional libraries to parse query
params, or to convert them back into a string at the end. I highly recommend
using it next time you need to do some query parameter parsing or updating, and
with it being very well supported in most browsers alongside many polyfills
being available, I don't see a good reason to not use it in your next project!</p>
React in Five: a new video course to level up your React2018-08-14T00:00:00+00:00http://www.jackfranklin.co.uk/blog/react-in-five-release/<p>Today I'm releasing my brand new video series titled "React in Five"</p>
<p>I've been working with, writing tutorials, and speaking about React for a few
years now and something that I get asked fairly often is how to improve as a
React developer.</p>
<p>The first answer is to spend time building React applications, but often people
will miss out on the small tricks, tips, or lesser known parts of React that can
make a big difference. That's what this course is all about. Every video is
<em>less than five minutes long</em> and covers a small part of React that you may or
may not have come across, but will have an impact on how you build React
applications.</p>
<p>The series is made up of ten videos, purposefully designed to be easily
watchable on a commute, on a quick break from work or when you've got a spare
five minutes over a weekend. The first four videos in the series are free and
you can purchase the rest for $20.</p>
<p>PS: if you purchased the testing course, or you're subscribed to the mailing
list, keep an eye out for a little discount code heading your way.</p>
<p>By purchasing the videos you'll also get access to all the source code, any
updates over time and the ability to email me with questions about the course.</p>
<p>If this sounds interesting, you can watch the first video below, and head to the
<a href="http://www.jackfranklin.co.uk/react-in-five">React in Five course page</a> for the rest of the videos and to
buy the full package.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/8gwpTaCDDzg" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen=""></iframe>
Testing React with Kent C. Dodds2018-09-17T00:00:00+00:00http://www.jackfranklin.co.uk/blog/testing-react-with-kent-c-dodds/<p>I'm sure that <a href="http://twitter.com/kentcdodds">Kent</a> needs no introduction, he's a prolific contributor to the React community and ecosystem. One of the things he talks a lot about is testing, which just so happens to be one of my favourite topics, too!</p>
<p>In this hour long hangout, Kent and I compared our approaches, both where they align and where we have slightly different opinions. If you're interested in hearing a deep dive on how to test React applications, this should really help. We mention different approaches, libraries and resources that have helped us get started with and improve our respective testing philosophies.</p>
<p>Don't forget, if you are after some more testing resources, that my <a href="https://javascriptplayground.com/testing-react-enzyme-jest/">Testing React with Enzyme and Jest</a> course is available now!</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/z4DNlVlOfjU" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen=""></iframe>
Black Friday sale on my React video courses2018-11-22T00:00:00+00:00http://www.jackfranklin.co.uk/blog/black-friday-react-sale/<p>In the past year I've launched two video courses on React, and today I'm offering 40% off them over the Black Friday period.</p>
<p>You can use the coupon code <code>JACKFRIDAY</code> to take 40% off, and it works on both courses.</p>
<ul>
<li><a href="http://www.jackfranklin.co.uk/react-in-five">Buy React in Five here</a></li>
<li>Or <a href="http://www.jackfranklin.co.uk/testing-react-enzyme-jest">Testing React with Enzyme and Jest here</a></li>
</ul>
<p>Buying the courses not only gets you access to the current content, but any updates to them forever, and I assure you that there's updates planned in the near future, with some more testing content on its way.</p>
Adventures with ReasonML2019-01-23T00:00:00+00:00http://www.jackfranklin.co.uk/blog/adventures-with-reasonml/<p>If you follow me on Twitter, or have read this blog for a while, you'll probably
know that I'm a big fan of <a href="https://elm-lang.org/">Elm</a>. It's a functional,
strictly typed language that compiles to JavaScript and is a great alternative
to JavaScript for building web applications.</p>
<p>That said, it's not the only contender in this space.
<a href="https://reasonml.github.io/">Reason</a> is also a very popular option that has
gained a lot of traction recently. I've always been interested in trying it out,
and <a href="https://adventofcode.com/">Advent of Code</a>, a series of coding challenges
posted each day leading up to Christmas, gave me a great excuse.</p>
<blockquote>
<p>If you're into Elm, you might also be interested to know that I've done two
videos completing Advent of Code challenges in Elm that you can find
<a href="https://www.youtube.com/watch?v=pF8gSF5QlP8">on Youtube</a>.</p>
</blockquote>
<p>If you're eager to skip ahead into the code, you can
<a href="https://github.com/jackfranklin/advent-of-code-2018/tree/master/day-two-reason-ml">find it all on GitHub</a>.
In the rest of this post I'll talk you through my approach to getting up and
running with Reason, and my thoughts on the language after trying it. I am <em>not</em>
a Reason expert, so if you spot any errors or things I've misunderstood, please
let me know! Equally, there might be better ways of solving the task, so if you
have any suggestions please get in touch.</p>
<p>The first part of this blog post talks through my approach and how I solved the
problem, and then we end with a list of my good and bad parts of trying Reason.</p>
<h2>Getting started</h2>
<p>I followed the official
<a href="https://reasonml.github.io/docs/en/installation">Installation and getting started</a>
guide to get easily up and running. It involved installing the compiler,
<a href="https://bucklescript.github.io/">BuckleScript</a>, which is what takes Reason and
produces JavaScript.</p>
<p>That let me run:</p>
<pre><code>bsb -init my-new-project -theme basic-reason
</code></pre>
<p>To get a basic project up and running! I also installed
<a href="https://marketplace.visualstudio.com/items?itemName=jaredly.reason-vscode">reason-vscode</a>
so that I had nice error highlighting and type hinting as I coded. I find this
particularly useful when working with a new language/framework that I'm not
super familiar with.</p>
<h2>Writing tests</h2>
<p>I didn't want to build a UI to solve the Advent of Code problem; so I did a bit
of googling to see if I could use Reason to write some unit tests, and solve the
problem in a TDD style. I managed to find
<a href="https://github.com/glennsl/bs-jest">bs-jest</a>, a library that adds bindings to
BuckleScript to the JS testing framework Jest. This lets us write Reason, but
have it compiled into JavaScript that we can then run with Jest as normal. So
we'll write a <code>tests.re</code> file, have it compiled into <code>tests.js</code>, and then run
<code>jest tests.js</code>. Setting this up was just a case of following the instructions
in the README, and it worked perfectly.</p>
<h2>The Advent of Code challenge</h2>
<p>I was taking on <a href="https://adventofcode.com/2018/day/2">Day Two</a>, and for this
exercise only completed Part One. I'll leave Part Two as an exercise for you!</p>
<p>The first part of the exercise needed me to take a string, such as <code>bababc</code>, and
calculate the frequencies that letters occur. So for this string, we'd end up
with:</p>
<pre><code>{ a: 2, b: 3, c: 1 }
</code></pre>
<p>So that was the first thing I set out to write. I discovered that BuckleScript
provides a
<a href="https://bucklescript.github.io/bucklescript/api/Js.Dict.html"><code>Js.Dict</code></a> module
that is the equivalent of a native JS object, and I could use that. It also
provides
<a href="https://bucklescript.github.io/bucklescript/api/Js.Array.html"><code>Js.Array</code></a>, and
<a href="https://bucklescript.github.io/bucklescript/api/Js.String.html"><code>Js.String</code></a>.
Using a combination of methods from these modules, I could split my input, and
loop over it, updating a dict with new frequencies as I go through each letter.</p>
<p>I decided to store the frequencies in a dictionary. In Reason you have to decide
what the types of the values are in a dictionary, so I went with integers, given
we're counting frequencies.</p>
<p>I first set out to write a function that could take a dictionary and a letter,
and update the frequency for that letter:</p>
<ul>
<li>If the letter has no entry in the dictionary, create one and set the frequency
to one.</li>
<li>If the letter has a frequency, update the count by one.</li>
</ul>
<p>Defining this function looks very similar to JavaScript:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">let</span> incrementOrSetFrequency <span class="token operator">=</span><br> <span class="token punctuation">(</span>frequencies<span class="token punctuation">:</span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>t<span class="token punctuation">(</span>int<span class="token punctuation">)</span><span class="token punctuation">,</span> letter<span class="token punctuation">:</span> string<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>t<span class="token punctuation">(</span>int<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>The bit that Reason adds is the type annotations. After each of the two
arguments, we declare the types. We don't have to do this - Reason will be able
to infer them for us - but I find it helps me work with code if I've documented
the type, and very rarely the compiler can infer a type slightly differently to
what you actually want it to be.</p>
<p>The type annotation above says that <code>frequencies</code> is a <code>Js.Dict.t(int)</code>, which
means a dictionary where each value is an <code>int</code> type. <code>letter</code> is a <code>string</code>.
After the arguments we have the return type, which is also a dict, as we want to
take the dict, update it, and then return it again.</p>
<p>The first thing we need to do is check to see if <code>letter</code> is in the dictionary,
and we can use <code>Js.Dict.get(frequencies, letter)</code> to do this. It doesn't return
the value or <code>undefined</code> though, like you would expect in JavaScript. Instead,
it returns something that's an <code>Option</code> type. This is Reason's way of trying to
avoid unexpected <code>undefined</code> or <code>null</code>s in your application. You can read more
about
<a href="https://reasonml.github.io/docs/en/null-undefined-option"><code>Option</code> on the Reason docs</a>.</p>
<p>When you have a function that returns an <code>Option</code> type, you can use
<a href="https://reasonml.github.io/docs/en/pattern-matching">pattern matching</a> to see
what the value is, and act accordingly. So if we look in our dictionary for our
letter and it returns <code>None</code>, we need to add the letter. If it returns
<code>Some(int)</code>, we want to increment it by one:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">let</span> incrementOrSetFrequency <span class="token operator">=</span><br> <span class="token punctuation">(</span>frequencies<span class="token punctuation">:</span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>t<span class="token punctuation">(</span>int<span class="token punctuation">)</span><span class="token punctuation">,</span> letter<span class="token punctuation">:</span> string<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>t<span class="token punctuation">(</span>int<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">switch</span> <span class="token punctuation">(</span><span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>get<span class="token punctuation">(</span>frequencies<span class="token punctuation">,</span> letter<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token operator">|</span> <span class="token constructor">Some</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token operator">=></span><br> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>set<span class="token punctuation">(</span>frequencies<span class="token punctuation">,</span> letter<span class="token punctuation">,</span> x <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> frequencies<span class="token punctuation">;</span><br> <span class="token operator">|</span> <span class="token constructor">None</span> <span class="token operator">=></span><br> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>set<span class="token punctuation">(</span>frequencies<span class="token punctuation">,</span> letter<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> frequencies<span class="token punctuation">;</span><br> <span class="token punctuation">}</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<h2>Getting our first test passing</h2>
<p>At this point I decided I'd figured out enough Reason to be dangerous, and
wanted to write a test so I could work towards getting it passing. I created
<code>__tests__/daytwo_test.re</code>:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">open</span> <span class="token constructor">Jest</span><span class="token punctuation">;</span><br>describe<span class="token punctuation">(</span><span class="token string">"DayTwo"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">open</span> <span class="token constructor">Expect</span><span class="token punctuation">;</span><br> test<span class="token punctuation">(</span><span class="token string">"letterFrequencies"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span><br> expect<span class="token punctuation">(</span><span class="token class-name">DayTwo</span><span class="token punctuation">.</span>letterFrequencies<span class="token punctuation">(</span><span class="token string">"bababc"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token operator">|></span> toEqual<span class="token punctuation">(</span><span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>fromList<span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token string">"b"</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token string">"a"</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token string">"c"</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>If you've written JS tests with Jest, you'll probably find the above quite
intuitive, and I was able to use <code>Js.Dict.fromList</code> to take a list of tuples and
create the dictionary that I needed for the test. The compiler compiled this
into a JS file that I could run using the regular Jest CLI. This was one thing I
liked about Reason; I can use the regular Jest CLI, rather than having to use a
special one specifically for Reason. Jest's CLI is so good that it makes total
sense to work on top of it rather than creating a language specific one from
scratch.</p>
<p>To get the test passing we needed to take our input string, split it into a list
of letters, and run each one through our <code>incrementOrSetFrequency</code> function:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">let</span> letterFrequencies <span class="token operator">=</span> <span class="token punctuation">(</span>input<span class="token punctuation">:</span> string<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>t<span class="token punctuation">(</span>int<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">let</span> frequencies <span class="token operator">=</span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>empty<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> input<br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">String</span><span class="token punctuation">.</span>split<span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>reduce<span class="token punctuation">(</span><br> <span class="token punctuation">(</span>acc<span class="token punctuation">,</span> currentValue<span class="token punctuation">)</span> <span class="token operator">=></span> incrementOrSetFrequency<span class="token punctuation">(</span>acc<span class="token punctuation">,</span> currentValue<span class="token punctuation">)</span><span class="token punctuation">,</span><br> frequencies<span class="token punctuation">,</span><br> <span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>And with that the test is passing!</p>
<h2>Getting frequencies for our entire puzzle input</h2>
<p>Next we need to take our full puzzle input, which is a series of strings, and
run the above function on each of them, so we can start to work towards the
final answer that we need.</p>
<p>Once again, I start by writing a test. I replicate the input that the real
puzzle provides by putting each entry on its own line. I want to make sure we
get the logic for splitting lines works properly.</p>
<p>Note that <code>{|string here|}</code> allows us to define a multi-line string.</p>
<pre><code>test("checksum", () => {
let puzzleInput = {|
abcdef
bababc
abbcde
abcccd
aabcdd
abcdee
ababab
|};
expect(DayTwo.checksum(puzzleInput)) |> toEqual(12);
});
</code></pre>
<p>We can use the familiar <code>Js.String.split</code> once again here, but pass it <code>"\n"</code> as
the thing to split on. We then map the resulting lines over <code>String.trim</code>, which
trims any whitespace and removes it. Note that we're <em>not</em> using
<code>Js.String.trim</code> here, this is the
<a href="https://reasonml.github.io/api/String.html">ReasonML module <code>String</code></a>, <em>not</em>
the
<a href="https://reasonml.github.io/api/String.html">BuckleScript <code>Js.String</code> module</a>.
This was one of the things I found most confusing when learning Reason. It
wasn't clear why some of the functions we use are Reason modules, and others are
provided by BuckleScript.</p>
<blockquote>
<p>If you're familiar with Reason and can clarify the above confusion, I'd love
to talk it through and update the blog post to include it.</p>
</blockquote>
<p>So, the first part of the <code>checksum</code> function is to take the multi-line input,
split it, and then ensure that we don't have any blanks:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">let</span> checksum <span class="token operator">=</span> <span class="token punctuation">(</span>input<span class="token punctuation">:</span> string<span class="token punctuation">)</span><span class="token punctuation">:</span> int <span class="token operator">=></span> <span class="token punctuation">{</span><br> input<br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">String</span><span class="token punctuation">.</span>split<span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>map<span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span>trim<span class="token punctuation">)</span><br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>filter<span class="token punctuation">(</span>s <span class="token operator">=></span> <span class="token class-name">String</span><span class="token punctuation">.</span>length<span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><br> <span class="token comment">// note: this is invalid (we're not returning an int)</span></code></pre>
<p>Once I've split the lines and given them a trim, I then use <code>Js.Array.filter</code> to
remove any strings that are entirely empty. Now we are working with an array of
letter frequencies that looks something like this:</p>
<pre><code>[
"abcdef",
"bababc",
"abbcde",
"abcccd",
"aabcdd",
"abcdee",
"ababab",
]
</code></pre>
<p>So we want to take each one and pass it into the <code>letterFrequencies</code> function
that we have defined:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">let</span> checksum <span class="token operator">=</span> <span class="token punctuation">(</span>input<span class="token punctuation">:</span> string<span class="token punctuation">)</span><span class="token punctuation">:</span> int <span class="token operator">=></span> <span class="token punctuation">{</span><br> input<br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">String</span><span class="token punctuation">.</span>split<span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>map<span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span>trim<span class="token punctuation">)</span><br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>filter<span class="token punctuation">(</span>s <span class="token operator">=></span> <span class="token class-name">String</span><span class="token punctuation">.</span>length<span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>map<span class="token punctuation">(</span>letterFrequencies<span class="token punctuation">)</span><br> <span class="token comment">// note: this is invalid (we're not returning an int)</span></code></pre>
<p>Now we've turned that list of strings into a list of frequencies. This code
sample highlights one of my favourite Reason features (I'm biased as it's also a
favourite feature of mine from other functional languages like Elm and Elixir),
the pipeline operator. The pipeline operator takes the thing on the left and
passes it as the last argument to the function on the right. It means fewer
parentheses around everything and lends itself to creating really readable code.</p>
<h2>Calculating frequency occurrences</h2>
<p>Now we have a list of frequency dictionaries, we need to take them and figure
out:</p>
<ul>
<li>how many of them contain a letter exactly 3 times</li>
<li>how many of them contain a letter exactly 2 times</li>
</ul>
<p>The result for each of those is what we'll need to multiply together to get our
checksum, which is the solution to our puzzle.</p>
<p>What I'd like to do is take our list of frequencies and map it into a list of
Reason objects that contain two properties, <code>twice</code> and <code>thrice</code>. These will be
booleans and correspond to if a word contains a letter twice or thrice. To help
the compiler give me good type errors if I make a mistake, I create a custom
type:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">type</span> twiceAndThriceFrequency <span class="token operator">=</span> <span class="token punctuation">{</span><br> twice<span class="token punctuation">:</span> bool<span class="token punctuation">,</span><br> thrice<span class="token punctuation">:</span> bool<span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>This declares a type, <code>twiceAndThriceFrequency</code>, which is an object with two
properties that are both booleans. I can then create a function that will take a
frequencies dictionary and convert it into one of these objects. Now I have this
custom type, I can use it in the type annotation too:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">let</span> findTwicesAndThrices <span class="token operator">=</span> <span class="token punctuation">(</span>frequencies<span class="token punctuation">:</span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>t<span class="token punctuation">(</span>int<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span> twiceAndThriceFrequency <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token punctuation">{</span>twice<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> thrice<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>For now I've hardcoded the values to both be <code>true</code>, we will fill those in
shortly. Notice how having the custom type defined makes the type annotation
read really nicely and clearly.</p>
<p>To figure out the value of the <code>twice</code> and <code>thrice</code> keys, we need to see if the
frequencies dictionary has any values of <code>2</code> or <code>3</code> in it. For this problem, we
don't actually care about <em>which</em> letter occurs two or three times, we just need
to know if any of them do.</p>
<p>We can use <code>Js.Dict.values</code>, which takes a dictionary and returns an array of
the values inside it. It's just like <code>Object.values()</code> in JavaScript. We can
then use <code>Js.Array.some</code>, which takes an array and a function and tells us if
any items in the array satisfy it. Therefore, we can define the functions
<code>hasTwices</code> and <code>hasThrices</code> like so:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">let</span> hasTwices <span class="token operator">=</span> <span class="token punctuation">(</span>frequencies<span class="token punctuation">:</span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>t<span class="token punctuation">(</span>int<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span> bool <span class="token operator">=></span> <span class="token punctuation">{</span><br> frequencies <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>values <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>some<span class="token punctuation">(</span>v <span class="token operator">=></span> v <span class="token operator">===</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span><br><br><span class="token keyword">let</span> hasThrices <span class="token operator">=</span> <span class="token punctuation">(</span>frequencies<span class="token punctuation">:</span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>t<span class="token punctuation">(</span>int<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span> bool <span class="token operator">=></span> <span class="token punctuation">{</span><br> frequencies <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>values <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>some<span class="token punctuation">(</span>v <span class="token operator">=></span> v <span class="token operator">===</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<blockquote>
<p>Note that in this solution I'm not worrying about performance. If I was, we'd
be doing this differently to reduce the number of times we iterate over the
<code>frequencies</code> array. I'll leave it as an exercise to the reader to improve
that.</p>
</blockquote>
<h2>Mapping to our <code>twiceAndThriceFrequency</code> type</h2>
<p>Now we have these functions, we can define a function that will take a
frequencies dictionary and return a <code>twiceAndThriceFrequency</code> type:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">let</span> findTwicesAndThrices <span class="token operator">=</span> <span class="token punctuation">(</span>frequencies<span class="token punctuation">:</span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Dict</span><span class="token punctuation">.</span>t<span class="token punctuation">(</span>int<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span> twiceAndThriceFrequency <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token punctuation">{</span>twice<span class="token punctuation">:</span> hasTwices<span class="token punctuation">(</span>frequencies<span class="token punctuation">)</span><span class="token punctuation">,</span> thrice<span class="token punctuation">:</span> hasThrices<span class="token punctuation">(</span>frequencies<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">;</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<blockquote>
<p>Notice that we don't need the <code>return</code> keyword in Reason. The last expression
in a function is automatically returned for you.</p>
</blockquote>
<p>And once we have this function, we can update our main <code>checksum</code> function:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">let</span> checksum <span class="token operator">=</span> <span class="token punctuation">(</span>input<span class="token punctuation">:</span> string<span class="token punctuation">)</span><span class="token punctuation">:</span> int <span class="token operator">=></span> <span class="token punctuation">{</span><br> input<br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">String</span><span class="token punctuation">.</span>split<span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>map<span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span>trim<span class="token punctuation">)</span><br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>filter<span class="token punctuation">(</span>s <span class="token operator">=></span> <span class="token class-name">String</span><span class="token punctuation">.</span>length<span class="token punctuation">(</span>s<span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>map<span class="token punctuation">(</span>letterFrequencies<span class="token punctuation">)</span><br> <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>map<span class="token punctuation">(</span>findTwicesAndThrices<span class="token punctuation">)</span><br> <span class="token comment">// note: this is invalid (we're not returning an int)</span></code></pre>
<h2>Calculating our checksum</h2>
<p>At this point we are working with a list of objects that have
<code>{ twice: true/false, thrice: true/false }</code> within them. We want to go through
this list and reduce it down to two values: the number of times that we have a
letter occurring twice, and the number of times we have a letter occurring three
times. So if we have this list:</p>
<pre><code>[
{ twice: true, thrice: false },
{ twice: false, thrice: false },
{ twice: true, thrice: true },
]
</code></pre>
<p>We want to end up with:</p>
<pre><code>{ twice: 2, thrice: 1 }
</code></pre>
<p>It's then these two numbers that we multiply to find our checksum.</p>
<p>We can use <code>Js.Array.reduce</code> to do this. It will take our array and loop through
each value in turn, allowing us to check the values of <code>twice</code> and <code>thrice</code> and
increment our accumulator accordingly. Our starting accumulator will be an
object, which I also define a type for:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">type</span> twiceAndThriceCounter <span class="token operator">=</span> <span class="token punctuation">{</span><br> twice<span class="token punctuation">:</span> int<span class="token punctuation">,</span><br> thrice<span class="token punctuation">:</span> int<span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<p>And now we can start planning our <code>reduce</code> call:</p>
<pre class="language-reason"><code class="language-reason"><span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>reduce<span class="token punctuation">(</span><br> <span class="token punctuation">(</span>acc<span class="token punctuation">:</span> twiceAndThriceCounter<span class="token punctuation">,</span> currentValue<span class="token punctuation">:</span> twiceAndThriceFrequency<span class="token punctuation">)</span> <span class="token operator">=></span> acc<br> <span class="token punctuation">{</span>twice<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> thrice<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">)</span></code></pre>
<p>Inside the body of the callback function, we need to check the <code>currentValue</code>
and check the values of <code>twice</code> and <code>thrice</code>.</p>
<p>This is a case where Reason's
<a href="https://reasonml.github.io/docs/en/pattern-matching">pattern matching</a> comes in
really handy. We can write code that pattern matches against the object and its
values:</p>
<pre class="language-reason"><code class="language-reason"><span class="token keyword">switch</span> <span class="token punctuation">(</span>currentValue<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token operator">|</span> <span class="token punctuation">{</span>twice<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> thrice<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> twice<span class="token punctuation">:</span> acc<span class="token punctuation">.</span>twice <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span><br> thrice<span class="token punctuation">:</span> acc<span class="token punctuation">.</span>thrice <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br> <span class="token operator">|</span> <span class="token punctuation">{</span>twice<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> thrice<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">}</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> twice<span class="token punctuation">:</span> acc<span class="token punctuation">.</span>twice <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span><br> thrice<span class="token punctuation">:</span> acc<span class="token punctuation">.</span>thrice<span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br> <span class="token operator">|</span> <span class="token punctuation">{</span>twice<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> thrice<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> twice<span class="token punctuation">:</span> acc<span class="token punctuation">.</span>twice<span class="token punctuation">,</span><br> thrice<span class="token punctuation">:</span> acc<span class="token punctuation">.</span>thrice <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br> <span class="token operator">|</span> <span class="token punctuation">{</span>twice<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> thrice<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">}</span> <span class="token operator">=></span> acc<br><span class="token punctuation">}</span><span class="token punctuation">,</span></code></pre>
<p>Each case that we're matching against starts with the pipe (<code>|</code>) and then we
match against the <code>twice</code> and <code>thrice</code> values within <code>currentValue</code>. So the
first will match only if <code>currentValue</code> has both values set to true, in which
case we increment both of our counters. In the case of one of <code>twice</code> or
<code>thrice</code> being true, we increment the appropriate counter and if both values are
<code>false</code>, we do nothing.</p>
<p>Pattern matching is my favourite feature of Reason (it's also one of my
favourite parts of Elm), and it leads to some really nice, expressive code.
What's also nice is that if we don't write code that deals with every possible
case, we get a compiler error. In the example below, I've removed the case that
deals with both values being <code>true</code>. You can see the compiler spot this and tell
me:</p>
<pre class="language-reason"><code class="language-reason"> <span class="token constructor">Warning</span> number <span class="token number">8</span><br> <span class="token operator">/</span><span class="token constructor">Users</span><span class="token operator">/</span>jackfranklin<span class="token operator">/</span>git<span class="token operator">/</span>advent<span class="token operator">-</span><span class="token keyword">of</span><span class="token operator">-</span>code<span class="token operator">/</span>day<span class="token operator">-</span>two<span class="token operator">-</span>reason<span class="token operator">-</span>ml<span class="token operator">/</span>src<span class="token operator">/</span><span class="token class-name">DayTwo</span><span class="token punctuation">.</span>re <span class="token number">55</span><span class="token punctuation">:</span><span class="token number">10</span><span class="token operator">-</span><span class="token number">65</span><span class="token punctuation">:</span><span class="token number">10</span><br><br> <span class="token number">53</span> ┆ <span class="token operator">|></span> <span class="token class-name">Js</span><span class="token punctuation">.</span><span class="token class-name">Array</span><span class="token punctuation">.</span>reduce<span class="token punctuation">(</span><br> <span class="token number">54</span> ┆ <span class="token punctuation">(</span>acc<span class="token punctuation">:</span> twiceAndThriceCounter<span class="token punctuation">,</span> currentValue<span class="token punctuation">:</span> twiceAndThriceFrequenc<br> y<span class="token punctuation">)</span> <span class="token operator">=></span><br> <span class="token number">55</span> ┆ <span class="token keyword">switch</span> <span class="token punctuation">(</span>currentValue<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token number">56</span> ┆ <span class="token operator">|</span> <span class="token punctuation">{</span>twice<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> thrice<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">}</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token punctuation">.</span> ┆ <span class="token operator">...</span><br> <span class="token number">64</span> ┆ <span class="token operator">|</span> <span class="token punctuation">{</span>twice<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span> thrice<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">}</span> <span class="token operator">=></span> acc<br> <span class="token number">65</span> ┆ <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token number">66</span> ┆ <span class="token punctuation">{</span>twice<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> thrice<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token number">67</span> ┆ <span class="token punctuation">)</span><br><br> <span class="token constructor">You</span> forgot <span class="token keyword">to</span> handle a possible value here<span class="token punctuation">,</span> <span class="token keyword">for</span> example<span class="token punctuation">:</span><br><span class="token punctuation">{</span>twice<span class="token operator">=</span><span class="token boolean">true</span><span class="token punctuation">;</span> thrice<span class="token operator">=</span><span class="token boolean">true</span><span class="token punctuation">}</span></code></pre>
<p>This means you can never end up with code in production that doesn't deal with
all possible cases, which is fantastic. It also means if you refactor and now
your pattern matching is out of date, the compiler will tell you.</p>
<p>Once we have this reduce done, it's going to end up turning our array of
frequencies into one object with two values. The solution to the puzzle (and
what we need to get our test passing) is to take these values and multiply them.
We can do this by piping our object into an anonymous function that does just
this:</p>
<pre class="language-reason"><code class="language-reason"><span class="token operator">|></span> result <span class="token operator">=></span> result<span class="token punctuation">.</span>twice <span class="token operator">*</span> result<span class="token punctuation">.</span>thrice</code></pre>
<p>And with this, our tests are back to green!</p>
<pre><code> PASS __tests__/daytwo_test.bs.js
DayTwo
✓ letterFrequencies (6ms)
✓ checksum (1ms)
</code></pre>
<p>There's one small refactor we can make here though. Much like JavaScript and its
ES2015 destructuring, we can destructure an object into the keys when it's
passed into a function. So we can rewrite our final line as:</p>
<pre class="language-reason"><code class="language-reason"><span class="token operator">|></span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">{</span>twice<span class="token punctuation">,</span> thrice<span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=></span> twice <span class="token operator">*</span> thrice<span class="token punctuation">)</span></code></pre>
<p>Which I think reads a bit more clearly. And with that, our puzzle is solved!</p>
<h2>Conclusion</h2>
<p>This was literally the first time I'd written Reason and after finishing the
Advent of Code challenge I took a moment to think through what I found good, and
what I struggled with, from the perspective of a beginner using a new language.</p>
<p>It's also worth noting that my experience with Elm almost certainly makes it
easier for me to learn Reason, there are similarities between the two.</p>
<h2>Things I liked</h2>
<ul>
<li>The tight interopability between Reason and JavaScript is very compelling. I
could easily see myself writing one module in Reason in an existing JS
application because the interop is so smooth and easy.</li>
<li>Continuing from the previous point, the fact that Reason can use Jest for its
test runner is excellent. Not having to learn how to run another test runner
was a major bonus. It also helps that Jest is absolutely exceptional and packs
in a tonne of useful features, so it makes perfect sense that Reason would
lean on that rather than build out a brand new test runner.</li>
<li>On the whole I found compiler errors clear and obvious. One of my main gripes
with TypeScript is that some of the compiler messages were hard to parse, but
Reason gave me understandable messages that I really appreciated, particularly
as a beginner.</li>
<li>The documentation on the Reason site is excellent. Take
<a href="https://reasonml.github.io/docs/en/pattern-matching">this page on pattern matching</a>
as an example: it's clear, the code samples are easy to follow, and it
explains things thoroughly. It also avoids any complex jargon and doesn't
attempt to sound super clever.</li>
<li>This one is editor specific, but the
<a href="https://marketplace.visualstudio.com/items?itemName=jaredly.reason-vscode">reason-vscode</a>
plugin gives a really good developer experience. It was easy to quickly get
formatting, syntax highlighting, compiler errors and so on in my editor. (If
you use another editor, there are
<a href="https://reasonml.github.io/docs/en/editor-plugins">links to plugins on the Reason site</a>).</li>
<li>Reason includes <code>refmt</code>, a code formatter for Reason code. Much like Prettier
for JavaScript, this runs and formats your code. What's great about this is
that all Reason projects use this, so all Reason code is formatted the same,
and that as a beginner any worries about conventions or how to format
something are gone. I just run the formatter! The VSCode plugin runs this for
me when I save, so I just didn't have to think about it.</li>
</ul>
<h2>Things I found confusing</h2>
<blockquote>
<p>Please remember that I am writing this as a Reason beginner, not an authority!
If I've misunderstood something or made a mistake, please let me know and I'd
be happy to update the blog post and give credit accordingly.</p>
</blockquote>
<ul>
<li>I've struggled in my head to fully understand the iteraction between Reason,
OCaml and BuckleScript. In my head Reason is a syntax on top of OCaml, and
BuckleScript is the compiler that can produce JavaScript. I'm not sure if my
mental model stacks up though, and I found it hard to get clarity on this
online. <em>Update!</em>: <a href="https://twitter.com/rauschma">Axel</a> was kind enough to
share
<a href="http://reasonmlhub.com/exploring-reasonml/ch_about-reasonml.html">this diagram</a>
which I think makes things clearer and provides a nice picture.</li>
<li>I also found it confusing where to look for documentation for available
modules. For example, when wanting to split a string, I found the
<a href="https://reasonml.github.io/api/Str.html">Str</a> Reason module. However, this
isn't available when compiling with BuckleScript, so I ended up using the docs
from the BuckleScript API for
<a href="https://bucklescript.github.io/bucklescript/api/Js.String.html">Js.String</a>.
After this I was confused as to which one I should use, and why some modules
exist in BuckleScript, but others in Reason. This is still a big point of
confusion for me - if you can help me understand it I'd love to chat and also
update this blog post!</li>
<li>I think this is me being strongly biased based on my Elm experience, but I
didn't love that methods like
<a href="https://reasonml.github.io/api/Array.html">Array.get</a> may raise an exception
if the item at the given index isn't present. I think here I'm projecting my
expectations from Elm onto Reason, and actually the approach Reason has taken
probably is an easier entry point for JS programmers, but I'd rather they all
return the <code>Option</code> type, which
<a href="https://reasonml.github.io/docs/en/null-undefined-option">Reason does support and use</a></li>
</ul>
<p>All in all, I'd really recommend giving Reason a go! I'm excited to see where
the language and ecosystem goes in 2019 and beyond, and I'll definitely be
playing with it some more, maybe next time on an actual frontend project, rather
than just a coding exercise.</p>
Configuring ESLint on a TypeScript project2019-01-28T00:00:00+00:00http://www.jackfranklin.co.uk/blog/typescript-eslint/<p>Whenever I've used TypeScript in the past, I've set up
<a href="https://palantir.github.io/tslint/">TSLint</a> as my linting tool of choice.
However, I've always wished I could use <a href="https://eslint.org/">ESLint</a> instead,
for a few reasons:</p>
<ol>
<li>I am more familiar with ESLint, and I know its rules better and have my
preferred set of plugins.</li>
<li>All the JS projects I work on use ESLint, so having all my projects use the
same linter is beneficial.</li>
<li>I already have an ESLint plugin in my editor, so I don't have to configure
the TSLint plugin in addition.</li>
</ol>
<p>I was therefore thrilled to read a
<a href="https://eslint.org/blog/2019/01/future-typescript-eslint">post on the ESLint blog</a>
about the future of TypeScript and ESLint, with the
<a href="https://github.com/Microsoft/TypeScript/issues/29288">TypeScript 2019 roadmap</a>
mentioning them transitioning to ESLint and contributing to the project.</p>
<p>I had to set up a new frontend project this week and I decided to use TypeScript
and try ESLint for the first time. I thought it would be useful to document the
process to help others get started!</p>
<h2>Installing dependencies</h2>
<p>First up, we're going to need to install some packages. We'll install <code>eslint</code>
itself, but also two plugins we need to allow ESLint to lint TypeScript: a
parser (so ESLint can understand TypeScript's syntax) and the plugin (to enable
linting on TS files):</p>
<pre><code>yarn add --dev eslint
yarn add --dev @typescript-eslint/eslint-plugin
yarn add --dev @typescript-eslint/parser
</code></pre>
<h2>Configuring ESLint</h2>
<p>That gives us enough to set up ESLint. Let's create a <code>.eslintrc.js</code> file and
configure the parser and the plugin:</p>
<blockquote>
<p>I much prefer using <code>.eslintrc.js</code> over a JSON file, primarily because it lets
you leave comments in your configuration!</p>
</blockquote>
<pre class="language-js"><code class="language-js">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">parser</span><span class="token operator">:</span> <span class="token string">'@typescript-eslint/parser'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'@typescript-eslint'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span></code></pre>
<p>With that ESLint is all set up to run on TS files, but we haven't enabled any
rules! You can find all the
<a href="https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin/docs/rules">rules and documentation on GitHub</a>,
but I decided to enable the recommended set of rules that the plugin provides,
by using the <code>extends</code> configuration key:</p>
<pre class="language-js"><code class="language-js">module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">parser</span><span class="token operator">:</span> <span class="token string">'@typescript-eslint/parser'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'@typescript-eslint'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token keyword">extends</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'plugin:@typescript-eslint/recommended'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span></code></pre>
<blockquote>
<p>At the time of writing there isn't a website with these rules documented yet,
but I'm sure there will be soon, and I'll update this post when that happens.</p>
</blockquote>
<p>And with that, we're set! The beauty of this is that you can continue to use any
other ESLint configurations you like (for example, I always
<a href="https://prettier.io/docs/en/eslint.html">integrate Prettier into my ESLint setup</a>)
and now I can do that whilst also linting TypeScript, too!</p>
<h2>Enabling ESLint on TS files in VSCode</h2>
<p>One final note for all you VSCode users out there - by default the ESLint plugin
only runs on <code>javascript</code> and <code>javascriptreact</code> files. To tell it to run on TS
files, you need to update the <code>eslint.validate</code> setting to:</p>
<pre class="language-js"><code class="language-js"><span class="token string-property property">"eslint.validate"</span><span class="token operator">:</span> <span class="token punctuation">[</span><br> <span class="token string">"javascript"</span><span class="token punctuation">,</span><br> <span class="token string">"javascriptreact"</span><span class="token punctuation">,</span><br> <span class="token string">"typescript"</span><span class="token punctuation">,</span><br> <span class="token string">"typescriptreact"</span><br><span class="token punctuation">]</span></code></pre>
<p>And that will get you nice linting errors in your editor.</p>
Refactoring a component to use React hooks2019-02-20T00:00:00+00:00http://www.jackfranklin.co.uk/blog/refactoring-to-react-hooks/<p><a href="https://reactjs.org/blog/2019/02/06/react-v16.8.0.html">React 16.8</a> introduced
<a href="https://reactjs.org/docs/hooks-intro.html">hooks</a>; a new way to work with
effects and state in React. No longer do React components that have state need
to be ES2015 classes that extend <code>React.Component</code> - hooks let us write
components as functions and still have all the functionality of class based
components.</p>
<blockquote>
<p>It's important to note that React will continue to support class based
components for a long time yet. It's advised that you consider hooks going
forward, but there's no need to instigate a big migration of your code.</p>
</blockquote>
<p>I wanted to get familiar with hooks and try them on some real life code, and
this blog post is the result of doing that and writing down how I find it, and
comparing the before and after code. This is far from a deep dive into hooks,
but more a quick look at my first experience refactoring to use them. I hope you
find it useful!</p>
<blockquote>
<p>Although I've simplified the code for this example, I did really do this at
work first on a real component that we shipped!</p>
</blockquote>
<h2>The component we are working with.</h2>
<p>The component we're going to refactor takes an <code>id</code> as a prop, and makes a
request to an API to fetch data for the user with that given ID. Its <code>id</code> prop
can change at any time, so we also have to fetch the user data again if the ID
changes. Therefore we have <code>componentDidMount</code> and <code>componentDidUpdate</code> to deal
with the first render and any subsequent prop changes. The <code>render</code> for this
example just dumps the user data out, but in real life this would render a
meaningful UI.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> Component <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><br><br><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">class</span> <span class="token class-name">Demo</span> <span class="token keyword">extends</span> <span class="token class-name">Component</span> <span class="token punctuation">{</span><br> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><br><br> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">user</span><span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">componentDidMount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">fetchUser</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">user</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> user <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">componentDidUpdate</span><span class="token punctuation">(</span><span class="token parameter">prevProps</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>id <span class="token operator">!==</span> prevProps<span class="token punctuation">.</span>id<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">fetchUser</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">user</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> user <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>pre</span><span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>code</span><span class="token punctuation">></span></span><span class="token punctuation">{</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>state<span class="token punctuation">.</span>user<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>code</span><span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>pre</span><span class="token punctuation">></span></span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<blockquote>
<p>Don't worry about the definition of <code>fetchUser</code> - it's a small wrapper around
<code>fetch</code> that talks to our API.</p>
</blockquote>
<h2>Refactoring to hooks</h2>
<p>Let's start thinking about how we will refactor this to use hooks. There are two
hooks we're going to use:</p>
<ul>
<li><a href="https://reactjs.org/docs/hooks-state.html"><code>useState</code></a>, which lets us hold a
piece of state in our component. We'll use this to hold the <code>user</code> data that
we fetch from our API.</li>
<li><a href="https://reactjs.org/docs/hooks-effect.html"><code>useEffect</code></a>. This lets us run
<em>side effects</em> in our components. That is, things that happen as a result of a
React component being rendered. You can map this roughly onto the old React
lifecycle methods - in fact the documentation says just that:
<blockquote>
<p>If you’re familiar with React class lifecycle methods, you can think of
useEffect Hook as componentDidMount, componentDidUpdate, and
componentWillUnmount combined.</p>
</blockquote>
</li>
</ul>
<p>Because we're using hooks, we will also rewrite our component as a function. So
we can start with our shell:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react'</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">DemoWithHooks</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token punctuation">[</span>user<span class="token punctuation">,</span> setUser<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">undefined</span><span class="token punctuation">)</span><br><br> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// TODO</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>pre</span><span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>code</span><span class="token punctuation">></span></span><span class="token punctuation">{</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>user<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>code</span><span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>pre</span><span class="token punctuation">></span></span><br> <span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>When we call <code>useState</code> we get back an array with two items in. The first is the
actual value of the state, and the second is a function used to update that
value. You can call these whatever you'd like, although the <code>user</code> and <code>setUser</code>
style is becoming convention. We're using
<a href="http://www.jackfranklin.co.uk/es6-destructuring/">ES2015 destructuring</a> to keep the boilerplate down, but
you could write it as:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">const</span> userState <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">undefined</span><span class="token punctuation">)</span><br><span class="token keyword">const</span> user <span class="token operator">=</span> userState<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><br><span class="token keyword">const</span> setUser <span class="token operator">=</span> userState<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span></code></pre>
<p>The value passed to <code>useState</code> is the original value. This is needed for the
first render. Here I've explicitly passed in <code>undefined</code> so it's clear that when
this component runs we don't have a user yet. To get a user, we need to move on
to the <code>useEffect</code> hook.</p>
<h2><code>useEffect</code></h2>
<p><code>useEffect</code> takes a function and runs it when the component renders. This means
it will run both when the component first mounts, <em>and</em> when the component is
re-rendered. Don't worry though, we are able to have control over exactly when
it is executed, and we'll see that shortly.</p>
<p>Let's fill our <code>useEffect</code> call in with a function that fetches our user and
updates the state. Note that we call <code>setUser</code> from within <code>useEffect</code>. This is
common if you've got some state that you're setting by making an HTTP request.</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">fetchUser</span><span class="token punctuation">(</span>props<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>setUser<span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>When used in this manner, the function given to <code>useEffect</code> will be called:</p>
<ul>
<li>when the component first renders</li>
<li>anytime the component is subsequently rendered</li>
</ul>
<p>As it happens, for our component this is OK, because we only have one prop that
could cause an update - <code>id</code>. And every time that property changes, we do want
to fetch the user's data again.</p>
<p>But, what if this component took many props, or had other bits of state? In that
case, whenever any of those props changed, and the component was rendered again,
our <code>fetchUser</code> code would run. It would do this even if <code>props.id</code> hadn't
changed, and that's just a wasted network request if we already have the data
for that user.</p>
<p>In a class based component we would tackle this by adding a conditional to our
<code>componentDidUpdate</code> code:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token function">componentDidUpdate</span><span class="token punctuation">(</span><span class="token parameter">prevProps</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>id <span class="token operator">!==</span> prevProps<span class="token punctuation">.</span>id<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">fetchUser</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">user</span> <span class="token operator">=></span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setState</span><span class="token punctuation">(</span><span class="token punctuation">{</span> user <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>This ensures we only make the network request when the data we care about has
changed. We can do the same with <code>useEffect</code> by passing a second argument which
is an array of data that has to change for the effect to rerun:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token function">useEffect</span><span class="token punctuation">(</span><br> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">fetchUser</span><span class="token punctuation">(</span>props<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>setUser<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">[</span>props<span class="token punctuation">.</span>id<span class="token punctuation">]</span><br><span class="token punctuation">)</span></code></pre>
<p>Now our effect will run on first render, and also whenever <code>props.id</code> changes.
If any other data changes, it won't trigger the effect.</p>
<h2>The final component</h2>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">const</span> <span class="token function-variable function">DemoWithHooks</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token punctuation">[</span>user<span class="token punctuation">,</span> setUser<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">undefined</span><span class="token punctuation">)</span><br><br> <span class="token function">useEffect</span><span class="token punctuation">(</span><br> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">fetchUser</span><span class="token punctuation">(</span>props<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>setUser<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">[</span>props<span class="token punctuation">.</span>id<span class="token punctuation">]</span><br> <span class="token punctuation">)</span><br><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>pre</span><span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>code</span><span class="token punctuation">></span></span><span class="token punctuation">{</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>user<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>code</span><span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>pre</span><span class="token punctuation">></span></span><br> <span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>If you compare the code above to the starting component at the top of the post,
I think it's much cleaner. The first component has some near-duplicated code in
the <code>componentDidMount</code> and <code>componentDidUpdate</code>, which is entirely removed as
<code>useEffect</code> lets us express everything in one function. We also avoid the
awkward comparison of props in <code>componentDidUpdate</code>; something that's easy to
get subtly wrong, especially in complex components, and cause bugs or pointless
network requests. <code>useEffect</code> lets us define the effect and what should cause it
to rerun really concisely.</p>
<p>If you're using hooks, I also recommend the
<a href="https://www.npmjs.com/package/eslint-plugin-react-hooks">eslint-plugin-react-hooks</a>
package, which will give you handy linter errors or warnings for some common
mistakes when using hooks. I've been finding it particularly useful for catching
things I get slightly wrong as I adjust to using hooks over class based
components.</p>
<p>If you're not sure where to start with hooks in your codebase, I'd really
recommend this approach of picking one straightforward component and refactoring
it. It's low risk, and a component with just one or two pieces of local state
shouldn't take long to refactor. It's a great learning exercise and a good way
of sharing knowledge of hooks across your team.</p>
The perfect unit test2019-04-12T00:00:00+00:00http://www.jackfranklin.co.uk/blog/the-perfect-javascript-unit-test/<p>There's a common theme I find with people who tell me that they don't find unit
testing useful, and it's normally that they are writing bad tests. This is
completely understandable, particularly if you're newer to unit testing. It's
<em>hard</em> to write good tests and it takes practice to get there. All the things
we're going to talk about today were learned the hard way; the pain of bad unit
tests lead me to creating my own rules for how to write a good unit test. It's
these rules that we're going to talk about today.</p>
<h2>Why are bad tests so bad?</h2>
<p>When you have application code that is messy, it's hard to work with. But
hopefully you have some tests alongside it, and those help you. It's OK to work
with hard code if you've got tests backing you up. That confidence tests give
you can go along way to erasing the effect of bad code.</p>
<p>Bad tests don't have any code to help you work with them. You don't write tests
for your tests. You <em>could</em>, but then you'd have to write tests for your tests
for your tests and that's a spiral none of us want to go down...</p>
<h2>Characteristics of bad tests</h2>
<p>It's hard to define a set of traits that make a bad test, because a bad test is
really any test that doesn't follow the rules we're about to talk about.</p>
<p>If you've ever looked at a test and had no idea what it's testing, or you can't
obviously spot the assertion, that's a bad test. A test with a poorly written
description (<code>it('works')</code> is a personal favourite) is a bad test.</p>
<p>Tests are bad if <em>you don't find them useful</em>. The <em>entire point</em> of having
tests is to increase your productivity, workflow and confidence in your
codebase. If a test isn't doing that (or actively making it worse), it's a bad
test.</p>
<p>I firmly believe that bad tests <em>are worse</em> than no tests.</p>
<h2>A good test starts with a good name</h2>
<p>The good news is that the rules of a good test are easy to remember and very
intuitive once you've got used to them!</p>
<p>A good test has a <em>succinct, descriptive name</em>. If you can't come up with a
short name, prefer clarity over saving on line length.</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'filters products based on the query-string filters'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>You should be able to know just from the description what a test's purpose is
for. You'll sometimes see people name <code>it</code> tests based on the method it tests
instead:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'#filterProductsByQueryString'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>But this doesn't help - imagine being new to this code and trying to figure out
exactly what the function does. In this case the name is pretty descriptive, but
an actual human readable string is always better if you can come up with one.</p>
<p>Another guide line for naming tests is to ensure you can read the sentence with
the <code>it</code> at the beginning. So if I'm reading the test below, in my head I read
one big sentence:</p>
<blockquote>
<p>"it filters products based on the query-string filters"</p>
</blockquote>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'filters products based on the query-string filters'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>Tests that don't do this, even if the string is descriptive, feel clunky:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'the query-string is used to filter products'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<h2>The three parts of a good test</h2>
<p>Once you've got your test named well it's time to focus on the body. A good test
follows the same pattern every single time:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'filters products based on the query-string filters'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// STEP ONE: SETUP</span><br> <span class="token comment">// STEP TWO: INVOKE CODE</span><br> <span class="token comment">// STEP THREE: ASSERT</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>Let's go through each of those steps in turn.</p>
<h2>Setup</h2>
<p>The first stage of any unit test is the setup: this is where you get your test
data in order, or mock any functions that you might need to for this test to
run.</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'filters products based on the query-string filters'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// STEP ONE: SETUP</span><br> <span class="token keyword">const</span> queryString <span class="token operator">=</span> <span class="token string">'?brand=Nike&size=M'</span><br><br> <span class="token keyword">const</span> products <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Nike'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'L'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'sweater'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Adidas'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'tracksuit'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Nike'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'t-shirt'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">]</span><br><br> <span class="token comment">// STEP TWO: INVOKE CODE</span><br> <span class="token comment">// STEP THREE: ASSERT</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>The set up should establish <em>everything you need</em> to perform the test. In this
case I'm creating the query string and the list of products that I'm going to
use to test against. Notice my choice of data for the products too: I've got
items that deliberately don't match the query string, along with one that does.
If I only had products that matched the query string, this test wouldn't prove
that the filtering works.</p>
<h2>Invoke code</h2>
<p>This step is normally the shortest: you should call the function that you need
to test. Your test data will have been created by the first step, so you should
just be passing variables into a function at this point.</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'filters products based on the query-string filters'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// STEP ONE: SETUP</span><br> <span class="token keyword">const</span> queryString <span class="token operator">=</span> <span class="token string">'?brand=Nike&size=M'</span><br><br> <span class="token keyword">const</span> products <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Nike'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'L'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'sweater'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Adidas'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'tracksuit'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Nike'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'t-shirt'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">]</span><br><br> <span class="token comment">// STEP TWO: INVOKE CODE</span><br> <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">filterProductsByQueryString</span><span class="token punctuation">(</span>products<span class="token punctuation">,</span> queryString<span class="token punctuation">)</span><br><br> <span class="token comment">// STEP THREE: ASSERT</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<blockquote>
<p>If the test data is very short, I might merge step one and two, but most of
the time I find the value in splitting the steps out very explicitly to be
worth the extra lines it takes up.</p>
</blockquote>
<h2>Assert</h2>
<p>This is the best step! It's where all your hard work pays off and we check that
what we're expecting to happen actually did.</p>
<p>I call this the assert step as we're making assertions, but these days I tend to
use Jest and it's <code>expect</code> function, so you could call this the "Expectation
Step" too if you wanted.</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'filters products based on the query-string filters'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// STEP ONE: SETUP</span><br> <span class="token keyword">const</span> queryString <span class="token operator">=</span> <span class="token string">'?brand=Nike&size=M'</span><br><br> <span class="token keyword">const</span> products <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Nike'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'L'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'sweater'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Adidas'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'tracksuit'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Nike'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'t-shirt'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">]</span><br><br> <span class="token comment">// STEP TWO: INVOKE CODE</span><br> <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">filterProductsByQueryString</span><span class="token punctuation">(</span>products<span class="token punctuation">,</span> queryString<span class="token punctuation">)</span><br><br> <span class="token comment">// STEP THREE: ASSERT</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Nike'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'t-shirt'</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>And with that, we have a perfect unit test:</p>
<ol>
<li>It has a descriptive name that reads clearly and is succinct.</li>
<li>It has a clear setup phase where we construct test data.</li>
<li>The invoking step is limited to simply calling our function with our test
data.</li>
<li>Our assertion is clear and demonstrates the behaviour we're testing clearly.</li>
</ol>
<h2>Small improvements</h2>
<p>Whilst I wouldn't actually include the <code>// STEP ONE: SETUP</code> comments in my real
tests, I do find it useful to put a blank line between all three parts. So if
this test was in my codebase for real, it would look like this:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'filters products based on the query-string filters'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> queryString <span class="token operator">=</span> <span class="token string">'?brand=Nike&size=M'</span><br> <span class="token keyword">const</span> products <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Nike'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'L'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'sweater'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Adidas'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'tracksuit'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Nike'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'t-shirt'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">]</span><br><br> <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">filterProductsByQueryString</span><span class="token punctuation">(</span>products<span class="token punctuation">,</span> queryString<span class="token punctuation">)</span><br><br> <span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Nike'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span><span class="token punctuation">,</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'t-shirt'</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>If we're building a system that has products in it, I'd look to create an easier
way to create these products. I created the
<a href="https://github.com/jackfranklin/test-data-bot">test-data-bot</a> library to do
exactly this. I won't dive into how it works, but it lets you easily create
<em>factories</em> to create test data. If we had that setup (the <code>README</code> has full
instructions) we could have this test like so:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'filters products based on the query-string filters'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> queryString <span class="token operator">=</span> <span class="token string">'?brand=Nike&size=M'</span><br> <span class="token keyword">const</span> productThatMatches <span class="token operator">=</span> <span class="token function">productFactory</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Nike'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> <span class="token keyword">const</span> products <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token function">productFactory</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Nike'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'L'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token function">productFactory</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">brand</span><span class="token operator">:</span> <span class="token string">'Adidas'</span><span class="token punctuation">,</span> <span class="token literal-property property">size</span><span class="token operator">:</span> <span class="token string">'M'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> productThatMatches<span class="token punctuation">,</span><br> <span class="token punctuation">]</span><br><br> <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">filterProductsByQueryString</span><span class="token punctuation">(</span>products<span class="token punctuation">,</span> queryString<span class="token punctuation">)</span><br><br> <span class="token function">expect</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token punctuation">[</span>productThatMatches<span class="token punctuation">]</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>By doing this we remove all the details of products that are irrelevant to this
test (notice how the <code>type</code> field is not present in our test now) and lets us
easily keep our test data in sync with the real data by updating our factory.</p>
<p>I also pull the product that I want to match out into its own constant so we can
reuse it in the assertion step. This avoids duplication and makes the test
clearer - having a piece of test data titled <code>productThatMatches</code> is a strong
hint that it's what we're expecting our function to return.</p>
<h2>Conclusion</h2>
<p>If you have these rules in mind whilst writing unit tests I'm confident that
you'll find your tests easier to work with and more useful in your development
workflow. Testing is just like anything else: it takes time and practice.
Remember the three steps: <code>setup</code>, <code>invoke</code>, <code>assert</code> and you'll be writing
perfect unit tests before you know it 👌.</p>
Hiding implementation details with React hooks2019-05-28T00:00:00+00:00http://www.jackfranklin.co.uk/blog/hiding-implementation-details-react-hooks/<p>It's fair to say that the
<a href="https://reactjs.org/blog/2019/02/06/react-v16.8.0.html">introduction of hooks in React 16.8</a>
has really changed how we build React components. They certainly take some
getting used to, but once the concept clicks in your head it becomes clear that
they are a superior mechanism for building complex components when compared to
the old lifecycle methods.</p>
<p>One area where hooks shines is in reusing code across components. Those of you
who have been doing React for a long time will remember mixins (if you don't
it's not a problem as they are now removed from React!), which attempted to
solve sharing functionality across two components. After that people tackled the
problem of code-reuse with
<a href="https://reactjs.org/docs/higher-order-components.html">Higher-Order Components</a>
and also <a href="https://reactjs.org/docs/render-props.html">Render Props</a>, but those
came with their own problems. I think that hooks are the best solution yet.</p>
<blockquote>
<p>Both Higher-Order Components and Render Props still have their place and use
cases and they are still good patterns to have in your toolbox.</p>
</blockquote>
<h2>Custom hooks can use hooks</h2>
<p>The real moment for me was realising two things:</p>
<ul>
<li>custom hooks are just JavaScript functions and nothing more</li>
<li>custom hooks can <em>call React hooks</em></li>
</ul>
<p>Suddenly, code reuse with hooks becomes as simple as <em>writing functions</em>. We've
all been doing this since we started programming; spotting some code that's
duplicated and wrapping it in a function. Custom hooks are just functions with a
convention that they start with the word <code>use</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">useCounter</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><br><br> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> id <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">setCount</span><span class="token punctuation">(</span><span class="token parameter">c</span> <span class="token operator">=></span> c <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><br><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> <span class="token keyword">return</span> count<br><span class="token punctuation">}</span></code></pre>
<blockquote>
<p>You can see this running <a href="https://codesandbox.io/s/f7552">on CodeSandbox</a>.</p>
</blockquote>
<p>Compare this to how you'd write a "regular" JS function:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">counter</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">let</span> count <span class="token operator">=</span> <span class="token number">0</span><br><br> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> count <span class="token operator">=</span> count <span class="token operator">+</span> <span class="token number">1</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">500</span><span class="token punctuation">)</span><br><br> <span class="token keyword">return</span> count<br><span class="token punctuation">}</span></code></pre>
<p>You can see that whilst the hook version contains some React specifics (namely
the <code>useState</code> and <code>useEffect</code> calls), the logic is largely the same.</p>
<h2>The benefits of hidden implementation details</h2>
<p>Until now in this post I've focused purely on the reuse benefits that hooks
provide. Continuing with the above example, now any component in our system can
easily use the <code>useCounter</code> hook and if we want to update that logic we can do
it in just one place. You can imagine this being a hook that provides logic for
user authentication, for example, rather than a slightly contrived blog post
demo.</p>
<p>There is another benefit to hooks (which also applies to JS functions): <em>hidden
implementation details</em>. The reason I think this is such a big benefit is
because when you're working on a codebase, you likely have a million things in
your head that you're thinking about. Say you're working on a component that
happens to use the <code>useCounter</code> hook, amongst other things, and this component
was written by your colleague. This is the first time you've worked with this
component so you're skimming the code to build up a picture in your head of what
it does. The beauty of seeing the <code>useCounter</code> hook is that <em>you do not have to
care or worry about how it works</em>. You can tell from seeing this line:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> count <span class="token operator">=</span> <span class="token function">useCounter</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre>
<p>That it's going to give you a count, and from seeing it in the browser you'll
know that it increments. Compare that one line to the 10 lines above that
implement the <code>useCounter</code> hook. Reading the line that calls the hook is 10% of
the lines of code that the full hook implementation is, so you've just saved
yourself a bunch of space in your brain for something more important (and this
gap gets bigger with larger hooks).</p>
<p>The beauty of hooks is that they <em>let you lean on functionality without caring
about how it works</em>. Higher-Order Components and Render Props do this too, but
they introduce more ceremony and work to do it. Hooks are <em>just function calls</em>.</p>
<h2>When to extract a custom hook</h2>
<p>As always in programming, the rules aren't clearcut. My advice for creating
custom hooks would be to feel the pain first: until you have logic that's
<em>exactly</em> the same in <em>at least two components</em>, don't create a hook.
Pre-emptively creating one and trying to predict how you're going to use it is
probably going to leave you with an overcomplicated hook that doesn't do an
elegant job of solving your problems.</p>
Making unit tests fail when PropTypes error2019-06-03T00:00:00+00:00http://www.jackfranklin.co.uk/blog/failing-tests-on-react-proptypes/<p>PropTypes are a great way to document your components and I generally advise
that everyone do this fairly strictly. In fact, we have an ESLint rule that
ensures all PropTypes are declared.</p>
<blockquote>
<p>If you're using TypeScript/Flow, you don't need to be using PropTypes.</p>
</blockquote>
<p>I always appreciate a PropTypes warning in the browser; it normally makes me
aware of a mistake I've made way before I've noticed it myself and I'm confident
that over the years PropTypes have saved me a lot of time debugging.</p>
<h2>Missing PropType warnings in test runs</h2>
<p>When running our test suite with Jest, I noticed that I'd often miss the console
warnings that the PropTypes library emits if some tests fail, particularly if
I'm running multiple tests and so recently I set about trying to improve this. I
wanted to make the errors as obvious as possible, so you couldn't miss them.</p>
<p>For our test today we're using a <code>ProductPrice</code> component we have at work which
(you guessed it!) shows the price of an item to the user. IT also has some logic
to show the previous price crossed out, so users are shown if the item is on
sale.</p>
<p>Here's the test we'll be working with (we're using Enzyme for this test, but you
can use whichever library you'd like):</p>
<pre class="language-js"><code class="language-js"><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">'ProductPrice'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'Shows previous price'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> props <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">pricing</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">price</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">currency</span><span class="token operator">:</span> <span class="token string">'GBP'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">amount</span><span class="token operator">:</span> <span class="token number">4500</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token literal-property property">fullPrice</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">currency</span><span class="token operator">:</span> <span class="token string">'GBP'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">amount</span><span class="token operator">:</span> <span class="token number">5400</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br><br> <span class="token keyword">const</span> wrapper <span class="token operator">=</span> <span class="token function">mount</span><span class="token punctuation">(</span><br> <span class="token operator"><</span>ProductPrice <span class="token punctuation">{</span><span class="token operator">...</span>props<span class="token punctuation">}</span> priceMatchUrl<span class="token operator">=</span><span class="token string">"/price-match"</span> <span class="token operator">/</span><span class="token operator">></span><br> <span class="token punctuation">)</span><br><br> <span class="token function">expect</span><span class="token punctuation">(</span>wrapper<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token string">'strike'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">'£54'</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>Now let's deliberately break this test, by removing the <code>pricing.price</code> prop,
and see what the output looks like from Jest (I've removed some output to keep
this post a bit shorter!):</p>
<pre><code> FAIL frontend/components/product/price.test.jsx
● ProductPrice › Shows previous price
Method “text” is meant to be run on 1 node. 0 found instead.
29 | );
30 |
> 31 | expect(wrapper.find('strike').text()).toEqual('£54');
| ^
32 | });
33 | });
34 |
at ReactWrapper.single (../node_modules/enzyme/build/ShallowWrapper.js:1958:17)
console.error node_modules/prop-types/checkPropTypes.js:20
Warning: Failed prop type: The prop `pricing.price.currency` is marked as required in `ProductPrice`, but its value is `undefined`.
in ProductPrice
</code></pre>
<p>Notice that we do get the PropTypes warning appear, but it's right at the
bottom. It's easy to spot in this small example where I'm running a single test,
but normally I'm running a whole file as I'm building or editing something, and
if you have a few failures it can be hard to trace back the PropTypes warnings
to the specific test that caused them. The main bit of output that I'm drawn to
is the main test error:</p>
<pre><code>Method “text” is meant to be run on 1 node. 0 found instead.
</code></pre>
<p>And this isn't telling me too much; it tells me that <code>wrapper.find('strike')</code>
didn't succeed, but I don't know the root cause. I can go digging around, but if
this clearly told me I'd missed a PropType, that would give me a clear first
instruction that fixing the PropTypes would be a solid first step.</p>
<h2>Failing unit tests for PropTypes warnings</h2>
<p>By default a PropType warning, which is just a <code>console.error</code> call, will never
fail a test. But that's what I'd like it to do. I want to fail a test on a
PropType warning every time. Not only does it help with debugging, it also means
our PropTypes are being used and are up to date with the real props we're
passing.</p>
<p>To do this we can create a setup file that Jest will run before tests and use
Jest's spying mechanism to spy on <code>console.error</code> calls, and check for calls
that look like PropType errors:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> originalConsoleError <span class="token operator">=</span> global<span class="token punctuation">.</span>console<span class="token punctuation">.</span>error<br><br><span class="token function">beforeEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> global<span class="token punctuation">.</span>console<span class="token punctuation">.</span><span class="token function-variable function">error</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> propTypeFailures <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">Failed prop type</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">Warning: Received</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">]</span><br><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>propTypeFailures<span class="token punctuation">.</span><span class="token function">some</span><span class="token punctuation">(</span><span class="token parameter">p</span> <span class="token operator">=></span> p<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>args<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span>args<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">originalConsoleError</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>By swapping <code>global.console.error</code> for our own version we can track any calls.
If we find one that matches what we suspect is a PropType issue, we can
immediately throw an error. Throwing an error in a <code>beforeEach</code> will make Jest
fail that test, so this does the trick.</p>
<p>When we run the tests again, our output looks like this:</p>
<pre><code> FAIL frontend/components/product/price.test.jsx
ProductPrice
✕ Shows previous price (4ms)
● ProductPrice › Shows previous price
Warning: Failed prop type: The prop `pricing.price.currency` is marked as required in `ProductPrice`, but its value is `undefined`.
in ProductPrice
28 |
29 | if (propTypeFailures.some(p => p.test(args[0]))) {
> 30 | throw new Error(args[0]);
| ^
31 | }
32 |
33 | originalConsoleError(...args);
</code></pre>
<p>Whilst this isn't perfect (the stack trace for example is useless here), having
the warning front and centre right by the test failure makes it impossible to
miss. We can also go a bit further if we like by using
<a href="https://www.npmjs.com/package/chalk">Chalk</a> to add some bold, red highlighting
to the error:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>propTypeFailures<span class="token punctuation">.</span><span class="token function">some</span><span class="token punctuation">(</span><span class="token parameter">p</span> <span class="token operator">=></span> p<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>args<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><br> <span class="token punctuation">[</span>chalk<span class="token punctuation">.</span>red<span class="token punctuation">.</span><span class="token function">bold</span><span class="token punctuation">(</span><span class="token string">'PropTypes caused test failure:'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> chalk<span class="token punctuation">.</span><span class="token function">red</span><span class="token punctuation">(</span>args<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><br> <span class="token string">'\n'</span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<h2>Conclusion</h2>
<p>We've been very happy at work with this change; it's saved me from some
confusing debugging on multiple occasions. Regardless of if you want to do this
for your tests for PropTypes, I'd encourage you to look for ways that your test
output makes thing slightly less clear than it should be, and improve it.</p>
<p>Your tests are a tool for you and your team; if they are not working as well as
they could be for you a technique like the one we've used today for PropTypes
can be a great way to improve them.</p>
Converting a JS library to TypeScript: Part 12019-06-05T00:00:00+00:00http://www.jackfranklin.co.uk/blog/typescript-videos-test-data-bot/<p>I've been wanting a project to dive into to help me learn TypeScript, and the
other day on an issue for
<a href="https://github.com/jackfranklin/test-data-bot">test-data-bot</a>, someone asked if
TypeScript definitions were available. I decided this was a good way for me to
dive in and try converting a library to TS, and I decided to record it and share
for anyone else wondering what the process looks like!</p>
<p>Rather than create streamlined, snappy, short videos like I do for my paid
courses, these videos will be ~15 minutes long and show you a much less edited
version of how I work. You'll see how I use my editor, how I go about driving
code with tests and how I debug when I get stuck. I'm not a TypeScript expert,
so there's a fair amount of time spent figuring out TypeScript together!</p>
<p>You can watch it on YouTube, either by
<a href="https://www.youtube.com/watch?v=XdPltW0a-fg">clicking here to view it directly</a>
or using the embedded player below. I filmed the video in 1080p so it should be
crystal clear 👌.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/XdPltW0a-fg" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
Things I was wrong about when I started programming2019-06-10T00:00:00+00:00http://www.jackfranklin.co.uk/blog/things-i-was-wrong-about-javascript/<p>When I got my first job after university I was ready to get stuck in. Through
university and side projects I'd done a good amount of programming and thought
that I was more than ready for my full time career to start. Recently I've been
looking back and thinking that I definitely had some misconceptions, weird
approaches and inefficient ways of working. These are all things I wish I could
go back and tell myself - it would have saved a bunch of time having to learn
them the hard way!</p>
<p>I was inspired by a
<a href="https://monicalent.com/blog/2019/06/03/absolute-truths-unlearned-as-junior-developer/">post on a similar subject by Monica Lent</a>
and thought it would be a good idea to write these down to share them with you
all.</p>
<p>Although these are things I ended up changing my opinion on, I'm still happy
that I made these mistakes. The best way for me to learn is to see one strategy
fail, reflect on why, and do it differently next time. If you're starting out,
don't be afraid of making mistakes. They are a great way to learn and improve.</p>
<h2>1: Less code is not always better</h2>
<p>When I started coding I had some hard rules about what constituted "good" code.
One of those rules was conciseness: if I could fit the same functionality into
fewer lines, that was an improvement. I've drastically changed my mind on this,
partly because I'd find myself revisiting code I wrote six months prior that
turned out to be a nightmare to understand.</p>
<p>Typically I find code that's been squashed up is more complex, uses tricks that
aren't common knowledge, and is also very hard to change. Given that most of a
developer's job is changing code, this matters. I am now very eager to extend a
function's body by a line or two if I can introduce more clarity to the code to
help me and my teammates understand it.</p>
<h2>2: Work smarter, not harder</h2>
<p>I worked <em>way too many hours</em> in my first job. This wasn't the fault of the
company, it was solely my choice. I would work long into the night determined to
get that ticket finished before I went home. I then realised (and had feedback
from my manager) that I wasn't working smart; I was trying to take on a lot at
once, and ended up trying to do too many things and not focusing on any of them
fully. This would lead to all of them taking way longer than anticipated.</p>
<p>Once I was aware of this I was able to focus on doing fewer things well and
efficiently. I worked hard to get better at focusing in and being productive
during work hours so I got things done. I reduced my hours in the office by <em>a
lot</em> but actually increased my output at the same time!</p>
<h2>3: Some technical debt is OK</h2>
<p>I came out of university thinking that only bad developers could create
technical debt. That in the real world all companies with good developers had
this beautiful codebase full of code that's easy to understand and follow. <em>How
wrong I was!</em> At first I was intolerant of technical debt before learning that
every developer will be responsible for some during their career and that it's
an inevitable part of being an engineer.</p>
<p>I would come across "bad" code and immediately want to fix it or rewrite it. I
lost many hours doing just that. What I wasn't good at is <em>judging the impact</em>
of technical debt. Tech debt that's isolated to part of the codebase that
doesn't get touched much is fine, and you should just leave it there. Bad code
isn't bad code because it's written badly; it's bad code if it slows you down,
causes bugs for users, or constantly breaks. That's the code you need to fix.</p>
<h2>4: Bad code isn't always the original developer's fault</h2>
<p>This point is related to the one above; I would encounter bad code and my
immediate thought would be to lay the blame on the developer(s) who wrote it.
But this isn't fair; although when you come across bad code, it's easy to
<code>git blame</code> and hunt down the "culprit", it doesn't take into account the
<em>context in which the code was written</em>. Sure, that code might be bad, but:</p>
<ul>
<li>there might have been a must-hit deadline which meant the usual review process
was skipped. Granted, if this happens often this would be an issue, but we've
all had one-off deadlines that must be hit at all costs.</li>
<li>the code might have been introduced as an emergency stop gap to fix a critical
bug that was stopping users checking out, so quality was less important than
fixing it.</li>
<li>the code may have been written with future modifications in mind that never
happened due to other work getting prioritised</li>
<li>or the developer simply had an off day; I've come in to work and looked at
code I wrote the day before in disdain before, it happens! We're all human and
have off days.</li>
</ul>
<h2>5: Working is better than perfect</h2>
<p>Due to the aforementioned misconceptions of technical debt and how it exists in
a codebase, I was always worried about introducing it myself. So when asked to
build a new feature I'd spend far too long trying to build <em>the perfect
solution</em>. This is incredibly inefficient - when trying to solve a problem you
are constantly learning more about the problem as you solve it - so the first
attempt is nearly always not going to hit the mark. It's far better to <em>get
something functional</em> in place - and cover it with tests - before refactoring
and working towards a better solution.</p>
<p>It's also important to realise that <em>the perfect solution does not exist</em>. Any
solution will have pros and cons and the challenge we have as developers is
deciding on the best solution for the task at hand.</p>
<h2>6: Software development is all about tradeoffs</h2>
<p>I used to think that the best solution to a problem would have no problems. That
for every ticket or piece of work I was asked to do, I could solve it in a way
that had no negatives. Now I'm a bit older (and <em>maybe a tiny bit wiser</em>) I've
realised that there is no such thing as the perfect solution. The job of a
developer is to know what tradeoffs to make, because there are always going to
be tradeoffs. The best developers make the right tradeoffs that solve the
problems at hand and don't cause issues further down the line. <em>But</em> they can
only make those tradeoffs and foresee problems <em>because they've made the wrong
choice many times</em>. So don't fret if you've made a refactoring that you thought
was great, but ended up causing problems, or implemented a bug fix which caused
your colleague hours of grief down the road. <em>We all have!</em> The single most
important skill for a developer in my opinion is to be humble, willing to admit
that you made a mistake, but be eager to understand why your choice was wrong,
how you could have realised that sooner, and learn from it. If you do that
you'll be in a very good place.</p>
Converting a JS library to TypeScript: Part 22019-06-14T00:00:00+00:00http://www.jackfranklin.co.uk/blog/test-data-bot-in-typescript-part-2/<blockquote>
<p>If you missed part one, you can
<a href="http://www.jackfranklin.co.uk/typescript-videos-test-data-bot/">find it here</a>.</p>
</blockquote>
<p>Today we're implementing more of test-data-bot's API in TypeScript and diving
more into types, interfaces and figuring out how best to model our API through
TypeScript. I talk through the pros and cons and my thought process as we figure
out the right approach.</p>
<p>You can watch it on YouTube, either by
<a href="https://youtu.be/Nqbik4MYqfw">clicking here to view it directly</a> or using the
embedded player below. I filmed the video in 1080p so it should be crystal clear
👌.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Nqbik4MYqfw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
Avoiding recursive useEffect hooks in React2019-06-20T00:00:00+00:00http://www.jackfranklin.co.uk/blog/avoiding-recursive-use-effect-hooks-react/<p>It's fair to say that React 16.8 and the introduction of
<a href="https://reactjs.org/docs/hooks-intro.html">hooks</a> has really changed how we
write React. Hooks are one of those APIs that make you realise the flaws of the
previous approach <em>after</em> you stop using it. I remember being very skeptical of
hooks when they were first released, not thinking that the previous class based
design had many flaws, but I've since come to realise I was very wrong, and
hooks are a vast improvement on how we build React components. If you're
interested in comparing the old vs the new, I wrote a
<a href="http://www.jackfranklin.co.uk/refactoring-to-react-hooks/">blog post refactoring a component to use hooks</a>
that offers a nice comparison.</p>
<p>One area that has taken me some time to get used to is the dependency array of
the <code>useEffect</code> hook. This lets you tell React when it should rerun the effect:</p>
<pre class="language-js"><code class="language-js"><span class="token function">useEffect</span><span class="token punctuation">(</span><br> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'I run when `a` changes'</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">[</span>a<span class="token punctuation">]</span><br><span class="token punctuation">)</span></code></pre>
<p>This <code>useEffect</code> will be run:</p>
<ul>
<li>when the component is first mounted</li>
<li>whenever the variable <code>a</code> changes.</li>
</ul>
<p>But this lead me to quite often end up with recursive calls to <code>setEffect</code>,
where I'd need to rely on some state in order to update its value:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span> setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><br><br><span class="token comment">// this is going to go on forever</span><br><span class="token comment">// because the effect relies on the `count` variable</span><br><span class="token comment">// and then updates the `count` variable</span><br><span class="token comment">// which triggers the effect</span><br><span class="token comment">// and so on...</span><br><span class="token function">useEffect</span><span class="token punctuation">(</span><br> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">setCount</span><span class="token punctuation">(</span>count <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">[</span>count<span class="token punctuation">]</span><br><span class="token punctuation">)</span></code></pre>
<p>This is a contrived example for the purpose of demonstration, but I also had
bigger examples where we had an object in state with many keys and values, and
we needed to read in the object and update one part of it:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>userData<span class="token punctuation">,</span> setUserData<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">friends</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'alice'</span><span class="token punctuation">,</span> <span class="token string">'bob'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><br><br><span class="token comment">// also runs infinitely for the same reasons as above</span><br><span class="token function">useEffect</span><span class="token punctuation">(</span><br> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> newUser <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token operator">...</span>userData<span class="token punctuation">,</span><br> <span class="token literal-property property">friends</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token operator">...</span>userData<span class="token punctuation">.</span>friends<span class="token punctuation">,</span> <span class="token string">'charlie'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br><br> <span class="token function">setUserData</span><span class="token punctuation">(</span>newUser<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">[</span>userData<span class="token punctuation">]</span><br><span class="token punctuation">)</span></code></pre>
<p>The solution lies in how we call the set state functions (in the prior code
example, <code>setUserData</code> is the "set state" function). There are two forms to
these functions:</p>
<pre class="language-js"><code class="language-js"><span class="token function">setUserData</span><span class="token punctuation">(</span>newUser<span class="token punctuation">)</span><br><span class="token function">setUserData</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">oldUser</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> newUser <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><br> <span class="token keyword">return</span> newUser<br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>The first takes the new value and sets it. The second takes <em>a function that is
called with the old value</em> and is expected <em>to return the new value</em>. Let's take
the previous <code>useEffect</code> code example and update it to use the second form of
the set state function:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>userData<span class="token punctuation">,</span> setUserData<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">friends</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'alice'</span><span class="token punctuation">,</span> <span class="token string">'bob'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><br><br><span class="token comment">// doesn't run infinitely! 👌</span><br><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">setUserData</span><span class="token punctuation">(</span><span class="token parameter">oldUser</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> newUser <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token operator">...</span>oldUser<span class="token punctuation">,</span><br> <span class="token literal-property property">friends</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token operator">...</span>oldUser<span class="token punctuation">.</span>friends<span class="token punctuation">,</span> <span class="token string">'charlie'</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br> <span class="token keyword">return</span> newUser<br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre>
<p>Do you notice what's different here? We no longer have to depend on <code>userData</code>,
because we read it from the callback function that we give to the set state
function! This means that our <code>useEffect</code> call is free to modify and set the new
user data without fear of recursion because it reads the old value by being
given it via the set state function. Therefore we can lose it from our
<code>useEffect</code> dependencies array, meaning that <code>useEffect</code> won't rerun when it
changes!</p>
<p>My experience of this was that once I spotted this trick it made the <code>useEffect</code>
hook really click in my head. I've come to use the set state function variant
much more frequently - in fact, nearly exclusively inside <code>useEffect</code> calls, and
I recommend giving it a go.</p>
Converting a JS library to TypeScript: Part 32019-06-28T00:00:00+00:00http://www.jackfranklin.co.uk/blog/test-data-bot-in-typescript-part-3/<blockquote>
<p>If you missed the prior videos, you can find them here:
<a href="http://www.jackfranklin.co.uk/typescript-videos-test-data-bot/">Part 1</a> and
<a href="http://www.jackfranklin.co.uk/test-data-bot-in-typescript-part-2/">Part 2</a>.</p>
</blockquote>
<p>Today we're implementing more of test-data-bot's API in TypeScript and diving
into using 3rd party libraries, specifically the FakerJS library. We'll see how
best to think about and model types by recognising a situation where our first
typed approach has failed to provide clarity, and see how time thinking about
remodelling types really pays off.</p>
<p>You can watch it on YouTube, either by
<a href="https://www.youtube.com/watch?v=3uK52uLEjJs&feature=youtu.be">clicking here to view it directly</a>
or using the embedded player below. I filmed the video in 1080p so it should be
crystal clear 👌.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/3uK52uLEjJs" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
Structuring React applications2019-07-08T00:00:00+00:00http://www.jackfranklin.co.uk/blog/structuring-react-applications/<p>One of the best features of React is that it doesn't force much convention and
leaves a lot of decisions up to the developer. This is different from say,
EmberJS or Angular, which provide more out of the box for you, including
conventions on where and how different files and components should be named.</p>
<blockquote>
<p>My personal preference is the React approach as I like the control, but there
are many benefits to the Angular approach too. This comes down to what you and
your team prefer to be working with.</p>
</blockquote>
<p>Over the years I've been working with React I've tried many different ways of
structuring my applications. Some of these ideas turned out to be be better than
others, so in today's post I am going to share all the things that have worked
well for me and hopefully they will help you too.</p>
<blockquote>
<p>This is not written as the "one true way" to structure your apps: feel free to
take this and change it to suit you, or to disagree and stick to what you're
working with. Different teams building different applications will want to do
things differently.</p>
</blockquote>
<p>It's important to note that if you loaded up the
<a href="https://www.thread.com/">Thread</a> frontend, you would find places where all of
these rules are broken! Any "rules" in programming should be thought of as
guidelines - it's hard to create blanket rules that always make sense, and you
should have the confidence to stray from the rules if you think it's going to
improve the quality of what you're working on.</p>
<p>So, without further ado, here's all I have to say on structuring React
applications, in no particular order.</p>
<h2>Don't worry too much</h2>
<p>This might seem like an odd point to get started on but I genuinely mean it when
I say that I think the biggest mistake people make is to stress too much about
this. This is especially true if you're starting a new project: it's impossible
to know the best structure as you create your first <code>index.jsx</code> file. As it
grows you should naturally end up with some file structure which will probably
do the job just fine, and you can tweak it as pain points start to arise.</p>
<p>If you find yourself reading this post and thinking "but our app doesn't do any
of these!" that's <em>not a problem</em>! Each app is different, each team is
different, and you should work together to agree on a structure and approach
that makes sense and helps you be productive. Don't worry about changing
immediately how others are doing it, or what blog posts like this say is most
effective. My tactic has always been to have my own set of rules, but read posts
on how others are doing it and crib bits from it that I think are a good idea.
This means over time you improve your own approach but without any big bang
changes or reworks 👌.</p>
<h2>One folder per main component</h2>
<p>The approach I've landed on with folders and components is that components
considered to be the "main" components of our system (such as a <code><Product></code>
component for an e-commerce site) are placed in one folder called <code>components</code>:</p>
<pre><code>- src/
- components/
- product/
- product.jsx
- product-price.jsx
- navigation/
- navigation.jsx
- checkout-flow/
- checkout-flow.jsx
</code></pre>
<p>Any small components that are only used by that component live within the same
directory. This approach has worked well because it adds some folder structure
but not so much that you end up with a bunch of <code>../../../</code> in your imports as
you navigate. It makes the hierarchy of components clear: any with a folder
named after them are big, large parts of the system, and any others within exist
primarily to split that large component into pieces that make it easier to
maintain and work with.</p>
<blockquote>
<p>Whilst I do advocate for some folder structure, the most important thing is
that your files are well named. The folders are less important.</p>
</blockquote>
<h2>Nested folders for sub components if you prefer</h2>
<p>One downside of the above is that you can often end up with a large folder for
one of these big components. Take <code><Product></code> as an example: it will have CSS
files (more on those later), tests, many sub-components and probably other
assets like images, SVG icons, and more, all in the one folder.</p>
<p>I actually don't mind that, and find that as long as the file is named well and
is discoverable (mostly via the fuzzy finder in my editor), the folder structure
is less important.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">🔥 Hot take: Most people create way too many folders in their projects. Introducing 5 levels of nested folder structure makes things harder to find, not easier.<br><br>"Organizing" things doesn't actually make your code better or make you more productive 👀</p>— Adam Wathan (@adamwathan) <a href="https://twitter.com/adamwathan/status/1145109572081860610?ref_src=twsrc%5Etfw">June 29, 2019</a></blockquote> <script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>If you would like more structure though it's easy to simply move the
sub-components into their own respective folders:</p>
<pre><code>- src/
- components/
- product/
- product.jsx
- ...
- product-price/
- product-price.jsx
</code></pre>
<h2>Tests alongside source code</h2>
<p>Let's start the points with an easy one: keep your test files next to your
source files. I'll dive into more detail on how I like to structure all my
components so their code is next to each other, but I've found my preference on
tests is to name them identically to the source code, in the same folder, but
with a <code>.test</code> suffix:</p>
<ul>
<li><code>auth.js</code></li>
<li><code>auth.test.js</code></li>
</ul>
<p>The main benefits of this approach are:</p>
<ul>
<li>it's easy to find the test file, and easy at a glance to see if there are even
tests for the file you're working on</li>
<li>all imports that you need are easier: no navigating out of a <code>__tests__</code>
directory to import the code you want to test. It's as easy as
<code>import Auth from './auth'</code>.</li>
</ul>
<p>If we ever have any test data that we use for our tests - mocking an API call,
for example - we'll put it in the same folder too. It feels very productive to
have everything you could ever need available right in the same folder and to
not have to go hunting through a large folder structure to find that file you're
sure exists but can't quite remember the name of.</p>
<h2>CSS Modules</h2>
<p>I'm a big fan of <a href="https://css-tricks.com/css-modules-part-1-need/">CSS Modules</a>
and we've found them great for writing modularised CSS in our components.</p>
<blockquote>
<p>I'm also a big fan of <a href="https://www.styled-components.com/">styled-components</a>,
but found at work with many contributors using actual CSS files has helped
people feel comfortable working with them.</p>
</blockquote>
<p>As you might have guessed, our CSS files go alongside our React components, too,
in the same folder. It's really easy to jump between the files and understand
exactly which class is doing what.</p>
<p>The broader point here is a running theme through this blog post: keep all your
component code close to each other. The days of having individual folders for
CSS, JS, icons, tests, are done: they made it harder to move between related
files for no apparent gain other than "organised code". Co-locate the files that
interact the most and you'll spend less time folder hopping and more time coding
👌.</p>
<p>We even built a
<a href="https://thread.engineering/2019-03-30-css-modules-strict/">strict CSS Modules Webpack loader</a>
to aid our developer workflow: it looks to see what classnames are defined and
sends a loud error to the console if you reference one that doesn't exist.</p>
<h2>Mostly one component per file</h2>
<p>In my experience people stick far too rigidly to the rule that each file should
have only one React component defined within it. Whilst I subscribe to the idea
that you don't want too large components in one file (just think how hard it
would be to name that file!), there's nothing wrong with pulling a small
component out if it helps keep the code clear, and remains small enough that it
makes little sense to add the overhead of extra files.</p>
<p>For example, if I was building a <code><Product></code> component, and needed a tiny bit of
logic for showing the price, I might pull that out:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">Price</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> price<span class="token punctuation">,</span> currency <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>span<span class="token operator">></span><br> <span class="token punctuation">{</span>currency<span class="token punctuation">}</span><br> <span class="token punctuation">{</span><span class="token function">formatPrice</span><span class="token punctuation">(</span>price<span class="token punctuation">)</span><span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>span<span class="token operator">></span><br><span class="token punctuation">)</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">Product</span> <span class="token operator">=</span> <span class="token parameter">props</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// imagine lots of code here!</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token operator"><</span>div<span class="token operator">></span><br> <span class="token operator"><</span>Price price<span class="token operator">=</span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>price<span class="token punctuation">}</span> currency<span class="token operator">=</span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>currency<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span><br> <span class="token operator"><</span>div<span class="token operator">></span>loads more stuff<span class="token operator">...</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><br> <span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>The nice thing about this is you don't create another file and you keep that
component private to <code>Product</code>. Nothing can possibly import <code>Price</code> because we
don't expose it. This means it'll be really clear to you about when to take the
step of giving <code>Price</code> its own file: when something else needs to import it!</p>
<h2>Truly generic components get their own folder</h2>
<p>One step we've taken recently at work is to introduce the idea of generic
components. These will eventually form our design system (which we hope to
publish online) but for now we're starting small with components such as
<code><Button></code> and <code><Logo></code>. A component is "generic" if it's not tied to any part
of the site, but is considered a building block of our UI.</p>
<p>These live within their own folder (<code>src/components/generic</code>) and the idea
behind this is that it's very easy to see all of the generic components we have
in one place. Over time as we grow we'll add a styleguide (we are big fans of
<a href="https://github.com/styleguidist/react-styleguidist">react-styleguidist</a>) to
make this even easier.</p>
<h2>Make use of import aliasing</h2>
<p>Whilst our relatively flat structure limits the amount of <code>../../</code> jumping in
our imports, it's hard to avoid having any at all. We use the
<a href="https://github.com/tleunen/babel-plugin-module-resolver">babel-plugin-module-resolver</a>
to define some handy aliases to make this easier.</p>
<blockquote>
<p>You can also do this via Webpack, but by using a Babel plugin the same imports
can work in our tests, too.</p>
</blockquote>
<p>We set this up with a couple of aliases:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br> <span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token string">'./src/components'</span><span class="token punctuation">,</span><br> <span class="token string-property property">'^generic/([\\w_]+)'</span><span class="token operator">:</span> <span class="token string">'./src/components/generic/\\1/\\1'</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span></code></pre>
<p>The first is straight forward: it allows any component to be imported by
starting the import with <code>components</code>. So rather than:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Product <span class="token keyword">from</span> <span class="token string">'../../components/product/product'</span></code></pre>
<p>We can instead do:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Product <span class="token keyword">from</span> <span class="token string">'components/product/product'</span></code></pre>
<p>And it will find the same file. This is great for not having to worry about
folder structure.</p>
<p>That second alias is slightly more complex:</p>
<pre class="language-js"><code class="language-js"><span class="token string-property property">'^generic/([\\w_]+)'</span><span class="token operator">:</span> <span class="token string">'./src/components/generic/\\1/\\1'</span><span class="token punctuation">,</span></code></pre>
<p>We're using a regular expression here to say "match any import that starts with
<code>generic</code> (the <code>^</code> ensures the import starts with "generic"), and capture what's
after <code>generic/</code> in a group. We then map that to
<code>./src/components/generic/\\1/\\1</code>, where <code>\\1</code> is what we matched in the regex
group. So this turns:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Button <span class="token keyword">from</span> <span class="token string">'generic/button'</span></code></pre>
<p>Into:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> Button <span class="token keyword">from</span> <span class="token string">'src/components/generic/button/button'</span></code></pre>
<p>Which will find us the JSX file of the generic button component. We do this
because it makes importing these components really easy, and protects us from if
we decide to change the file structure (which we might as we grow our design
system).</p>
<blockquote>
<p>Be careful with aliases! A couple to help you with common imports are great,
but more and it'll quickly start causing more confusion than the benefits it
brings.</p>
</blockquote>
<h2>A generic "lib" folder for utilities</h2>
<p>I wish I could get back all the hours I spent trying to find the perfect
structure for all my non-component code. I split them up into utilities,
services, helpers, and a million more names that I can't even remember. My
approach now is much more straightforward: just put them all in one "lib"
folder.</p>
<p>Long term, this folder might get so large that you want to add structure, but
that's OK. <em>It's always easier to add extra structure than remove superfluous
structure</em>.</p>
<p>Our <code>lib</code> folder at Thread has about 100 files in it, split roughly 50/50
between tests and implementation. And it hasn't once been hard to find the file
I'm looking for. With fuzzy file finders in most editors, I can just type
<code>lib/name_of_thing</code> and I'll find exactly what I want nearly every time.</p>
<p>We've also added an alias to make importing easier:
<code>import formatPrice from 'lib/format_price'</code>.</p>
<p>Don't be afraid of flat folders with lots of files in. It's often all you need.</p>
<h2>Hide 3rd party libraries behind your own API so they are easily swappable</h2>
<p>I'm a big fan of <a href="https://sentry.io/welcome/">Sentry</a> and have used it many
times across the backend and the frontend to capture and get notified of
exceptions. It's a great tool that has helped us become aware of bugs on the
site very quickly.</p>
<p>Whenever I implement a 3rd party library I'm thinking about how I can make it
easy to replace should we need to. Often we don't need to - in the case of
Sentry we are very happy - but it's good to think about how you would move away
from one service, or swap it for another, just in case.</p>
<p>The best approach for this is to provide your own API around the underlying
tool. I like to create a <code>lib/error-reporting.js</code> module, which exposes an
<code>reportError()</code> function. Under the hood this uses Sentry, but other than in
<code>lib/error-reporting.js</code>, there is no direct import of the Sentry module. This
means that swapping Sentry for another tool is really easy - I change one file
in one place, and as long as I keep the public API the same, no other files need
know.</p>
<blockquote>
<p>A module's public API is all the functions it exposes, and their arguments.
This is also known as a module's public interface.</p>
</blockquote>
<h2>Always use <code>prop-types</code> (or TypeScript/Flow)</h2>
<p>Whenever I'm programming I'm thinking about the three versions of myself:</p>
<ul>
<li>Past Jack, and the (questionable at times!) code he wrote</li>
<li>Current Jack, and what code I'm writing right now</li>
<li>Future Jack, and how I can write code now that makes his life as easy as
possible later on</li>
</ul>
<p>This sounds a bit silly but I've found it a useful way to frame my thinking
around approaches: <em>how is this going to feel in six months time when I come
back to it?</em></p>
<p>One easy way to make current and future versions of yourself more productive is
to document the prop-types that components use! This will save you time in the
form of typos, misremembering how a certain prop is used, or just completely
forgetting that you need to pass a certain prop. The
<a href="https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prop-types.md"><code>eslint-react/prop-types</code> rule</a>
comes in handy for helping remind us, too.</p>
<p>Going one step further: try to be specific about your prop-types. It's easy to
do this:</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">blogPost</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>object<span class="token punctuation">.</span>isRequired</code></pre>
<p>But far more helpful if you do this:</p>
<pre class="language-js"><code class="language-js"><span class="token literal-property property">blogPost</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span><span class="token function">shape</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>number<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br> <span class="token literal-property property">title</span><span class="token operator">:</span> PropTypes<span class="token punctuation">.</span>string<span class="token punctuation">.</span>isRequired<span class="token punctuation">,</span><br> <span class="token comment">// and so on</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>isRequired</code></pre>
<p>The former will do the bare minimum of checks; the latter will give you much
more useful information if you miss one particular field in the object.</p>
<h2>Don't reach for libraries until you need them</h2>
<p>This advice is more true now with the
<a href="http://www.jackfranklin.co.uk/refactoring-to-react-hooks/">release of React hooks</a> than it ever has been
before. I've been working on a large rebuild of part of
<a href="https://www.thread.com/">Thread's site</a> and decided to be extra particular about
including 3rd party libraries. My hunch was that with hooks and some of my own
utilities I could get pretty far down the road before needing to consider
anything else, and (unusually! 😃) it turned out that my hunch was correct.
<a href="https://kentcdodds.com/blog/application-state-management-with-react">Kent has written about this in his post "Application State Management with React"</a>
but you can get a long way these days with some hooks and React's built in
context functionality.</p>
<p>There is certainly a time and a place for libraries like Redux; my advice here
isn't to completely shun such solutions (and nor should you prioritise moving
away from it if you use it at the moment) but just to be considered when
introducing a new library and the benefits it provides.</p>
<h2>Avoid event emitters</h2>
<p>Event emitters are a design pattern I used to reach for often to allow for two
components to communicate with no direct link between them.</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// in component one</span><br>emitter<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">'user_add_to_cart'</span><span class="token punctuation">)</span><br><br><span class="token comment">// in component two</span><br>emitter<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'user_add_to_cart'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// do something</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>My motivation for using them was that the components could be entirely decoupled
and talk purely over the emitter. Where this came back to bite me is in the
"decoupled" part. Although you may <em>think</em> these components are decoupled, I
would argue they are not, they just have a dependency that's incredibly
implicit. It's implicit specifically because of what I thought was the benefit
of this pattern: the components don't know about each other.</p>
<p>It's true that if this example was in Redux it would share some similarities:
the components still wouldn't be talking directly to each other, but the
additional structure of a named action, along with the logic for what happens on
<code>user_add_to_cart</code> living in the reducer, makes it easier to follow.
Additionally the Redux developer tools makes it easier to hunt down an action
and where it came from, so the extra structure of Redux here is a benefit.</p>
<p>After working on many large codebases that are full of event emitters, I've seen
the following things happen regularly:</p>
<ol>
<li>Code gets deleted and you have emitters sending events that are never
listened to.</li>
<li>Or, code gets deleted and you have listeners listening to events that are
never sent.</li>
<li>An event that someone thought wasn't important gets deleted and a core bit of
functionality breaks.</li>
</ol>
<p>All of these are bad because they lead to a <em>lack of confidence</em> in your code.
When developers are unsure if some code can be removed, it's normally left in
place. This leads to you accumulating code that may or may not be needed.</p>
<p>These days I would look to solve this problem either using React context, or by
passing <a href="https://kentcdodds.com/blog/prop-drilling">callback props around</a>.</p>
<h2>Make tests easy with domain specific utilities</h2>
<p>We will end with a final tip of testing your components (PS:
<a href="http://www.jackfranklin.co.uk/testing-react-enzyme-jest/">I wrote a course on this!</a>): build out a suite of
test helper functions that you can use to make testing your components easier.</p>
<p>For example, I once built an app where the user's authentication status was
stored in a small piece of context that a lot of components needed. Rather than
do this in every test:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> context <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span> <span class="token literal-property property">userId</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><br><span class="token keyword">const</span> wrapper <span class="token operator">=</span> <span class="token function">mount</span><span class="token punctuation">(</span><br> <span class="token operator"><</span>UserAuth<span class="token punctuation">.</span>Provider value<span class="token operator">=</span><span class="token punctuation">{</span>context<span class="token punctuation">}</span><span class="token operator">></span><br> <span class="token operator"><</span>ComponentUnderTest <span class="token operator">/</span><span class="token operator">></span><br> <span class="token operator"><</span><span class="token operator">/</span>UserAuth<span class="token punctuation">.</span>Provider<span class="token operator">></span><br><span class="token punctuation">)</span></code></pre>
<p>I created a small helper:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> wrapper <span class="token operator">=</span> <span class="token function">mountWithAuth</span><span class="token punctuation">(</span>ComponentUnderTest<span class="token punctuation">,</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">userId</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>This has multiple benefits:</p>
<ul>
<li>each test is cleaned up and is very clear in what it's doing: you can tell
quickly if the test deals with the logged in or logged out experience</li>
<li>if our auth implementation changes I can update <code>mountWithAuth</code> and all my
tests will continue to work: I've moved our authentication test logic into one
place.</li>
</ul>
<p>Don't be afraid to create a lot of these helpers in a <code>test-utils.js</code> file that
you can rely upon to make testing easier.</p>
<h2>In conclusion</h2>
<p>In this post I've shared a bunch of tips from my experiences that will help your
codebase stay maintainable and more importantly <em>enjoyable</em> to work on as it
grows. Whilst every codebase has its rough edges and technical debt there are
techniques we can use to lessen the impact of it and avoid creating it in the
first place. As I said right at the start of this post, you should take these
tips and mould them to your own team, codebase, and preferences. We all have
different approaches and opinions when it comes to structuring and working on
large apps. I'd love to hear other tips you have: you can tweet me on
<a href="https://www.twitter.com/jack_franklin">@Jack_Franklin</a>, I'd love to chat.</p>
Saving manual work with babel-plugin-macros2019-07-09T00:00:00+00:00http://www.jackfranklin.co.uk/blog/saving-manual-work-with-babel-macro/<p><a href="https://github.com/kentcdodds/babel-plugin-macros">babel-plugin-macros</a> is a
project that I've followed with interest even though I'd never had a chance to
use it. Today that changed and I wanted to share my use case and my very
positive experience using it.</p>
<h2>What is babel-plugin-macros?</h2>
<p>The key feature of a Babel Macro is that they run <em>at compile time</em>. Rather than
writing JavaScript that gets bundled and executed in the browser, writing
JavaScript via babel-plugin-macros lets you run code at compile time. This means
that the code is executed <em>on your computer when you bundle</em>, not by your users
when they visit your website.</p>
<p>Most commonly these macros will either calculate some value (one that you can
and need at compilation time, not at runtime in the browser), or generate some
other code that runs in the browser.</p>
<p>As an example, once configured (we'll get to that in a moment), you can use
<a href="https://www.npmjs.com/package/preval.macro">preval.macro</a> to easily evaluate
some code at compile time:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> preval <span class="token keyword">from</span> <span class="token string">'preval.macro'</span><br><br><span class="token keyword">const</span> twoPlusTwo <span class="token operator">=</span> preval<span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">module.exports = 2 + 2</span><span class="token template-punctuation string">`</span></span></code></pre>
<p>This will be executed at compilation time, and the code that ships in your
bundle looks like this:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> twoPlusTwo <span class="token operator">=</span> <span class="token number">4</span></code></pre>
<h2>But, why is this useful?</h2>
<p>The example above is ultimately not that useful - I think we all trust browsers
to be able to add two and two at runtime. Today I came across a problem at work
that I solved with a macro which made my job much easier.</p>
<p>At <a href="https://www.thread.com/">Thread</a> we sell clothes. Part of the site allows
users to explore our entire product listing by filtering it down to what they
are after. One of the things they can filter by is "sub category": this is
specific types of clothes within a broader category. For example, for the
category "Shirts", we have sub categories of "Plain shirts", "Formal shirts",
"Denim shirts", and so on. The feature I'm working on adds an image to each of
these sub categories in the UI so that people who might not have heard of the
terminology can still recognise the category (before working in fashion I had no
idea what a "chambray" shirt was!).</p>
<p>One of the designers on the team sent me all the images, and there are <em>a lot</em>.
We have 50+ sub categories across all products and I had two choices for hooking
up each image to the sub category:</p>
<ol>
<li>Just use an image take and hard code the path:<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> source <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/media/images/sub-categories/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>subCategory<span class="token punctuation">.</span>slug<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span></code></pre>
</li>
<li>Manually create a map of <code>sub category slug => image URL</code>. This would mean
manually moving and importing 50+ images and hooking them into data from our
API.</li>
<li>Explore a solution that let me automatically load in the images and not have</li>
</ol>
<p>Unsurprisingly, I picked option three, and the game was on!</p>
<h2>Avoiding the basic solution</h2>
<p>Just to add a bit of colour to why I avoided what on paper is the easiest
solution:</p>
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>img<br> src<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/media/images/sub-categories/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>subCategory<span class="token punctuation">.</span>slug<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">}</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><br> alt<span class="token operator">=</span><span class="token punctuation">{</span>subCategory<span class="token punctuation">.</span>name<span class="token punctuation">}</span><br><span class="token operator">/</span><span class="token operator">></span></code></pre>
<p>For us this approach has a major downside: we can no longer use Webpack and
ES2015 imports to manage all our assets. We have Webpack configured to take our
images and move them into the right place, and I didn't want to have to special
case one folder of images just to make using them a little bit easier.</p>
<h2>Setting up babel-plugin-macros</h2>
<p>You might think that the macros need some complex setup but nope, it's as easy
as:</p>
<ol>
<li><code>yarn add babel-plugin-macros</code></li>
<li>Add <code>'macros'</code> to your plugins list in your babel config.</li>
</ol>
<p>And that's it 👌.</p>
<h2>Sub category slugs</h2>
<p>Each sub category is an object with a few keys:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span><br> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'Denim shirts'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">slug</span><span class="token operator">:</span> <span class="token string">'denim-shirts'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token string">'abc123'</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span></code></pre>
<p>Thankfully I'd already discussed with our designer that we'd name the images
based on the slugs, so I knew that I had all the images mapped and ready. This
helped a lot and it's something I'd recommend when working with a designer who
is creating a bunch of assets: chat ahead of time to figure out the best format
and naming scheme for sharing the results.</p>
<h2>import-all.macro</h2>
<p>The final piece of the puzzle is the
<a href="https://github.com/kentcdodds/import-all.macro">import-all.macro package</a>. This
lets me generate a list of imports from a folder <em>at compile time</em>. For example:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> importAll <span class="token keyword">from</span> <span class="token string">'import-all.macro'</span><br><br><span class="token keyword">const</span> a <span class="token operator">=</span> importAll<span class="token punctuation">.</span><span class="token function">sync</span><span class="token punctuation">(</span><span class="token string">'./files/*.js'</span><span class="token punctuation">)</span></code></pre>
<p>Gets turned into something like this <em>at compile time</em>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> _filesAJs <span class="token keyword">from</span> <span class="token string">'./files/a.js'</span><br><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> _filesBJs <span class="token keyword">from</span> <span class="token string">'./files/b.js'</span><br><br><span class="token keyword">const</span> a <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token string-property property">'./files/a.js'</span><span class="token operator">:</span> _filesAJs<span class="token punctuation">,</span><br> <span class="token string-property property">'./files/b.js'</span><span class="token operator">:</span> _filesBJs<span class="token punctuation">,</span><br><span class="token punctuation">}</span></code></pre>
<p>This is exactly what we want! We can use <code>importAll</code> to create an object of all
the file paths and the image URLs - We have Webpack set up so that when we
import an image we get back the full path of where that image will be put during
build:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> image <span class="token keyword">from</span> <span class="token string">'./image.jpg'</span><br><br><span class="token comment">// image => /media/images/image.jpg</span></code></pre>
<p>Once I'd figured this out, I was ready to write some code 🎉.</p>
<h2>Dealing with nested folders</h2>
<p>To make the folder of images easier to work with we'd agreed to nest sub
categories under a folder of that category. This meant that I needed to do a bit
of data manipulation to get exactly what I wanted, because the file name
returned from <code>import-all.macro</code> would have that extra folder in:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> images <span class="token operator">=</span> importAll<span class="token punctuation">.</span><span class="token function">sync</span><span class="token punctuation">(</span><span class="token string">'./category_images/**/*.png'</span><span class="token punctuation">)</span><br><br><span class="token comment">// images looks like:</span><br><span class="token punctuation">{</span><br> <span class="token string-property property">'./category_images/shirts/denim-shirt.png'</span><span class="token operator">:</span> <span class="token string">'/media/images/category_images/shirts/denim-shirt.png'</span><span class="token punctuation">,</span><br> <span class="token operator">...</span><br><span class="token punctuation">}</span></code></pre>
<p>And what I wanted to end up with was a map where the key is purely the slug:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// this is what we want</span><br><span class="token punctuation">{</span><br> <span class="token string-property property">'denim-shirt'</span><span class="token operator">:</span> <span class="token string">'/media/images/category_images/shirts/denim-shirt.png'</span><span class="token punctuation">,</span><br> <span class="token operator">...</span><br><span class="token punctuation">}</span></code></pre>
<p>This was a case of doing a bit of work on the object that <code>import-all.macro</code>
generates for us:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> importAll <span class="token keyword">from</span> <span class="token string">'import-all.macro'</span><br><br><span class="token keyword">const</span> allCategoryImages <span class="token operator">=</span> importAll<span class="token punctuation">.</span><span class="token function">sync</span><span class="token punctuation">(</span><span class="token string">'./category_images/**/*.png'</span><span class="token punctuation">)</span><br><br><span class="token keyword">const</span> imagesMap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><br> Object<span class="token punctuation">.</span><span class="token function">entries</span><span class="token punctuation">(</span>allCategoryImages<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">[</span>fileName<span class="token punctuation">,</span> imageUrl<span class="token punctuation">]</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// image = "./category_images/accessories/bags.png"</span><br> <span class="token comment">// so split and pick out just the "bags.png" bit</span><br> <span class="token keyword">const</span> subCategory <span class="token operator">=</span> fileName<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">3</span><span class="token punctuation">]</span><br><br> <span class="token comment">// remove the extension and return [key, value] pair of [slug, imageURL]</span><br> <span class="token keyword">return</span> <span class="token punctuation">[</span>subCategory<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.png</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">,</span> imageUrl<span class="token punctuation">]</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">)</span><br><br><span class="token keyword">export</span> <span class="token keyword">default</span> imagesMap</code></pre>
<p>And with that, we're done! Now in our React component we can fetch the image
from our Map:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> imageUrl <span class="token operator">=</span> imagesMap<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>subCategory<span class="token punctuation">.</span>slug<span class="token punctuation">)</span></code></pre>
<p>As a bonus, we can also easily add some logging to alert us to if a sub category
is missing an image:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>imageUrl<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>subCategory<span class="token punctuation">.</span>slug<span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">logError</span><span class="token punctuation">(</span><span class="token string">'...'</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<h2>Conclusion</h2>
<p>The solution that babel-plugin-macros lets us create is elegant and easy to work
with. It will also automatically deal with new images and new sub categories and
it's easy for non-engineers to update a sub category image without needing any
help from us - they can just dump the new image in the right place and
everything will update. For tasks like this in the future we will definitely be
reaching for it again and I recommend giving it a go next time you're faced with
a much of manual lifting that feels very much like it could be automated!</p>
Making impossible states impossible: data structures in React2019-07-22T00:00:00+00:00http://www.jackfranklin.co.uk/blog/avoiding-impossible-states-react/<p>One of the things I like to spend a lot of time on is data structures. It's one
of the first things I think about when building something: what data do I have
to work with, and what's the best format for it to be in?</p>
<p>In my experience if you can get the data format correct everything else should
fall into place; a data structure that allows you to read and manipulate the
data easily is going to be much nicer to work with. You want the data structure
to do as much of the work for you as it can and it should work with you and not
feel like it gets in your way.</p>
<p>Interestingly, I think because of the strictly typed nature of the languages, I
find myself taking this approach much more when I'm working with Elm or
TypeScript: something about the presence of types leads me to think about
defining the types I'll use through my application - and this leads to me
thinking about data structures. Today we're going to look at a JavaScript
example where we'll strongly consider the datatype that we use to solve a
problem.</p>
<h2>Making impossible states impossible</h2>
<p>There is a very popular Elm talk titled
<a href="https://www.youtube.com/watch?v=IcgmSRJHu_8">"Making Impossible States Impossible"</a>
by <a href="https://twitter.com/rtfeldman">Richard Feldman</a> which has become my
reference of choice for this topic. I highly recommend watching the video - even
if you don't like or know Elm - because the approach transcends any given
language. The example for this blog post is also taken from that talk because
it's perfect for what I want to discuss, so thank you Richard!</p>
<h2>Tabs</h2>
<p>Every frontend developer has built a tabbed interface at one point in their
lives, and it's these that we'll look at today. We'll have some tabs at the top
of the page and then show the content for the currently active tab below it.</p>
<blockquote>
<p>Today I'll be using React for the UI but this is not important for the topic -
feel free to swap React for your framework of choice 👍</p>
</blockquote>
<p>We have two bits of information that we have as data:</p>
<ul>
<li>all the tabs: their title and their content</li>
<li>some data to know which tab is active and therefore which tab to highlight and
which content to show</li>
</ul>
<p>Feel free to think for a moment about how you'd model this data.</p>
<p>This is my first pass, and I'm confident that I'm not the only one who would
take this approach:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>activeIndex<span class="token punctuation">,</span> setActiveIndex<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><br><br><span class="token keyword">const</span> tabs <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Tab One'</span><span class="token punctuation">,</span> <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'This is tab one'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Tab Two'</span><span class="token punctuation">,</span> <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'This is tab two'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Tab Three'</span><span class="token punctuation">,</span> <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'This is tab three'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">]</span></code></pre>
<blockquote>
<p>I'm hardcoding <code>tabs</code> here but let's imagine in reality we're building a Tab
library that others will consume and pass in the tabs.</p>
</blockquote>
<h2>The critical question: what impossible states does this data structure permit?</h2>
<p>When we're thinking about data structures and how to improve them this is the
question you want to be asking yourself. Take the data structure that you've
come up with and see if you can set values that cause impossible states. For
example, I can:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>activeIndex<span class="token punctuation">,</span> setActiveIndex<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><br><br><span class="token comment">// omitted the contents to save space</span><br><span class="token keyword">const</span> tabs <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">]</span></code></pre>
<p>In this state I've set the <code>activeIndex</code> to <code>4</code> (which would mean the 5th tab as
arrays are zero-indexed in JavaScript), but we only have three tabs. So this
state is impossible!</p>
<p>At this point you might be thinking that it doesn't matter that this state
<em>could</em> exist, because we can write code to ensure that it can't exist. And that
is true: we could write code to ensure that <code>activeIndex</code> never gets set a value
that is out of bounds. And we could ensure all our click event listeners for our
tabs only set valid <code>activeIndex</code> values. But if we had a data structure that
didn't allow this impossible state, we <em>wouldn't have to write any of the code
we just spoke about</em>. And that's the value of thinking of data structures that
ban impossible states: they remove even the slightest chance of certain bugs
ever occurring because <em>the data doesn't allow them to</em>.</p>
<blockquote>
<p>In JavaScript land technically every data structure we come up with will allow
an invalid state because we could set any value to <code>undefined</code> or <code>null</code>. This
is where the typed languages have an edge: when you can ensure at compile time
that a certain value must exist, you can create data structures that truly
make impossible states impossible. For today's post we'll take the leap of
hoping that values that we expect to be present are indeed present.</p>
</blockquote>
<p>Whilst it's very hard to come up with a data structure that avoids <em>any</em>
impossible state, we can work on creating data structures that avoid <em>obviously
invalid states</em>, such as the problem above.</p>
<h2>An alternative data structure</h2>
<p>So if we want to avoid the problem of the <code>activeIndex</code> being an invalid number,
how about we remove it entirely and track which tab is active:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>activeTab<span class="token punctuation">,</span> setActiveTab<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span>tabs<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><br><span class="token keyword">const</span> <span class="token punctuation">[</span>restOfTabs<span class="token punctuation">,</span> setRestOfTabs<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span>tabs<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<p>In this approach we split the actual tab object out and remember which one is
active. This does mean we will need a new key on each tab to know which order to
render them in, as we've lost the nice ordered array they were in, but maybe
this is a price worth paying for this data structure. Is this better or worse
than the previous attempt? And crucially: does it allow any invalid states?</p>
<p>If we assume that our code won't go rogue and set values to <code>null</code> (as
previously mentioned, this is where some types and a compiler would come in
handy), it's harder to get this data into an invalid state. When a user clicks
on a tab we can swap which tab is the <code>activeTab</code>. However there is a big red
flag to me here: two co-located <code>useState</code> calls with very related bits of data.</p>
<p>This data structure opens us up to problems by storing two values in the state
together. Whenever you see two state values that are tightly related you are
likely to be opening yourself up to bugs where these values get out of sync. You
can either rethink how you are modelling your data, or reach for the
<a href="https://reactjs.org/docs/hooks-reference.html#usereducer"><code>useReducer</code> hook</a>,
which allows you to update multiple bits of state at once.</p>
<p>The fact that this data structure loses a key feature of our tabs - their
ordering - is also a red flag. We'll have to either ask the consumer of our
module to pass in objects with an <code>order</code> key, or do it ourselves. When you find
yourself having to mutate data to add properties you need because your data
structure doesn't provide it, that's a sign that maybe the data structure isn't
quite right.</p>
<h2>Zip lists</h2>
<p>Let's look at a final data structure: the zip list. The zip list breaks down a
list where we care about the active state into three parts:</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// before:</span><br><span class="token keyword">const</span> tabs <span class="token operator">=</span> <span class="token punctuation">[</span>tabOne<span class="token punctuation">,</span> tabTwo<span class="token punctuation">,</span> tabThree<span class="token punctuation">]</span><br><br><span class="token comment">// after:</span><br><span class="token keyword">const</span> tabs <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">previous</span><span class="token operator">:</span> <span class="token punctuation">[</span>tabOne<span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token literal-property property">current</span><span class="token operator">:</span> tabTwo<span class="token punctuation">,</span><br> <span class="token literal-property property">next</span><span class="token operator">:</span> <span class="token punctuation">[</span>tabThree<span class="token punctuation">]</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span></code></pre>
<p>The advantages of this approach over our last two are:</p>
<ol>
<li>We keep the ordering of the tabs and can easily construct an array of them
(<code>[...tabs.previous, tabs.current, ...tabs.next]</code>).</li>
<li>We now have to have a current tab at all times. And because we'll construct
this data structure from the initial array of tabs the user gives us, we can
be pretty confident of avoiding some of the impossible states this data
structure does allow (duplicated tabs).</li>
<li>All our data is in one object: the previous attempt split the tabs up into
two pieces of state which could more easily get out of sync: here we've got
just one.</li>
</ol>
<blockquote>
<p>Notice how we still have impossible states here: <code>tabs.previous</code> could contain
the same tab as <code>tabs.current</code>, which would be a bug. But because it's all in
one piece of data that we are going to write code to manipulate we can have
close control over this and those bugs are less likely than two individual
pieces of state becoming misaligned.</p>
</blockquote>
<p>Let's start our initial zip list implementation and see how we go. I'll create a
function that takes in the initial array, sets the first item as active (in the
future we might allow the user to tell us which tab is active) and then create
our data structure:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">zipList</span> <span class="token operator">=</span> <span class="token parameter">initialArray</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token punctuation">[</span>initialActive<span class="token punctuation">,</span> <span class="token operator">...</span>restOfTabs<span class="token punctuation">]</span> <span class="token operator">=</span> initialArray<br><br> <span class="token keyword">const</span> zip <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">previous</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token literal-property property">current</span><span class="token operator">:</span> initialActive<span class="token punctuation">,</span><br> <span class="token literal-property property">next</span><span class="token operator">:</span> restOfTabs<span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br><br> <span class="token keyword">const</span> <span class="token function-variable function">setActive</span> <span class="token operator">=</span> <span class="token parameter">zip</span> <span class="token operator">=></span> <span class="token parameter">newActive</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// TODO: fill this in</span><br> <span class="token keyword">const</span> newZip <span class="token operator">=</span> zip<br> <span class="token keyword">return</span> <span class="token function">apiForZip</span><span class="token punctuation">(</span>newZip<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><br> <span class="token keyword">const</span> <span class="token function-variable function">apiForZip</span> <span class="token operator">=</span> <span class="token parameter">zip</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token function-variable function">asArray</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token operator">...</span>zip<span class="token punctuation">.</span>previous<span class="token punctuation">,</span> zip<span class="token punctuation">.</span>current<span class="token punctuation">,</span> <span class="token operator">...</span>zip<span class="token punctuation">.</span>next<span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token function-variable function">isActive</span><span class="token operator">:</span> <span class="token parameter">tab</span> <span class="token operator">=></span> zip<span class="token punctuation">.</span>current <span class="token operator">===</span> tab<span class="token punctuation">,</span><br> <span class="token literal-property property">setActive</span><span class="token operator">:</span> <span class="token function">setActive</span><span class="token punctuation">(</span>zip<span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token function-variable function">activeTab</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> zip<span class="token punctuation">.</span>current<span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> <span class="token keyword">return</span> <span class="token function">apiForZip</span><span class="token punctuation">(</span>zip<span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>When creating custom data structures the key is to <em>hide the raw data behind a
nice API</em>. If you expose the raw data it's hard to change that structure because
people might rely on it, and in a mutable language world like JavaScript people
could reach in and change your data in whatever way they like. Notice how the
<code>zip</code> object is not exposed and instead we provide a small API.</p>
<p>In our React component we can still map over tabs by doing
<code>tabs.asArray().map(...)</code>, and we can determine the active tab via the
<code>isActive()</code> function. The <code>activeTab()</code> function lets us fetch the active tab
so we can show its content on the page. The final piece of the jigsaw is
<code>setActive</code>, which needs a bit more thought. This is where we are going to write
more code than if we'd have taken the <code>activeIndex</code> approach, but we're trading
that off against the higher confidence we have in this data structure.
<em>Programming is all about trade-offs, after all!</em>.</p>
<p>So we can move the tabs in our component into a piece of state:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>tabs<span class="token punctuation">,</span> setTabs<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><br> <span class="token function">zipList</span><span class="token punctuation">(</span><span class="token punctuation">[</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Tab One'</span><span class="token punctuation">,</span> <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'This is tab one'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Tab Two'</span><span class="token punctuation">,</span> <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'This is tab two'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Tab Three'</span><span class="token punctuation">,</span> <span class="token literal-property property">content</span><span class="token operator">:</span> <span class="token string">'This is tab three'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">]</span><span class="token punctuation">)</span><br><span class="token punctuation">)</span></code></pre>
<p>And we can use the <code>setTabs</code> function to update the state when a user clicks on
a tab (ensuring that our zip list's API returns a new zip list from the
<code>setActive</code> call):</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token punctuation">{</span><br> tabs<span class="token punctuation">.</span><span class="token function">asArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">tab</span> <span class="token operator">=></span> <span class="token punctuation">(</span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span><br> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>tab<span class="token punctuation">.</span>title<span class="token punctuation">}</span></span><br> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setTabs</span><span class="token punctuation">(</span>tabs<span class="token punctuation">.</span><span class="token function">setActive</span><span class="token punctuation">(</span>tab<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">}</span></span><br> <span class="token attr-name">className</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>tabs<span class="token punctuation">.</span><span class="token function">isActive</span><span class="token punctuation">(</span>tab<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token string">'border-red-800'</span> <span class="token operator">:</span> <span class="token string">'border-gray-800'</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span></span><br> <span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token punctuation">{</span>tab<span class="token punctuation">.</span>title<span class="token punctuation">}</span><span class="token plain-text"><br> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span><br> <span class="token punctuation">)</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>The <code>setActive</code> function takes a bit of thought to get right in terms of
updating the values. Let's say we have this state:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> zip <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">previous</span><span class="token operator">:</span> <span class="token punctuation">[</span>tabOne<span class="token punctuation">,</span> tabTwo<span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token literal-property property">current</span><span class="token operator">:</span> tabThree<span class="token punctuation">,</span><br> <span class="token literal-property property">next</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span></code></pre>
<p>And now we click on <code>tabOne</code>. We need to make the data structure become:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> zip <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">previous</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token literal-property property">current</span><span class="token operator">:</span> tabOne<span class="token punctuation">,</span><br> <span class="token literal-property property">next</span><span class="token operator">:</span> <span class="token punctuation">[</span>tabTwo<span class="token punctuation">,</span> tabThree<span class="token punctuation">]</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span></code></pre>
<p>To do this we can follow a set of steps:</p>
<ol>
<li>Figure out where the new active tab is: <code>previous</code> or <code>next</code>. For this
example it's in the <code>previous</code> state.</li>
<li>We now need to split <code>previous</code> into two lists: the previous items that
appear <em>before</em> the new active tab, and the items that appear <em>after</em> it. We
need this because the ones that appear before need to <em>stay in the previous
list</em>, but the items that appear after the item that's about to become active
need to <em>go into the next list</em>.</li>
<li>We can then construct the new zip:<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> newZip <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">previous</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token operator">...</span>previousItemsBeforeActive<span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token literal-property property">current</span><span class="token operator">:</span> newActive<span class="token punctuation">,</span><br> <span class="token literal-property property">next</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token operator">...</span>previousItemsAfterActive<span class="token punctuation">,</span> zip<span class="token punctuation">.</span>current<span class="token punctuation">,</span> <span class="token operator">...</span>zip<span class="token punctuation">.</span>next<span class="token punctuation">]</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span></code></pre>
</li>
</ol>
<p>And with that we now have a functioning set of tabs with a zip list
implementation 👍.</p>
<h2>That was...a lot of work?!</h2>
<p>That might feel like an awful amount of work to go through just to get some tabs
listed on the screen. And to some extent, it was! But we've definitely gained
benefits from doing this work. Firstly, the Zip List isn't specific to tabs:
whenever you find yourself having a list of things where one is considered
active in some form, this data structure is a great one to reach for. And you
now have a reusable implementation of a zip list ready to be used whenever the
time comes.</p>
<p>I've lost count of the number of bugs I've had because an <code>activeIndex</code> type
tracker got out of sync: in our zip list we don't rely on any other data:
there's one object that controls everything about which item is active. That's
going to pay off in terms of bugs we've avoided, for sure.</p>
<p>Is building a data structure like this worth it <em>every single time</em> you have
some tabs and you want to show one as active? Possibly not - that's up to you.
As always in programming, it depends. But I hope this blog post inspires you to
think more carefully about data structures and ask how you can structure them to
work with you and help rule out impossible states.</p>
<h2>NPM Package</h2>
<p>I have published the Zip List implementation (well, a slightly tweaked one) as
an npm package so you can use them without having to implement them! You can
find the repository <a href="https://github.com/jackfranklin/zip-list/">on Github</a> and
install it via npm or Yarn today 🎉:</p>
<pre><code>yarn add @jackfranklin/zip-list
npm install @jackfranklin/zip-list
</code></pre>
Getting started with GraphQL: what client to use?2019-07-29T00:00:00+00:00http://www.jackfranklin.co.uk/blog/using-graphql-without-a-client/<p>When I first started working with GraphQL APIs my first challenge was to decide
what GraphQL frontend library I wanted to use. I can remember spending all
morning exploring all sorts of options, from small libraries like
<a href="https://www.npmjs.com/package/graphql-request">graphql-request</a> to slightly
larger ones like <a href="https://github.com/FormidableLabs/urql">urql</a> and finally the
most well known like <a href="https://www.apollographql.com/">Apollo</a>. These are all great
libraries - in fact we use urql at work - but at this point in time I was
working with a tiny GraphQL library that I'd built for a side project and I
really didn't need any complexity. I think I lost a good couple of hours trying
to decide before thinking: what if I made my own?</p>
<blockquote>
<p>This post is not meant to criticise libraries: they provide a bunch of
features that many applications will want and need, but if you're just getting
started, they might be overkill for your needs.</p>
</blockquote>
<h2>Do you need a library to use GraphQL?</h2>
<p>I had in my head this mindset that making a request to a GraphQL API was
"special" and not something that I could do with the <code>fetch</code> API, for example.
I'm not really sure where this came from but I think I'd seen so many talks
about Apollo and various client libraries doing all sorts of smart things I'd
ended up assuming that I'd use one of those. But Apollo packs in a vast array of
features that I really didn't need on my side project. I wanted to make a
request and get the data. Concerns such as smart caching and cache invalidation
were not present for me.</p>
<p>When you're starting to learn something it can be tempting to reach for
libraries to fill in gaps in knowledge but I highly recommend trying to avoid
doing this when possible. I'm very happy that I made the decision to write my
own tiny client because it plugged gaps in my knowledge and de-mystified how a
GraphQL API works. In this post I'll talk through how to get started talking to
a GraphQL API just by using the <code>fetch</code> API and nothing more.</p>
<h2>A sample GraphQL API</h2>
<p>We need a sample API for this and I've made one that lives on Heroku:
http:faker-graphql-api.herokuapp.com/graphql. This API returns some fake people
(all data is generated by <a href="https://github.com/marak/Faker.js/">Faker.js</a>). It lets
us query for people and get their names:</p>
<pre class="language-graphql"><code class="language-graphql"><span class="token punctuation">{</span><br> <span class="token object">people</span> <span class="token punctuation">{</span><br> <span class="token property">name</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Returns an array of ten people and their names. This is the query we're going to
use as our example today.</p>
<blockquote>
<p>My dummy API is hosted on a free Heroku instance so please be patient if it
takes some time to boot up when you request it.</p>
</blockquote>
<h2>Making a request to a GraphQL API</h2>
<p>It turns out there are some simple steps to follow to talk to a GraphQL
endpoint:</p>
<ul>
<li>All requests are <code>POST</code> requests</li>
<li>You should pass the <code>Content-Type</code> header as <code>application/json</code></li>
<li>The body of the request should contain a string which is the GraphQL query</li>
</ul>
<p>As long as we follow those rules we can easily use <code>fetch</code> to talk to the API.
Let's do it!</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> api <span class="token operator">=</span> <span class="token string">'http:faker-graphql-api.herokuapp.com/graphql'</span><br><br><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">request</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> query <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span>api<span class="token punctuation">,</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">'POST'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">'Content-Type'</span><span class="token operator">:</span> <span class="token string">'application/json'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> query<span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">response</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">result</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'got here!'</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><br> <span class="token keyword">return</span> result<br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>The <code>request</code> function takes an object and expects the <code>query</code> key to contain
the raw GraphQL query. The <code>fetch</code> API takes the URL and an object of options,
which are used to configure the request: we set <code>method: 'POST'</code> and the
<code>Content-Type</code> header as discussed and then use <code>JSON.stringify({ query })</code> to
generate the body for the request, passing in the <code>query</code> that was passed in to
our <code>request</code> function. Finally, the GraphQL API will return JSON so we parse
the response before returning it (I've logged it just to aid debugging but feel
free to skip that!).</p>
<p>With that we can make our request:</p>
<pre class="language-js"><code class="language-js"><span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">query</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">{ people { name } }</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>And you should get some people back! 🎉.</p>
<p>If you only need to make basic requests in your app you could stop here and be
done. We've saved having to install, learn and ship in our bundle any additional
libraries. Of course this comes with less functionality - but for some projects
that might be just fine.</p>
<blockquote>
<p>If you do need caching and more advanced features I'd highly recommend a well
tested, established library rather than rolling your own!</p>
</blockquote>
<h2>Supporting variables</h2>
<p>Another feature of GraphQL is that queries can take variables. For example, the
fake API lets us find a single person by their ID:</p>
<pre class="language-graphql"><code class="language-graphql"><span class="token keyword">query</span> <span class="token definition-query function">fetchPerson</span><span class="token punctuation">(</span><span class="token variable">$id</span><span class="token punctuation">:</span> <span class="token scalar">Int</span><span class="token operator">!</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token property-query">person</span><span class="token punctuation">(</span><span class="token attr-name">id</span><span class="token punctuation">:</span> <span class="token variable">$id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token property">name</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>To support this our API needs to pass variables through as well that it includes
in the request:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">request</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> variables<span class="token punctuation">,</span> query <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span>api<span class="token punctuation">,</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">'POST'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">'Content-Type'</span><span class="token operator">:</span> <span class="token string">'application/json'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> query<span class="token punctuation">,</span><br> variables<span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">response</span> <span class="token operator">=></span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">result</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'got here!'</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span><br> <span class="token keyword">return</span> result<br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>And now our client supports variables:</p>
<pre class="language-js"><code class="language-js"><span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">query</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">query fetchPerson($id: Int!) {<br> person(id: $id) {<br> name,<br> }<br> }</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br> <span class="token literal-property property">variables</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>If this is all you need, or you're not using React for your frontend, you can
stop here. This client will be plenty good enough to keep you going as you work
with and get more familiar with GraphQL. By working with your own
implementations first you'll find you have a greater fundamental understanding
when swapping to a library, and you'll understand the features the library
provides better.</p>
<h2>A React hook!</h2>
<p>Finally let's see how easy it would be to wrap this up in a React hook for those
of you working with React.</p>
<blockquote>
<p>If you're not familiar with hooks, I wrote
<a href="http://www.jackfranklin.co.uk/refactoring-to-react-hooks/">an introduction to them</a> which will help get
you up to speed.</p>
</blockquote>
<p>Creating the hook is a case of wrapping our <code>request</code> function in a
<code>React.useEffect</code> hook and storing the response via <code>React.useState</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">useGraphQL</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> variables<span class="token punctuation">,</span> query <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token punctuation">[</span>data<span class="token punctuation">,</span> setData<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><br><br> React<span class="token punctuation">.</span><span class="token function">useEffect</span><span class="token punctuation">(</span><br> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span> variables<span class="token punctuation">,</span> query <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>setData<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">[</span>variables<span class="token punctuation">,</span> query<span class="token punctuation">]</span><br> <span class="token punctuation">)</span><br><br> <span class="token keyword">return</span> <span class="token punctuation">[</span>data<span class="token punctuation">]</span><br><span class="token punctuation">}</span></code></pre>
<blockquote>
<p>This hook is missing some useful features like tracking if we're loading or
not, but I'll leave that as an exercise to the reader 😃</p>
</blockquote>
<p>We can use this hook within a component like so:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>data<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useGraphQL</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">query</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">{ people { name } }</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>And it works! There is one gotcha though that I want to highlight. If you do
this:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>data<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useGraphQL</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">variables</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token literal-property property">query</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">{ people { name } }</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>You'll cause an infinite loop of requests, which isn't what we want! This is
because <code>React.useEffect</code> has <code>variables</code> as a dependency and every time it
changes it will cause the effect to re-run. Every re-render this code runs and
<code>variables: {}</code> creates a new object every time which means <code>React.useEffect</code>
will re-run.</p>
<p>We can fix this by remembering to wrap our <code>variables</code> in a <code>React.useMemo</code> hook
to ensure that we only recalculate the variables if we need to:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> vars <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useMemo</span><span class="token punctuation">(</span><br> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> props<span class="token punctuation">.</span>id<span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">[</span>props<span class="token punctuation">.</span>id<span class="token punctuation">]</span><br><span class="token punctuation">)</span><br><br><span class="token keyword">const</span> <span class="token punctuation">[</span>data<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useGraphQL</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">variables</span><span class="token operator">:</span> vars<span class="token punctuation">,</span><br> <span class="token literal-property property">query</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">{ people { name } }</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>But this requires you to remember to do this every time. Instead what we can do
is convert the <code>variables</code> within our <code>useGraphQL</code> hook to a string, via
<code>JSON.stringify</code>, and use that as the dependency to <code>useEffect</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> stringifiedVars <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>variables<span class="token punctuation">)</span><br>React<span class="token punctuation">.</span><span class="token function">useEffect</span><span class="token punctuation">(</span><br> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span> variables<span class="token punctuation">,</span> query <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>setData<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">[</span>stringifiedVars<span class="token punctuation">,</span> query<span class="token punctuation">]</span><br><span class="token punctuation">)</span></code></pre>
<blockquote>
<p>❗️This isn't the best solution but it is the easiest and will serve just fine
for most projects. It's also similar to how the popular
<a href="https://github.com/FormidableLabs/urql/blob/master/src/utils/keyForQuery.ts">urql works</a>
although that uses the
<a href="https://www.npmjs.com/package/fast-json-stable-stringify">fast-json-stable-stringify</a>
to avoid some of the performance problems with <code>JSON.stringify</code>.</p>
</blockquote>
<h2>Conclusion</h2>
<p>Although this post has focused on GraphQL I hope that your main takeaway is to
resist diving straight for libraries. You can often get a long way with a few
lines of code you write yourself, <em>particularly when learning a new technology</em>.
This will help your understanding of the tech that you're learning but also your
understanding of libraries: if you've written a library yourself, however small
and straight forward, you're more likely to be able to follow how the more
complex libraries work.</p>
A free video series on building web apps with Elm2019-08-29T00:00:00+00:00http://www.jackfranklin.co.uk/blog/building-apps-with-elm-video-series/<p>If you've followed me on the internet for a while you'll know that I'm a big fan
of <a href="https://elm-lang.org/">Elm</a> and I've written and spoken a fair bit about it.</p>
<p>There are some great guides for Elm out there but when I was learning I
struggled with being unable to find examples of how Elm apps were put together,
particularly as they got bigger.</p>
<p>So, now I'm a little more comfortable with Elm than I once was, I set about
recording a series that tries to show just that. My initial intentions were to
sell the videos as a course, but I've now decided to make every single video
entirely free and available on YouTube for you to enjoy.</p>
<p>You can get started with the playlist and watch all videos in order by
<a href="https://www.youtube.com/watch?v=-1ZA3G9k0Rw&list=PLGDf0elkI13EJ55MbwZd98scG7BKl_n-j">heading to YouTube</a>
or watching here:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/-1ZA3G9k0Rw" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<p>If you have any questions, Twitter is the best place to grab me :)</p>
Avoiding bugs with data structures: using Sets in JavaScript2019-09-02T00:00:00+00:00http://www.jackfranklin.co.uk/blog/avoiding-bugs-with-javascript-sets-react/<p>When working on a part of a user interface I like to constantly try to think
about potential bugs that could occur, potentially when looking at taking input
from users. Most components that take input will have code to prevent invalid
input and bugs and you can't ever avoid this, but sometimes the right data
structure can remove the amount of bugs you'll have to write code to deal with.</p>
<p>To demonstrate this we'll be working today with a component that lets a user tag
something with tags. The GIF below shows two versions; the first has a bug and
the second doesn't. We'll talk about why in just a moment...</p>
<img src="http://www.jackfranklin.co.uk/code-for-posts/sets/example.gif" width="500">
<p>The great thing is that the second example <em>has no code to explicitly deal with
that bug</em>; it uses a more appropriate data structure that makes this bug
impossible.</p>
<p>When working with a list of data where one of the constraints is that there is
no duplication, I like to reach for a JavaScript
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set">Set</a>.
Sets were introduced in ES2015 and allow you to store unique data. If you try to
add some data to a set that it already has, it won't do anything. So it's
<em>literally impossible</em> for a set to contain duplicate values, and we can
leverage this for our tags component.</p>
<h2>Working with sets</h2>
<p>Rather than create my tags state as an array, I instead use a set. You
initialise a set by giving it an array of items:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>tags<span class="token punctuation">,</span> setTags<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'react'</span><span class="token punctuation">,</span> <span class="token string">'javascript'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<blockquote>
<p>Be careful, <code>new Set('react')</code> gives you a set with 5 items; <code>r</code>, <code>e</code>, and so
on. You probably want <code>new Set(['react'])</code> 👍.</p>
</blockquote>
<p>You add an item to a set by calling the <code>add</code> method:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> names <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br>names<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">'jack'</span><span class="token punctuation">)</span><br>names<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">'jack'</span><span class="token punctuation">)</span> <span class="token comment">// does nothing!</span></code></pre>
<p>Be careful though: adding to a set mutates the set. When working with React you
typically want to avoid mutating data and instead create new instances. You
could use a <a href="https://github.com/immerjs/immer">library such as Immer</a> to make
this easier, or pass the set into the <code>Set</code> constructor:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> names <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'alice'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><br><br><span class="token keyword">const</span> newNames <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span>names<span class="token punctuation">)</span><br>newNames<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">'bob'</span><span class="token punctuation">)</span><br><br><span class="token comment">// newNames = alice, bob</span><br><span class="token comment">// but names is left alone</span></code></pre>
<p>Using this within our <code>Tags</code> component looks like so:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>tags<span class="token punctuation">,</span> setTags<span class="token punctuation">]</span> <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'react'</span><span class="token punctuation">,</span> <span class="token string">'javascript'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">addTag</span> <span class="token operator">=</span> <span class="token parameter">newTag</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">setTags</span><span class="token punctuation">(</span><span class="token parameter">oldTags</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> newSet <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span>oldTags<span class="token punctuation">)</span><br> newSet<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>newTag<span class="token punctuation">)</span><br> <span class="token keyword">return</span> newSet<br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>It's worth noting at this point that this code is slightly more verbose than if
we'd have used an array, where we could have done:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">addTag</span> <span class="token operator">=</span> <span class="token parameter">newTag</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">setTags</span><span class="token punctuation">(</span><span class="token parameter">oldTags</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token operator">...</span>oldTags<span class="token punctuation">,</span> newTag<span class="token punctuation">]</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>But if you wanted, you could make the set equivalent slightly more concise:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">addTag</span> <span class="token operator">=</span> <span class="token parameter">newTag</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">setTags</span><span class="token punctuation">(</span><span class="token parameter">oldTags</span> <span class="token operator">=></span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">...</span>oldTags<span class="token punctuation">,</span> newTag<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<blockquote>
<p>This is probably what I'd do in a real app - but I'll stick with the slightly
longer example for this post as I think it's clearer if you're not super
familiar with using Sets.</p>
</blockquote>
<p>If you create a set with the same values in twice, only one will persist. The
code below creates a set with just one item, set to <code>'alice'</code>:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'alice'</span><span class="token punctuation">,</span> <span class="token string">'alice'</span><span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre>
<h2>Rendering sets in React</h2>
<p>There's one more gotcha with sets: they don't have common array methods like
<code>map</code>, which is commonly used in React to map an array to a list of components:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span><span class="token punctuation">{</span>tags<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">tag</span> <span class="token operator">=></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>tag<span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token punctuation">{</span>tag<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></code></pre>
<p>This is easily solved by converting a set to an array. You can use the spread
operator to do this, or use <code>Array.from</code>. Either works:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> set <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'alice'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><br><br><span class="token punctuation">[</span><span class="token operator">...</span>set<span class="token punctuation">]</span> <span class="token comment">// works!</span><br><br>Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>set<span class="token punctuation">)</span> <span class="token comment">// also works!</span></code></pre>
<p>I tend to prefer <code>[...set]</code> as it's cleaner, but this is personal preference so
pick your favourite.</p>
<h2>Bug avoided! 🐛</h2>
<p>Swapping our data structure from an array to a set has completely removed the
ability for the user to ever enter duplicates because <em>the data structure
forbids it</em>. This means we don't have to write code to filter duplicates our,
and that we don't have to write tests for it (I wouldn't test something that's
provided natively by the language) and we can focus on all the other concerns
this component has.</p>
<p>Whenever you're working with some data that has some validation requirements or
constraints it's a good idea to pause and think if you could use a data
structure that helps provide some of those constraints out the box with no extra
effort on your part.</p>
<blockquote>
<p>If you enjoyed this post, you might enjoy
<a href="http://www.jackfranklin.co.uk/avoiding-impossible-states-react/">this post on impossible states with data structures</a>.</p>
</blockquote>
Using Windows 10 and WSL for frontend web development2019-10-18T00:00:00+00:00http://www.jackfranklin.co.uk/blog/frontend-development-with-windows-10/<p>I've been an exclusively Mac developer ever since I bought a second hand MacBook
(remember the all white, plastic ones?). I absolutely loved it and as I got more
into software development and discovered the terminal it became hard for me to
see how I could go back to Windows.</p>
<p>When I started my first full time engineering role the company provided a
MacBook Pro and a Cinema Display. This was so exciting! Over the next few years
I was provided exclusively with MacBook Pros to work on (which I recognise is a
fortunate position to be in).</p>
<p>When Apple released the latest iteration of the MacBook Pro, with its touchbar
and keyboard woes, I did begin to wonder if Windows was going to end up being
something I'd have to try. Reviews online and from friends and colleagues who
had these MacBooks were not positive. About a year ago I was due a new laptop
and work and was given the newest MacBook Pro, at around the same time I was
starting to think about buying a laptop myself so I didn't rely on my work
machine for personal projects. I'm also an Android phone user, so I'm not
invested into the Apple ecosystem as others which makes the potential swap to
Windows easier, I think.</p>
<p><em>The rest of this post is very much based on my opinions: none of this is a
recommendation on what you should do. We all have different preferences and
opinions on which hardware and software combination is best for us.</em></p>
<p>Sadly I've not found the experience of the MacBook Pro to live up to either its
"Pro" naming or its "Pro" price point. Whilst I think I'm in the minority of
people who actually don't mind the butterfly keyboard I've found the software to
have some constant issues that I've struggled with. I've had the MacBook
completely shut down whilst running a workshop for 40 people because it told me
it was charging the battery despite not. I have to hard reset the machine when I
try to wake it from sleep at least once or twice a week in order to get anything
beyond a blank screen (the first time it did this I thought it had broken). I've
had regular issues with the HDMI dongle (and yes, I did pay full price for the
official Apple dongle 😢) and it not connecting properly to external screens. As
someone who does a reasonable amount of talking and teaching this has become a
real issue to the point where I considered taking a <em>backup laptop</em> because I
didn't trust the MBP to work properly.</p>
<h2>Windows and WSL</h2>
<p>I'd been following the work on WSL (Windows Subsystem for Linux) for some time
and found it a very compelling prospect; being able to run a Linux distribution
from within Windows could be a great way to make Windows more feasible for the
development work I do. Coupled with the
<a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl">VS Code WSL plugin</a>,
which makes it seamless to run VS Code with files from that Linux subsystem, I
felt it could be a viable alternative.</p>
<h2>Taking the plunge</h2>
<p>So I decided, given my MBP frustrations, to go for it. I did some research into
machines and went for a Dell XPS, which are regularly given very high reviews
online. Some (non-engineering) colleagues at work have them and spoke highly of
the machine. It worked out at ~£1000 less than the MacBook Pro cost, which I
figured was a very good saving - but only if I could work effectively on the
machine.</p>
<h2>Getting started with WSL</h2>
<p>I didn't really have a clue where to start with setting up the Windows machine.
I was fighting years of Mac muscle memory and took to Google to find posts to
point me in the right direction.
<a href="https://daverupert.com/2018/04/developing-on-windows-with-wsl-and-visual-studio-code/">Dave Rupert's post on webdev with Windows</a>
was the best blog post I found and really helped explain some things and point
me in the right direction. However, that post was written in early 2018, and
somethings have changed which means the steps are simpler now. Dave mentions
needing to install Git on the Windows side so VS Code can find it, but with the
VS Code WSL plugin that's not needed as it plugs into the <code>git</code> that you have
installed on the Linux side. I also referred to the
<a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10">official Windows WSL installation instructions</a>,
using those to verify if a blog post was up to date or not.</p>
<h2>The terminal</h2>
<p>I've been a solid fan of iTerm2 for a long time and was struggling to find a
terminal on Windows that could get close to it. I tried a few before discovering
that the next big update to Windows will include a brand new terminal app! Even
better, you can download it now from the Windows store. The
<a href="https://github.com/Microsoft/Terminal">Windows Terminal</a> has provided me with
everything I need; it can easily be configured via JSON (so I can get my custom
font in there just fine) and you can configure it to automatically connect to
your Linux distribution when it starts up, saving the need to type <code>ubuntu</code>
everytime you fire up a command line prompt.</p>
<h2>Seamless workflow</h2>
<p>The new terminal, coupled with VS Code and the Remote plugin, gets me an
experience on Windows 10 that's pretty much identical to my Mac workflow:</p>
<ol>
<li>Fire up a terminal.</li>
<li>Navigate into the project directory.</li>
<li>Run <code>code .</code> to load VS Code with that directory active.</li>
<li>Let the VS Code Remote plugin connect (this is normally quick so doesn't
cause any delays).</li>
<li>Start coding!</li>
</ol>
<p>Everything within VS Code works perfectly; if I pop open a terminal there it
will be in my Ubuntu WSL, I can use the Git UI without any fuss, and extensions
run just fine too. I've yet to hit any snags with this workflow.</p>
<h2>The frustrations</h2>
<p>The above might make it sound completely plain sailing but there have been
teething issues along the way that are worth considering if you're thinking of
trying the swap to Windows:</p>
<ul>
<li>It's a known problem that file reading/writing via WSL is much slower than it
should be. This is due to a limitation of how WSL works. The great news is
that WSL2 will fix this, but it's not out yet (unless you run an "Insiders"
build of Windows 10 that is slightly less stable). In practice I don't find
slow read/writes to be much of an issue but you can notice it, particularly if
you're npm installing.</li>
<li>This is more on me than on Windows but having used OS X exclusively for so
long it's taking some time to get used to Windows and its keyboard shortcuts.
It was definitely a few weeks before I felt comfortable and had found some 3rd
party apps that helped replicate some apps from OS X that I was missing. If
you take the plunge be prepared for a bit of frustration as you and your
muscle memory adapts.</li>
<li>I miss the Mac trackpad. The Dell one is perfectly good, but it's not quite as
nice to use. That said the <em>keyboard is so much nicer!</em> so this one evens
itself out.</li>
<li>Because I'm using this laptop for side projects and mostly frontend work I
don't hit upon any limitations of WSL but there are plenty of apps or
libraries that can cause issues when run within WSL. If you're expecting WSL
to just work with everything I would taper your expectations slightly. That
said, WSL2 supposedly fixes a lot of this (I saw a video where someone runs
Docker via WSL2, which is quite cool!) so this might get better once WSL2 is
out.</li>
</ul>
<h2>In conclusion</h2>
<p>I've been pleasantly surprised with my journey into Windows 10 so far and it's
gone much better than expected! With WSL2 and further improvements to the
developer workflow on Windows I'm excited to see where we are in another 6-12
months time. It's really exciting to see Microsoft shift and take this stuff
more seriously - and they are doing an excellent job!</p>
Frontend tech choices I'm making in 20202020-01-08T00:00:00+00:00http://www.jackfranklin.co.uk/blog/frontend-javascript-choices/<p>Happy New Year! The world of frontend web development is continually changing
with new technologies, ideas and frameworks springing up all the time. Whilst
this can get overwhelming, it's also an exciting space to be in with so much
opportunity to try new things. Today I've picked out a few libraries, languages
or ideas that I'm looking foward to trying in 2020. Some of these aren't
necessarily the new shiny thing - TypeScript has been around for a while now -
but they are all things that I think might make a big impact on the community in
the coming months.</p>
<blockquote>
<p>I'd love to hear what you're excited to work with or try in 2020!
<a href="https://www.twitter.com/Jack_Franklin">Tweet @Jack_Franklin</a> and let me know
😊</p>
</blockquote>
<h2>TypeScript</h2>
<p>In 2019 I had some mixed experiences with TypeScript. I started rebuilding
<a href="http://github.com/jackfranklin/test-data-bot">test-data-bot</a> in it (and <a href="https://javascriptplayground.com/typescript-videos-test-data-bot/">did some screencasts of the
process</a>) but on another React project ended up removing
TypeScript completely, which you can hear more about on <a href="https://fishandscripts.com/episode/season-1-episode-8-untangling-typescript/">Episode 8 of Fish and
Scripts</a>.</p>
<p>Where I've landed with my opinions <em>for now</em> is that TypeScript for me is going
to be very beneficial on standalone JavaScript libraries, like test-data-bot,
but the trade off of TypeScript's compiler catching errors compared to the
amount of hard debugging of obscure error messages when working on a large
application with many dependencies is not worth it. In my large React project
where I eventually removed TypeScript I spent more time debugging odd type
issues with React and Apollo and other dependencies than I did writing actual
application code.</p>
<blockquote>
<p>I know the TypeScript team are aware that sometimes TypeScript's errors aren't
the most readable so work in this area may well make TypeScript an even more
compelling choice.</p>
</blockquote>
<h2>Svelte</h2>
<p>Hardily a controversial choice, <a href="https://svelte.dev/">Svelte 3</a> has picked up a lot of well
deserved interest since its release. If you've not come across it I recommend
<a href="https://www.youtube.com/watch?v=AdNJ3fydeao">Rich Harris' talk at YGLF</a> as a great taster.</p>
<p>What I really like about Svelte is that it's a <em>compiler</em>. This means that when
you hit save in your editor the compiler runs and converts your Svelte
components into JavaScript code that is then executed in the browser. This isn't
what a framework like React does - in React you write JavaScript (or sometimes
JSX that is converted to JavaScript) and execute that in the browser.</p>
<p>Being a compiler, Svelte is able to spot potential issues at compile time and
let you know about them, aiding developer debugging. It's also really good at
shipping the smallest amount of JavaScript possible because Svelte is able to
take your components and intelligently compile them down into the smallest, most
performant JavaScript that it can.</p>
<p>I also love some of the defaults that Svelte ships with, primarily that CSS is
entirely scoped to each component by default. This is my preferred way of
writing CSS and it's refreshing to work with a tool that ships this out of the
box. It's a small thing but it's refreshing to not have to configure a build
tool to enable CSS Modules and instead just have the Svelte compiler do all the
work.</p>
<h2>Rollup</h2>
<p>Doing some reading into Svelte also leads naturally into <a href="https://rollupjs.org/guide/en/">Rollup</a>, a JavaScript
module bundler written by Rich Harris who is the creator of Svelte. I like
Rollup because it feels very approachable; it's very easy to create your first
bundle and very easy to add a plugin to solve a common problem such as bundling
CSS or using Babel.</p>
<p>What's really impressed me with Rollup recently is how easy <em>writing your own
plugins is</em>. This has always felt like something far beyond my capabilities in
other tools - Webpack has felt like this black box to me and I would never
consider writing a plugin for that. Rollup on the other hand has good
documentation but also the Rollup plugins you find online (many of them written
by the core team) are very easy to look at and follow. The prospect of using a
bundler that I can manipulate and customise fully to suit my specific needs is
very exciting.</p>
<blockquote class="twitter-tweet" data-lang="en-gb"><p lang="en" dir="ltr">working with Rollup has been really fun - and is incredibly easy to customise with plugins. Checkout the source code if you're interested - it's very straight forward and way easier than you might think.</p>— Jack Franklin (@Jack_Franklin) <a href="https://twitter.com/Jack_Franklin/status/1211717795085504516?ref_src=twsrc%5Etfw">30 December 2019</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>I'm excited to work with Rollup on some projects in 2020 and see how it
develops.</p>
<h2>Cloud databases</h2>
<p>I have worked as and still can build backend applications but these days for
side projects I'm often keen to shift as much of the work as possible to other
tools to let me focus on the bits that I enjoy doing the most, and make it more
likely that this side project will ever see the light of day! I've always
defaulted in the past to <a href="https://firebase.google.com/">Firebase</a> because I'm familiar with it and it's fairly
easy to work with once you're used to the core concepts, but I've always had a
bit of a gripe in that the JavaScript libraries you need to use are quite large
in file size. This is definitely an area where I'd like to find other tools that
solve this problem and make it easy to host a frontend app that requires an API
/ database without having to build and host it myself. Recommendations welcome!</p>
<h2>Letting tools make choices for me</h2>
<p>I've noticed a trend in the tools that I like: they make choices for me. I'm a
fan of Svelte (or at least, a fan enough to want to get more familiar with it)
in part because it makes nice choices out the box and decreases the amount of
thought required in getting a Svelte project running. I continue to be a strong
advocate of <a href="https://elm-lang.org/">Elm</a> because the language makes decisions for me and helps prevent
silly bugs from creeping in. I maintain that <a href="https://prettier.io/">Prettier</a> has been the most
productive change to my toolset in the last couple of years <em>because it makes so
many formatting decisions for me</em>.</p>
<p>I don't miss spending hours configuring Babel and all the myriad of plugins
required to get the exact set of features I want to have supported (to be fair,
<code>@babel/preset-env</code> has made this much easier). I don't miss trying to decide
what variant of CSS to use on this project. I've become a fan of putting more of
that burden onto the technologies I'm chosing such that I can focus in on the
actual application. I would be surprised if the tools that catch my eye in 2020
aren't ones that follow this pattern.</p>
<h2>What tech are you excited about in 2020?</h2>
<p>Let me know! It's so hard to narrow down to just a few and I'm sure there's many
that I've missed. All suggestions are welcome and I'd love to discuss with you.
Drop me a tweet!</p>
<!-- prettier-ignore-start -->
<!-- prettier-ignore-end -->
Moving domain names to jackfranklin dot co dot uk2020-01-13T00:00:00+00:00http://www.jackfranklin.co.uk/blog/moving-domain-names/<p>Back in April 2012 I registered and put the JavaScript Playground online with a first blog post about <a href="http://www.jackfranklin.co.uk/blog/using-objects-in-jquerys-css/">using objects in jQuery's <code>.css()</code> method</a>.</p>
<p>Over the years I've written over 100 posts (admittedly far less than I'd like!) about a variety of topics and have been fortunate enough to have many people say very kind things about my content and how they've found it useful. I've always found that the best part of blogging and would recommend you try to tell people if you enjoy what they've written 😊.</p>
<p>The domain gave me a lot of opportunities that I've been very fortunate to have - I wrote a book on jQuery, became a Google Developer Expert (and very soon, <a href="https://twitter.com/Jack_Franklin/status/1206544220712046593">an actual Googler</a>), sold some video courses and spoke at many conferences off the back of people finding my writing. I've been so lucky to have these chances and I'm grateful to everyone who has helped me along the way.</p>
<p>I always had a slight plan to eventually transform JavaScript Playground into a large JavaScript hub with multiple courses, paid membership (or something similar) and more writers creating more content, but that's a vast amount of work that I simply never had time (or perhaps wanted) to do.</p>
<p>In the end I found it confusing that my Twitter, GitHub, YouTube and others are all named as "Jack Franklin" but the blog wasn't. By moving all the content onto jackfranklin.co.uk it's clearer who is writing the blog posts and it's easier to map me on Twitter / at a conference / on YouTube and find me on the rest of the internet.</p>
<p>I've set up redirects from the old blog so I'm hopeful that this move doesn't create a bunch of broken links - everything should be redirected automatically.</p>
Letting tools make choices2020-01-15T00:00:00+00:00http://www.jackfranklin.co.uk/blog/letting-tools-make-choices/<p>In my
<a href="http://www.jackfranklin.co.uk/blog/frontend-javascript-choices/">first post of the year about technical choices I'm making in 2020</a>
I finished with a point about letting tools make choices for you:</p>
<blockquote>
<p>I've become a fan of putting more of that burden onto the technologies I'm
choosing such that I can focus in on the actual application. I would be
surprised if the tools that catch my eye in 2020 aren't ones that follow this
pattern.</p>
</blockquote>
<p>This has been a trend for me and my work over the last year or so and I wanted
to use this post to expand on it.</p>
<h3>Holding onto control</h3>
<p>I would never have written a post like this a few years ago. One of my main
decisions when deciding what tools to use was how much control I had over the
entire surface area of the tool and how much I could customise it to my every
need.</p>
<p>My logic at the time was that if I could configure my environment and tools to
<em>precisely</em> what I wanted, I would create this zen-like application that was set
up to enable me to be the most productive I could be.</p>
<h3>Time spent configuring</h3>
<p>My approach wasn't correct because of two things that are true of all software:</p>
<ol>
<li>Software is never finished.</li>
<li>Software is never perfect.</li>
</ol>
<p>I could never get to this perfect setup of tools because there would <em>always</em> be
something left to do! Anyone who has worked on an engineering team knows this;
teams create sprint boards and backlogs and those backlogs inevitably end up
with far more items in than your team could ever achieve. I remember sitting
down one evening after work to focus on a side project and losing the best part
of the evening trying to get two different tools that I'd chosen to use playing
nicely alongside each other. I finished for the night and realised that I'd made
<em>no progress</em>. I didn't even need those tools to work together to allow me to
make progress, but I was so concerned about having the perfect setup that I
forgot about building the actual application.</p>
<p>Once I had everything playing nicely, one of the tools would have an update
which broke something and I'd repeat the process all over again.</p>
<p>Shockingly, that project never saw the light of day (and there are many more
like it).</p>
<h3>Losing hours to extreme ESLint configuration</h3>
<p>The amount I valued control really became apparent on another side project where
I probably spent the first two hours <em>just configuring ESLint</em>. I can't tell you
how long I debated in my head between Style A or B, all while having no actual
project code and basing my decision off dummy code I was writing to test my
ESLint setup!</p>
<p>At this point as well I was <em>the only developer</em>, so why it really mattered to
me that I stuck to an incredibly strict set of rules I'm not quite sure. Yet
again I'd scuppered a side project before it had even started.</p>
<blockquote>
<p>I still use and value ESLint in my toolchain but apply far fewer rules than in
the past.</p>
</blockquote>
<h3>Working on a team</h3>
<p>When I got my first professional job out of university I joined a team who
already had a set of conventions for their code that newer members of the team
were expected to stick to (although we had a good culture where anyone could
suggest changes/new additions). It shocked me <em>how much I struggled with this</em>!
I would sit at my desk not wanting to write code or even trying to avoid certain
language features because it would frustrate me to do it "wrong". Looking back
on this it's very embarrassing to admit and silly that I got hung up on it.</p>
<h3>Deciding what to work on</h3>
<p>Once I'd worked in an engineering team for over half a year it dawned on me that
every person in every team has far more they'd like to do than they can actually
do. Regardless of company size, team size, an individual's role or experience,
there is simply too much to do.</p>
<p>Once I realised this I began to think about what I value most and what I want to
spend my time doing. At work, I like building things that people use. I like
finishing off a nice UI to help users with a particular problem. I like building
tools that other engineers use that helps them be more productive. I like
improving our acceptance tests after a bug makes it into production so it can't
happen again. That's what I like doing and it's how I have the most impact on
the company, my team, and the people who are using the products we build.</p>
<p>I decided that any work that takes me away from the core of my job and what I
like doing was not worth dedicating multiple hours to. I still care about it and
still work in this area (as I said above, we use ESLint at work to help us) but
I spend far less time than before. On side projects I'll tend to chuck
<a href="https://github.com/suchipi/eslint-config-unobtrusive">my favourite ESLint config</a>
in and be done with it so I can focus on the actual project itself.</p>
<h3>Tools that make decisions make me more productive</h3>
<p>The best example of a tool that I've come to love is
<a href="https://prettier.io/">Prettier</a>. It's far from the first code formatting tool
out there but it popularised the idea of automatic code formatting for frontend
development. Suddenly I went from strictly controlling all aspects of my code
formatting via thousands of ESLint rules to having one tool that made a set of
choices that <em>I couldn't change even if I wanted to</em>! Prettier is opinionated
and it's what I love the most. I install it, set it running and it formats my
code how it thinks it should be formatted and that's that. I don't like every
decision Prettier makes with code, but I like that its made that decision for
me.</p>
<p>The trend of <em>zero config</em> tools was perhaps overhyped slightly - there will
always be projects with edge cases and certain situations that rely on full
customisation and control - but tools that lean towards being less configurable
have tended to find their way into my toolbox.</p>
<p>For small side projects these days I'll often reach for
<a href="https://parceljs.org/">Parcel</a> as an out of the box bundler because it just
handles anything I throw at it without much effort, and it's not surprise that
<a href="https://jestjs.io/">Jest</a> has become my testing framework of choice for the
same reason.</p>
<h3>Opinions are still encouraged!</h3>
<p>Whilst I may not dedicate as much time and energy to configuring a project to
within an inch of its life that doesn't mean that I don't have opinions. I still
have strong opinions and preferences about how code should be formatted, which
ESLint rules are good (or bad) and which test framework is my favourite. I spend
a lot of time thinking about software design and what "clean code" really means.
My colleagues and I regularly debate exactly how to write a piece of code and we
definitely don't always agree.</p>
<p>I've learned that it's not about not having opinions, but instead holding onto
them less strongly.
<a href="https://medium.com/@ameet/strong-opinions-weakly-held-a-framework-for-thinking-6530d417e364">Strong opinions, weakly held</a>
is a great way to frame these discussions and allow you to have opinions but be
open to discussing them and having those opinions challenged. This process,
coupled with the practice of
<a href="https://en.wikipedia.org/wiki/Disagree_and_commit">Disagree and Commit</a> has
enabled me and my team at work to continually challenge our thoughts, opinions
and ideas whilst not getting bogged down in debating for the sake of it, or
becoming frustrated with anyone refusing to budge on their viewpoint.</p>
<h3>Tools that make decisions help beginners get up and running</h3>
<p>Preferring tools that make decisions is why I'll push people towards
<a href="https://github.com/facebook/create-react-app">create-react-app</a> if they want to
learn React but aren't sure where to start. I've seen many people try and fail
to learn React not because they aren't capable of learning React but they give
themselves a huge mountain to climb and try to learn React, Webpack, Babel, and
more <em>all at the same time!</em></p>
<p>If you're teaching beginners, or working with junior developers, encourage them
to focus on the job in hand and what's really important and let tools fill in
the gaps.</p>
<p>There's nothing wrong with someone being comfortable with React and deciding
that they would like to learn what create-react-app does under the hood, or
spending a weekend building their own rough version of React to gain a greater
understanding of the tool. But when you're just getting started it's important
to focus in on what's really important. Anything else can be deferred.</p>
<h3>Clearing your head and focusing</h3>
<p>Another benefit I've experienced is that once you offload decisions to tools
you're able to think more clearly about the problem at hand. That applies to
beginners trying to learn something new, but it applies to starting a side
project and working on what's really important.</p>
<p>I encourage you to think about this next time you load up a project at work, or
at home. Where are you spending time and energy that you can offload to
something else, freeing you up to do your best work?</p>
The three developers2020-01-27T00:00:00+00:00http://www.jackfranklin.co.uk/blog/the-three-software-developers/<p>Have you ever come across code that you wrote six months ago and thought "what
was I doing?". I know I have! And I know that in the past I've been too easy to
beat myself about past mistakes instead of reflecting on why the code I wrote
six months ago is now causing me problems.</p>
<p>Worse still I've caught myself criticising <em>someone else's</em> code that they wrote
six months ago. "I can't believe Bob wrote that, what was he thinking?!" is
<em>not</em> a thought that I'm proud of, but it's one that I've had many times.</p>
<p>In the past few years I've spent a large portion of my time tackling large
software migrations; first one from AngularJS to React, and then one from legacy
templating and jQuery to React (turns out I quite like React!). The very nature
of this work means that coming across "bad" code is guaranteed.</p>
<h3>Lacking empathy</h3>
<p>A couple of years ago a colleague gave me some candid feedback that they had
noticed that I sometimes spoke quite negatively of the codebase, or work that
had been done a long time ago. This took me by surprise but on reflection was
entirely correct; I was allowing my frustrations to cloud my judgement and
taking that frustration out in meetings on colleagues. This wasn't a good
approach and lead to me coming across as an incredibly unempathetic person to
work with. I don't think this was a true reflection but the way I was thinking
about past code - the "what IDIOT wrote this?!" approach - wasn't healthy for me
or for the team I was on.</p>
<p>After some reflection I realised that I was thinking about my past coding
efforts (or that of my colleagues) all wrong; rather than criticising and
assuming bad decisions, I should think back to what I knew <em>at the time of
making the decision</em> and what I <em>now know, at the time of criticising that prior
decision</em>. When thinking about that code I wrote six months ago along with <em>the
context in which it was written</em> it became clear that it wasn't an idiotic or
bad decision, but a reasonable one at the time. This was a big shift in my
thinking but one that lead me to a greater understanding of how we make
decisions when programming and how I should always assume good intentions given
the context of the decision.</p>
<h3>Context matters in code</h3>
<p>As a concrete example, I came across some code that short circuited various
conditionals given a certain value, and it stuck out as different to all the
code surrounding it and I couldn't figure out why it needed to short circuit in
the way it did. I did some digging, asked around, and got a solid explanation
that it had been an urgent bug fix on a Friday afternoon to fix an issue with
some bad historical data that had suddenly revealed itself. Suddenly it became
clear; the developer who wrote that code wasn't bad, they hadn't purposefully
written bad code, they had made a reasonable decision to deploy this change to
fix a bug before everyone headed home for the weekend.</p>
<h3>The three developers</h3>
<p>Knowing that decisions that seemed reasonable at the time can end up being
sub-optimal, and that we can never predict the future of how our software will
need to change, lead me to what I've found a very clear, productive way of
thinking where I don't blame myself (or others) for past mistakes and instead
place emphasis on what <em>I can learn</em> rather than <em>who I can blame</em>.</p>
<p>So when I'm writing code now I think of three developers:</p>
<ul>
<li><em>Past Jack</em></li>
<li><em>Current Jack</em></li>
<li><em>Future Jack</em></li>
</ul>
<p>And whilst I am thinking about myself as the person who wrote, or is writing,
the code, this applies to all members of the team or anyone who could encounter
or interact with code I write.</p>
<h3>Past Jack</h3>
<p>I used to think that Past Jack made loads of stupid mistakes, wrote poor
decisions and generally left code in a bad state. But now I trust that Past Jack
made those decisions with the best intentions, using the knowledge he had to
inform the decision as best he could. I like to think about what I can learn
from Past Jack; how I can see now that the code he wrote six months ago wasn't
the best solution in the long run, and how that can inform the decisions that I
make today - which brings me nicely to the next developer.</p>
<h3>Current Jack</h3>
<p>Current Jack (or, me - I get this is a bit weird to talk about myself in the
third person 😂) likes to take lessons learned from past code and try to avoid
those problems in the future. It's great to be able to look back at code that
was written three, six, twelve months ago and decide what's causing issues, what
isn't clear, and how the code could have been clearer.</p>
<blockquote>
<p>Writing code that computers understand is easy, but writing code that humans
can understand is the challenge.</p>
</blockquote>
<p>Developers spend more time reading existing code and modifying it rather than
writing brand new code from scratch so being able to take code that you (or a
colleague) wrote six months ago and get it into your head quickly is a major
productivity boost during your day.</p>
<h3>Future Jack</h3>
<p>Future Jack is always in my mind when I'm writing code because I want to give
him that productivity boost, whether that's in the form of clear code that's
easy to follow (I hope so), or a good set of unit tests that clearly document
all the expected behaviour so it's easy to refactor later, or if that's a
massive code comment explaining some odd edge case that's impossible to solve
nicely. Future Jack will be the person loading up a file to fix a bug that's
causing downtime and will be in a rush to understand and fix the problem as
quickly as possible and anything I can do now to make Future Jack's job easier -
whilst learning from Past Jack's decisions - is worth doing.</p>
<h3>We're all learning</h3>
<p>One of my favourite things about being a software engineer is that it's never
finished. There is never a perfect approach that applies equally to every type
of problem, or a particular framework that solves every issue any developer will
ever have. We're all learning, making mistakes, fixing them, and trying to make
life just a little bit easier for our future selves or colleagues.</p>
Using ftplugin to tidy my Vim configuration2020-05-10T00:00:00+00:00http://www.jackfranklin.co.uk/blog/using-ftplugin-in-vim/<p>I've used Vim on and off for a long time. I got introduced to it at University
by a lecturer, tried it, didn't get it, and moved on. I then decided to learn it
more seriously and spent a lot of time configuring it, as my
<a href="https://github.com/jackfranklin/dotfiles">dotfiles repository</a> shows. It's on
1203 commits!</p>
<p>Often in Vim you'll want to have different settings for different filetypes.
Foexample I want to configure Markdown files to have spell-check turned on at
all times, but when I'm coding I don't care for spell-check being on.</p>
<p>In the past I would have done this with an <code>autocmd</code>:</p>
<pre><code>autocmd FileType markdown setlocal spell spelllang=en_gb
</code></pre>
<p>But then your <code>vimrc</code> (or <code>init.vim</code> for Neovim users like me!) gets cluttered
with these and it's hard to keep up, or find exactly where you configured those
Markdown settings.</p>
<p>Instead, you can use ftplugins for this case! A <code>ftplugin</code> is a file type plugin
that will be run automatically when Vim detects you're editing a file of that
type.</p>
<p>So instead of cluttering up my <code>vimrc</code> with <code>autocmd</code> lines, I can instead
create <code>~/.config/nvim/ftplugin/markdown.vim</code> with the settings I want in:</p>
<pre><code>setlocal spell spelllang=en_gb
</code></pre>
<blockquote>
<p>If you're using Vim, not Neovim, you can create
<code>~/.vim/ftplugin/markdown.vim</code>.</p>
</blockquote>
<p>This keeps my <code>vimrc</code> tidy, and my dotfiles easier to manage. It's very
straightforward to remember which settings I've applied globally (they are in my
<code>vimrc</code>) or per-filetype, in which case I can dive into my <code>ftplugin</code>s folder.</p>
Learning keyboard shortcuts with Post-it notes2020-05-13T00:00:00+00:00http://www.jackfranklin.co.uk/blog/learning-with-post-its/<p>I like keyboard shortcuts. I use Vim to edit code, which is entirely keyboard
based, and generally I feel better and more productive if I can use the keyboard
to get things done on my computer.</p>
<p>But I've always found learning new keyboard shortcuts hard, particularly if I've
already found another way to solve my problem already. Let's say I use an app
and a core piece of my workflow involves two consecutive keyboard shortcuts. One
day I learn that I can perform the same action in a single command. Great!
Except I have that two-consecutive shortcut workflow committed to muscle memory
and changing that is going to be really hard.</p>
<p>It turns out that the answer for me is Post-it notes! I've been using this
technique for many years and it's worked well for me. Each week or two I'll try
to find a few shortcuts that I'd like to adopt into muscle memory and learn.
I'll stick them on a Post-it on my monitor as a constant reminder. I don't
always remember to use them, but I remember more and more as time goes by until
the Post-it becomes redundant. This is how I learned Vim; I didn't attempt to
learn the myriad of commands at once, but instead picked a few each week that I
wanted to get used to using.</p>
<p>Right now I'm trying to get better at using
<a href="https://ianyh.com/amethyst/">Amethyst</a>. It's a tiling window manager for MacOS,
and has a load of shortcuts. I've not been good at remembering the shortcuts for
moving focus around windows (instead reaching for <code>Cmd+tab</code> or my mouse) and I
don't make use of spaces as much as I'd like. So guess what I've just added to
my desk?</p>
<p><img src="http://www.jackfranklin.co.uk/images/post-its.jpg" alt="Post-its at my desk with keyboard shortcuts"></p>
<p>If you've ever struggled to commit things to memory, I recommend giving this a
go!</p>
Refactoring to remove passthrough variables2020-05-19T00:00:00+00:00http://www.jackfranklin.co.uk/blog/refactoring-to-remove-passthrough-variables/<p>I've been working recently on <a href="https://github.com/puppeteer/puppeteer">Puppeteer</a> and migrating it to TypeScript. This
has presented the opportunity to do some refactoring and today I want to share a
recent refactoring I did to remove <em>passthrough variables</em>.</p>
<h3>What is a passthrough variable?</h3>
<p>A passthrough variable is a variable that gets passed through multiple method
calls before it gets given to the actual place in which it's used.</p>
<p><img src="http://www.jackfranklin.co.uk/images/passthrough.svg" alt=""></p>
<p>Normally these happen either because:</p>
<ul>
<li>the object that needs the data is unable to create it</li>
<li>the object that creates the data (in the above example, <code>A</code>), used to need it,
but now doesn't due to a change in functionality or behaviour.</li>
</ul>
<blockquote>
<p>Whilst we're not specifically talking about React in this post, you see this
happen a lot with React props. This is known as
<a href="https://kentcdodds.com/blog/prop-drilling/">"prop drilling"</a> and is also
something you should be wary of.</p>
</blockquote>
<h3>Dealing with passthrough variables</h3>
<p>It's important to note that passthrough variables are not always avoidable, and
often they are the preferred solution. The fix for passthrough variables can be
simple - moving the creation of the value to the place where it's needed is the
easiest fix - but if you're constrained often the explicitness of passthrough
variables is preferable to any other solution.</p>
<p>Whilst it makes you jump through a hoop or two, the below code is explicit and
does tell the full story about what's happening:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token punctuation">{</span><br> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SomeValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>b <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">B</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br><span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token punctuation">{</span><br> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span>c <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">C</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br><span class="token keyword">class</span> <span class="token class-name">C</span> <span class="token punctuation">{</span><br> <span class="token comment">// somewhere in C we use the value</span><br><span class="token punctuation">}</span></code></pre>
<p>It's definitely not the nicest code you've ever seen but it can be methodically
followed. Any solution that creates a method for <code>C</code> to access the variable
without the explicitness of passing the values through will introduce some
indirection for a developer to follow. For example, if you chose to put the
value on the global scope (<em>I do not recommend this, but it's a useful
example!</em>), you have to figure where that value comes from:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">C</span> <span class="token punctuation">{</span><br> <span class="token function">doSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// woah, where does this come from?!!</span><br> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>globalStuff<span class="token punctuation">.</span>value<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Even a more sophisticated approach like React's
<a href="https://reactjs.org/docs/context.html">Context API</a> still suffers from this
problem. <em>Often this is a good trade-off and worth taking</em> but it's still
something you have to consider. As always in building software there is no
silver bullet!</p>
<h3>Fixing the simple case</h3>
<p>Thankfully for me the specific case I was tackling in the <a href="https://github.com/puppeteer/puppeteer">Puppeteer</a> codebase
was easier to deal with; there was no reason to not create the data in the same
place that it was needed. This is the best fix; taking code that's spread across
three files and moving it into a single file is nearly always an improvement
because it's simply less to keep in your head at any given time.</p>
<p>Taking a look at the
<a href="https://github.com/puppeteer/puppeteer/pull/5826/files">pull request that made the change</a>
you can see that we came out net-negative in terms of lines of code (not always
the most useful metric but good here) and we simplified classes in the process.
In the case of Puppeteer we had:</p>
<ul>
<li><code>BrowserContext</code> create a <code>TaskQueue</code> and initialise a <code>Target class</code>, passing
the queue instance.</li>
<li>The <code>Target</code> class took that <code>TaskQueue</code> instance and passed it into the
<code>Page</code> constructor.</li>
<li>The <code>Page</code> class made use of the queue instance.</li>
</ul>
<p>Not only is this very mechanical code to pass all these values through, it's
also polluting multiple classes with knowledge that they don't need. The only
class above that <em>actually cares</em> about a <code>TaskQueue</code> is <code>Page</code>. But because we
create that value in <code>BrowserContext</code> both it and <code>Target</code> now have to know
about a task queue and how to pass it around. So not only does this change
remove lines of code, but it reduces the amount of classes that have to know
about the task queue by 66%!</p>
<p>And if that wasn't enough, <code>BrowserContext</code> has one fewer instance variable,
<code>Target</code> has one fewer instance variable and constructor argument, and <code>Page</code>
has one fewer constructor argument to. So this one small PR packs in a good
punch in terms of reducing the complexity of the code.</p>
<p>Keep an eye out for situations like this; they are often left behind as an
accidental by-product of refactorings and they can provide an easy, low risk way
to remove some confusion from your codebase.</p>
Writing tests for bad JavaScript code2020-05-26T00:00:00+00:00http://www.jackfranklin.co.uk/blog/writing-tests-for-bad-javascript-code/<p>I like refactoring code and thinking about software design. It's something I
speak about, blog about and enjoy doing as part of my job day to day. A core
part of any refactoring is knowing that you haven't broken any functionality and
the best way to have confidence in that is by having a set of tests you can run
to ensure you've not broken anything.</p>
<p>But what do you do when there are no tests? You should never dive into a
refactoring without tests, but how do you ensure that you've got good tests?
Today we're going to look at some code we've stumbled across and want to
refactor, and how we first take the step of adding tests.</p>
<blockquote>
<p>The example code below is taken from a <em>fantastic</em> talk by Katrina Owen titled
<a href="https://www.youtube.com/watch?v=J4dlF0kcThQ">"Therapeutic Refactoring"</a> which
I highly recommend. It's such a good example that I've adapted it to
JavaScript to use for this blog post.</p>
</blockquote>
<h3>The code: generating filenames for books</h3>
<p>Here's the code we've been asked to work with. We're working at a publishers and
this code generates the filename for the front cover of a given book (or
<em>target</em>). There's some features we need to add to this code, but for now we
just need to understand it. Feel free to take a moment to give it a read.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">Publisher</span> <span class="token punctuation">{</span><br> <span class="token keyword">static</span> <span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">let</span> fileName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>target<span class="token punctuation">.</span>publishOn<span class="token punctuation">.</span><span class="token function">getFullYear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>target<span class="token punctuation">.</span>publishOn<span class="token punctuation">.</span><span class="token function">getMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span><br> <span class="token number">1</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br><br> fileName <span class="token operator">+=</span> target<span class="token punctuation">.</span>categoryPrefix<br> fileName <span class="token operator">+=</span> target<span class="token punctuation">.</span>kind<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">'_'</span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><br> fileName <span class="token operator">+=</span> <span class="token function">String</span><span class="token punctuation">(</span>target<span class="token punctuation">.</span>id<span class="token punctuation">)</span><br> fileName <span class="token operator">+=</span> Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">length</span><span class="token operator">:</span> <span class="token number">5</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token parameter">_</span> <span class="token operator">=></span><br> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><br><br> <span class="token keyword">let</span> truncatedTitle <span class="token operator">=</span> target<span class="token punctuation">.</span>title<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">[^\[a-z\]]</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token keyword">let</span> truncateTo <span class="token operator">=</span> truncatedTitle<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">9</span> <span class="token operator">?</span> <span class="token number">9</span> <span class="token operator">:</span> truncatedTitle<span class="token punctuation">.</span>length<br> fileName <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>truncatedTitle<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> truncateTo<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br> fileName <span class="token operator">+=</span> <span class="token string">'.jpg'</span><br><br> <span class="token keyword">return</span> fileName<br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>There's a lot going on here! It looks like we generate the name based on the
published date, the category, the type of book, some random digits, and then the
title which we truncate if needed. It's clear that this code could do with some
attention; it's not the easiest to read or follow. The first step is to try and
clarify all the behaviour that we have so we can test it. But right now we don't
have a single test! So let's attempt to write one.</p>
<h3>Writing our first test</h3>
<p>I've spoken before about descriptive tests, but in this case we don't even know
what we're testing! In this case I like to start really basic and just prove to
myself that this code even works:</p>
<pre class="language-js"><code class="language-js"><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">'Publisher'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'does a thing'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>We know that <code>generateFilename</code> takes a target, so we can try to make a fake
target as best we can. If we mess it up, we'll get errors from the tests telling
us what we missed.</p>
<pre class="language-js"><code class="language-js"><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">'Publisher'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'does a thing'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> fileName <span class="token operator">=</span> Publisher<span class="token punctuation">.</span><span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">publishOn</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2021</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token literal-property property">categoryPrefix</span><span class="token operator">:</span> <span class="token string">'tech'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">kind</span><span class="token operator">:</span> <span class="token string">'software-design'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">123</span><span class="token punctuation">,</span><br> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Software Design'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> <span class="token function">expect</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">'???'</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>But what about the assertion? We have no idea what the output will be. In this
case I like to write an obviously wrong output and watch the test fail. The
failure will show us what we're actually expecting!</p>
<pre class="language-bash"><code class="language-bash">Expected: <span class="token string">"???"</span><br>Received: <span class="token string">"2021-4techsoftware-design12358113-softwared.jpg"</span></code></pre>
<p>OK, so let's drop that name into our assertion and hopefully the test should
pass. Well unfortunately:</p>
<pre class="language-bash"><code class="language-bash">Expected: <span class="token string">"2021-4techsoftware-design12358113-softwared.jpg"</span><br>Received: <span class="token string">"2021-4techsoftware-design12369199-softwared.jpg"</span></code></pre>
<p>Random numbers like this can derail a test, but thankfully there's a workaround.
We can expect our output to match a regex where we hardcode everything bar the 5
digits that are random:</p>
<pre class="language-js"><code class="language-js"><span class="token function">expect</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatch</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">2021-4techsoftware-design123[0-9]{5}-softwared\.jpg</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">)</span></code></pre>
<p>And now we are passing! Phew. Whilst this felt like a bit of a slog we're now in
a great position. We have at least one test, and now we're ready to figure out
the other set of tests that we'll need.</p>
<h3>Finding branches in the code</h3>
<p>When you're trying to write test cases that flush out all the possible edge
cases you should look for conditionals in the code. These are effectively all
the branches that you're trying to test. Each <code>if</code> becomes two test cases: one
that tests the positive side and one for the negative side.</p>
<p>The first conditional we hit adds the <code>ageRange</code> to the file name if the book is
personal:</p>
<pre class="language-js"><code class="language-js">fileName <span class="token operator">+=</span> target<span class="token punctuation">.</span>isPersonal <span class="token operator">?</span> target<span class="token punctuation">.</span>ageRange <span class="token operator">:</span> <span class="token string">''</span></code></pre>
<p>Our first test case didn't include this, so let's make sure we test this and
include the age range in the assertion:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'includes the age range if the book is personal'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> fileName <span class="token operator">=</span> Publisher<span class="token punctuation">.</span><span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">publishOn</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2021</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token literal-property property">ageRange</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span><br> <span class="token literal-property property">isPersonal</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span><br> <span class="token literal-property property">categoryPrefix</span><span class="token operator">:</span> <span class="token string">'kids'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">kind</span><span class="token operator">:</span> <span class="token string">'childrens-book'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">123</span><span class="token punctuation">,</span><br> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Five go on an Adventure'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatch</span><span class="token punctuation">(</span><br> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">2021-4kidschildrens-book123[0-9]{5}10-fivegoona\.jpg</span><span class="token regex-delimiter">/</span></span><br> <span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>The next conditional is the truncation:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> truncatedTitle <span class="token operator">=</span> target<span class="token punctuation">.</span>title<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">[^\[a-z\]]</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br><span class="token keyword">let</span> truncateTo <span class="token operator">=</span> truncatedTitle<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">9</span> <span class="token operator">?</span> <span class="token number">9</span> <span class="token operator">:</span> truncatedTitle<span class="token punctuation">.</span>length<br>fileName <span class="token operator">+=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>truncatedTitle<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> truncateTo<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span></code></pre>
<p>Our first test case used the title 'Software Design' which is greater than 9
characters long, so this behaviour is being tested already. So let's add another
test case that uses a really short title and confirms it does not get truncated.</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'does not truncate titles less than 9 characters long'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> fileName <span class="token operator">=</span> Publisher<span class="token punctuation">.</span><span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">publishOn</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2021</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token literal-property property">categoryPrefix</span><span class="token operator">:</span> <span class="token string">'bio'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">kind</span><span class="token operator">:</span> <span class="token string">'biography'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">123</span><span class="token punctuation">,</span><br> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Jack'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatch</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">2021-4biobiography123[0-9]{5}-jack\.jpg</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<blockquote>
<p>There's other behaviour here yet to be tested - that regex in particular looks
interesting - but right now we are only after branches.</p>
</blockquote>
<p>Those are all the conditionals that we've come across so let's have a look at
where we're up to with our tests:</p>
<pre class="language-js"><code class="language-js"><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">'Publisher'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'does a thing'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'includes the age range if the book is personal'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'does not truncate titles less than 9 characters long'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>We can now rename the <code>'it does a thing'</code> test; that test actually tests that
truncation works with titles greater than 9 characters long. Notice how we
didn't know that at the time but we do now. Let's update it's description
accordingly:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'truncates titles greater than 9 characters long'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></code></pre>
<p>Now we have three passing tests and our conditionals dealt with, let's look at
other edge cases or particularly interesting bits of behaviour that we'd like to
test.</p>
<h3>Looking for other edge cases and changes in behaviour</h3>
<p>Now we're scanning the code looking for things that we'd like to test. And we
hit a good candidate on line 1; including the year and month in the output. What
we now have to consider is is this worth writing a specific test for, or are the
current suite of tests sufficient? This is where some personal preference comes
in; I'd argue that every test will test this date logic, as it's not conditional
on anything else, so we can leave this be.</p>
<pre class="language-js"><code class="language-js">fileName <span class="token operator">+=</span> target<span class="token punctuation">.</span>kind<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">'_'</span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span></code></pre>
<p>This is the first line that makes me want to write a test. If the <code>kind</code> has an
underscore in, it will be removed. We also hit a curious issue here: what if
there are multiple underscores? This code will only replace the first instance,
not all of them. This would be the sort of thing I'd note down for later; to
check if this is desired or a bug in the implementation. <strong>When you're writing
tests for code you don't understand, don't fix anything at first. Get good test
coverage and note down any potential bugs you find along the way</strong>.</p>
<p>Here I make sure I write a test where <code>kind</code> has an underscore and assert that
it's been removed in the output. I then also write a test that confirms if there
are multiple underscores only the first is removed, because I'd like to document
that behaviour even if we then ultimately decide that it's a bug (at which point
we can update the test).</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'removes the first underscore from the kind'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> fileName <span class="token operator">=</span> Publisher<span class="token punctuation">.</span><span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">publishOn</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2021</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token literal-property property">categoryPrefix</span><span class="token operator">:</span> <span class="token string">'bio'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">kind</span><span class="token operator">:</span> <span class="token string">'self_biography'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">123</span><span class="token punctuation">,</span><br> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Title'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatch</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">2021-4bioselfbiography123[0-9]{5}-title\.jpg</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><br><br><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'does not remove any subsequent underscores from the kind'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> fileName <span class="token operator">=</span> Publisher<span class="token punctuation">.</span><span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">publishOn</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2021</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token literal-property property">categoryPrefix</span><span class="token operator">:</span> <span class="token string">'bio'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">kind</span><span class="token operator">:</span> <span class="token string">'self_bio_graphy'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">123</span><span class="token punctuation">,</span><br> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Title'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatch</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">2021-4bioselfbio_graphy123[0-9]{5}-title\.jpg</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>The next thing that strikes me is this line:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> truncatedTitle <span class="token operator">=</span> target<span class="token punctuation">.</span>title<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">[^\[a-z\]]</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre>
<p>Or specifically, <em>this regex</em>:</p>
<pre class="language-js"><code class="language-js"><span class="token punctuation">[</span><span class="token operator">^</span>\<span class="token punctuation">[</span>a<span class="token operator">-</span>z\<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token operator">/</span>gi</code></pre>
<p>This regex (we think) is supposed to match anything that isn't a letter. In the
code anything that matches is replaced by nothing, and we note that the <code>/gi</code>
makes it global (every match will be replaced) and case insensitive. But what's
curious here is that the inner braces are escaped:</p>
<pre class="language-bash"><code class="language-bash"><span class="token punctuation">\</span><span class="token punctuation">[</span>a-z<span class="token punctuation">\</span><span class="token punctuation">]</span></code></pre>
<p>So this regex also looks like it will leave any braces in the title. This <em>seems
unlikely</em> so we note this as a potential bug, but given it is coded behaviour,
let's write a test to prove that braces do remain. We'll also write another test
that has a funky title full of special characters to ensure they get removed:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'does not remove braces or letters from the book title'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> fileName <span class="token operator">=</span> Publisher<span class="token punctuation">.</span><span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">publishOn</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2021</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token literal-property property">categoryPrefix</span><span class="token operator">:</span> <span class="token string">'bio'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">kind</span><span class="token operator">:</span> <span class="token string">'biography'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">123</span><span class="token punctuation">,</span><br> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'My [Title]'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatch</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">2021-4biobiography123[0-9]{5}-my\[title\]\.jpg</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><br><br><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'removes other special characters from the book title'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> fileName <span class="token operator">=</span> Publisher<span class="token punctuation">.</span><span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">publishOn</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2021</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token literal-property property">categoryPrefix</span><span class="token operator">:</span> <span class="token string">'bio'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">kind</span><span class="token operator">:</span> <span class="token string">'biography'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">123</span><span class="token punctuation">,</span><br> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'(My) <title$>'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatch</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">2021-4biobiography123[0-9]{5}-mytitle\.jpg</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>And that's the last part of behaviour that leaps out at us as worth testing.</p>
<h3>Conclusion</h3>
<p>With that we now have 7 tests that describe and specify the functionality that
<code>generateFilename</code> gives us:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'truncates titles greater than 9 characters long'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'includes the age range if the book is personal'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'does not truncate titles less than 9 characters long'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'removes the first underscore from the kind'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'does not remove any subsequent underscores from the kind'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'does not remove braces or letters from the book title'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'removes other special characters from the book title'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>We also think we might have found some bugs along the way:</p>
<ul>
<li>Is it deliberate that only the first <code>_</code> gets removed from the <code>kind</code> of the
<code>target</code>?</li>
<li>Similarly, are braces meant to be included as part of the title's output? Or
is that a typo when defining the regex?</li>
</ul>
<p>Although it's tempting to fix these "bugs" as you go, remember that the entire
point of this work is to clarify the code's behaviour in order to make
improvements. Resist the urge to make improvements as you go; once you have a
thorough test suite it's much easier to make decisions on where to go and if you
start making changes you've got a good set of tests to ensure you don't break
any functionality.</p>
<p>Now we have the tests it's time to look at the feature request we've been asked
to implement and how we go about doing that. Keep an eye out for next week's
blog post where we'll do just that!</p>
<blockquote>
<p>Thanks again to Katrina Owen and her
<a href="https://www.youtube.com/watch?v=J4dlF0kcThQ">Therapeutic Refactoring talk</a>
which was the inspiration for writing up this blog post. I highly recommend
watching it!</p>
</blockquote>
Refactoring JavaScript with tests2020-06-18T00:00:00+00:00http://www.jackfranklin.co.uk/blog/refactoring-javascript-code-with-tests/<p>In
<a href="http://www.jackfranklin.co.uk/blog/writing-tests-for-bad-javascript-code/index.html">the last post we tackled writing tests for bad JavaScript code</a>
and now we have tests covering the behaviour of our code we are ready to do some
refactoring and improve the code to make it easier to work with.</p>
<p>The code at hand generates filenames for media associated with a book. Here's
one of the tests to jog your memory:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> fileName <span class="token operator">=</span> Publisher<span class="token punctuation">.</span><span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">publishOn</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2021</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token literal-property property">categoryPrefix</span><span class="token operator">:</span> <span class="token string">'tech'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">kind</span><span class="token operator">:</span> <span class="token string">'software-design'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">123</span><span class="token punctuation">,</span><br> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'Software Design'</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token function">expect</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatch</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">2021-4techsoftware-design123[0-9]{5}-softwared\.jpg</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">)</span></code></pre>
<p>What motivated this refactoring is that we've been asked by our manager to make
a change to this output. Each individual section in the filename should be
separated by a dash (<code>-</code>). In the above output you can see that this happens
inconsistently on different parts of the output. Right now this would be a very
manual bit of work to take all the string concatenation and add dashes. Let's
see if we can follow <a href="https://twitter.com/KentBeck">Kent Beck</a>'s advice and do our work
as two separate steps:</p>
<ol>
<li>Do the work to make the change easy (note: this may be hard).</li>
<li>Do the easy change.</li>
</ol>
<blockquote>
<p>It's a common misconception that you need to carve out explicit time to
refactor code; instead try to think of refactoring as work to be done to make
a new feature easier and quicker to implement. That's also much easier to
convey to stakeholders!</p>
</blockquote>
<h3>Making the change easy</h3>
<p>If we think of the filename as a series of parts then we can start to make
progress. We know that we have the tests to confirm that everything is working,
and our goal now is to make a series of changes to improve the code. Our steps
should be small, and we should run the tests after every change. We want to know
ASAP if we've broken anything!</p>
<blockquote>
<p>Have you ever broken your app and frantically started undoing things to try to
get back to a state where it was working? Or been midway through a refactor
and had loads of broken tests? Try to get into the habit of making small
changes and running your tests <em>after every one</em> to help you become aware of
any issues the moment they crop up. It's much easier to undo immediately
rather than backtrack through changes.</p>
</blockquote>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">Publisher</span> <span class="token punctuation">{</span><br> <span class="token keyword">static</span> <span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">let</span> fileName <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>target<span class="token punctuation">.</span>publishOn<span class="token punctuation">.</span><span class="token function">getFullYear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><br> target<span class="token punctuation">.</span>publishOn<span class="token punctuation">.</span><span class="token function">getMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><br> <span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br> <span class="token comment">// more code here</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>The first change I'm going to do is to split each part of the filename
generation into its own function. Let's take that first part and pull it into a
function:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">publishDatePart</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>target<span class="token punctuation">.</span>publishOn<span class="token punctuation">.</span><span class="token function">getFullYear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>target<span class="token punctuation">.</span>publishOn<span class="token punctuation">.</span><span class="token function">getMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span></code></pre>
<p>And then call it:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">Publisher</span> <span class="token punctuation">{</span><br> <span class="token keyword">static</span> <span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">let</span> fileName <span class="token operator">=</span> <span class="token function">publishDatePart</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><br> <span class="token comment">// more code here</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Running the tests confirms we've not broken anything. Another good guiding
principle here is that when refactoring, you should be able to stop and have
left the code in a better place than when you found it. Although it's only a
small step, it's easier to figure out and deal with this code now it's pulled a
little bit apart, so we've made an improvement.</p>
<h3>Pulling out all the functions</h3>
<p>I'll spare you the details of each function but this is what we're left with
after taking the step above multiple times:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">Publisher</span> <span class="token punctuation">{</span><br> <span class="token keyword">static</span> <span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">let</span> fileName <span class="token operator">=</span> <span class="token function">publishDatePart</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><br><br> fileName <span class="token operator">+=</span> target<span class="token punctuation">.</span>categoryPrefix<br> fileName <span class="token operator">+=</span> <span class="token function">kindPart</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><br><br> fileName <span class="token operator">+=</span> <span class="token function">String</span><span class="token punctuation">(</span>target<span class="token punctuation">.</span>id<span class="token punctuation">)</span><br> fileName <span class="token operator">+=</span> <span class="token function">randomPart</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> fileName <span class="token operator">+=</span> target<span class="token punctuation">.</span>isPersonal <span class="token operator">?</span> target<span class="token punctuation">.</span>ageRange <span class="token operator">:</span> <span class="token string">''</span><br><br> fileName <span class="token operator">+=</span> <span class="token function">titlePart</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><br> fileName <span class="token operator">+=</span> <span class="token string">'.jpg'</span><br><br> <span class="token keyword">return</span> fileName<br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">titlePart</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">let</span> truncatedTitle <span class="token operator">=</span> target<span class="token punctuation">.</span>title<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">[^\[a-z\]]</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token keyword">let</span> truncateTo <span class="token operator">=</span> truncatedTitle<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">9</span> <span class="token operator">?</span> <span class="token number">9</span> <span class="token operator">:</span> truncatedTitle<span class="token punctuation">.</span>length<br> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>truncatedTitle<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> truncateTo<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br><span class="token punctuation">}</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">randomPart</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">length</span><span class="token operator">:</span> <span class="token number">5</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">_</span><span class="token punctuation">)</span> <span class="token operator">=></span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><br> <span class="token string">''</span><br> <span class="token punctuation">)</span><br><span class="token punctuation">}</span><br><span class="token keyword">const</span> <span class="token function-variable function">kindPart</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> target<span class="token punctuation">.</span>kind<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">'_'</span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><br><br><span class="token keyword">const</span> <span class="token function-variable function">publishDatePart</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>target<span class="token punctuation">.</span>publishOn<span class="token punctuation">.</span><span class="token function">getFullYear</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>target<span class="token punctuation">.</span>publishOn<span class="token punctuation">.</span><span class="token function">getMonth</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><br><span class="token punctuation">}</span></code></pre>
<p>It's really important during this part of work that you resist the urge to
change any of the code. The bodies of the functions are exactly as they were
before; I've just extracted them into functions. Some of them we might not even
get to refactoring today; but that's OK, we're still making great progress and
the code is far more approachable for the next time we come to work on it. And
more importantly, we're now ready to make our feature change!</p>
<h3>Making a feature change</h3>
<p>I like to be driven by tests, so knowing that we're going to have more dashes in
the output than we do currently, let's go through each test and update it so
they have dashes in the places we expect. Here's one example:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'removes other special characters from the book title'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> fileName <span class="token operator">=</span> Publisher<span class="token punctuation">.</span><span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">publishOn</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token number">2021</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token literal-property property">categoryPrefix</span><span class="token operator">:</span> <span class="token string">'bio'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">kind</span><span class="token operator">:</span> <span class="token string">'biography'</span><span class="token punctuation">,</span><br> <span class="token literal-property property">id</span><span class="token operator">:</span> <span class="token number">123</span><span class="token punctuation">,</span><br> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">'(My) <title$>'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>fileName<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatch</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">2021-4-bio-biography-123-[0-9]{5}-mytitle\.jpg</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>If we run the tests now, all seven are failing! Let's see if we can get them
back to passing. If you find this overwhelming, often I'll pick just one single
test (in Jest you can change an <code>it</code> to <code>it.only</code> and have only that test run).
This way you don't have a huge output and once you have one test passing you can
run the rest.</p>
<p>The first thing we'll do is go through each individual part and remove any
dashes that are currently output. This way we'll make them all uniform - no
individual part will be responsible for adding dashes. Then we can easily make
it so we take all the parts and combine them with a dash. As it happens we only
have to do this to <code>titlePart</code>, where we can lose the string interpolation
return just the title part:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">titlePart</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">let</span> truncatedTitle <span class="token operator">=</span> target<span class="token punctuation">.</span>title<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">[^\[a-z\]]</span><span class="token regex-delimiter">/</span><span class="token regex-flags">gi</span></span><span class="token punctuation">,</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token keyword">let</span> truncateTo <span class="token operator">=</span> truncatedTitle<span class="token punctuation">.</span>length <span class="token operator">></span> <span class="token number">9</span> <span class="token operator">?</span> <span class="token number">9</span> <span class="token operator">:</span> truncatedTitle<span class="token punctuation">.</span>length<br> <span class="token keyword">return</span> truncatedTitle<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> truncateTo<span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>Now we can make the easy change to get us back to green. Let's create an array
for all the book's parts and join those together with a dash as the joining
character:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">class</span> <span class="token class-name">Publisher</span> <span class="token punctuation">{</span><br> <span class="token keyword">static</span> <span class="token function">generateFilename</span><span class="token punctuation">(</span><span class="token parameter">target</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> parts <span class="token operator">=</span> <span class="token punctuation">[</span><br> <span class="token function">publishDatePart</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">,</span><br> target<span class="token punctuation">.</span>categoryPrefix<span class="token punctuation">,</span><br> <span class="token function">kindPart</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token function">String</span><span class="token punctuation">(</span>target<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token function">randomPart</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span><br> target<span class="token punctuation">.</span>isPersonal <span class="token operator">?</span> target<span class="token punctuation">.</span>ageRange <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">,</span><br> <span class="token function">titlePart</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>Boolean<span class="token punctuation">)</span><br><br> <span class="token keyword">const</span> extension <span class="token operator">=</span> <span class="token string">'.jpg'</span><br> <span class="token keyword">return</span> parts<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'-'</span><span class="token punctuation">)</span> <span class="token operator">+</span> extension<br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>There's one slight "gotcha" that I miss the first time; without the
<code>filter(Boolean)</code> we include the empty string should <code>target.isPersonal</code> be
<code>false</code>, which means we end up joining the empty string with dashes and get
doubles. But once we spot that, we're green again and have our feature
implemented.</p>
<h3>Conclusion</h3>
<p>There's much more we could do here; the code is by no means perfect. But it is
much cleaner than it was, it's got a comprehensive suite of tests, and by
pulling out its functionality into smaller methods we have put in place the
foundations to further iterate on this code when we next need to add a feature.
That extra time spent writing tests has paid off now, and it will continue to
pay off time and time again whenever we revisit this part of the codebase.</p>
Learning from mistakes2020-06-23T00:00:00+00:00http://www.jackfranklin.co.uk/blog/learning-from-mistakes/<p><em>Today I'm kicking off a new series on writing and maintaining JavaScript
software titled "Designing Good JavaScript" by looking at learning at our
mistakes. I hope you enjoy this post and the series!</em></p>
<p>How many times have you loaded up a file in your codebase to make some quick
changes, only to be confused by the choices you made six months ago? How many
times has that architecture you worked so hard on in the past come back to bite
you? How often do you find yourself bemoaning a section of the codebase to a
colleague, thinking that the only way to solve it is a complete rewrite?</p>
<p>The good news is that if you answered "yes" to any of those questions, you're
not alone, and you have something in common with me! I've spent the most part of
my career maintaining large JavaScript applications and what I've come to
realise is that <strong>it's easy to write code you can understand now, but hard to
write code you'll understand in six months.</strong> The best engineers I've worked
with aren't the best because they know every API method under the sun, or
because they can turn five lines of code into two with a clever <code>reduce</code> call,
but because they write <strong>code that they (and their colleagues) can understand
now and code that can be understood in the future.</strong> They have an awareness of
how a particular decision now can impact your velocity further down the line and
an ability to predict problems before they happen.</p>
<p>How do these engineers get this ability? <strong>Experience.</strong> They don't foresee
problems because they are able to look into a crystal ball, or experience
premonitions of the future like that kid in Final Destination, but because
they've been there, done that, countless times. How do they know that a
particular approach might backfire? Because two years ago working at Company X,
it did.</p>
<p>The good news is that whilst there is no substitute for experience and learning
from your mistakes
(<a href="http://www.jackfranklin.co.uk/blog/the-three-software-developers/">and being nice to yourself in the process</a>)
there are many people, including yours truly, willing to share their mistakes
and lessons learned from them. No engineer knows everything, and no engineer
makes the right decision on software every time. Opinions on software are formed
over time as we write code, make decisions, and learn what works and what
doesn't. That's what this series is all about. Over the coming weeks I'll be
sharing opinions and stories from when a software decision backfired - or when
one really paid off - so that you can keep them in your back pocket when the
next time a similar decision has to be made. I'll reflect on teams that I've
worked on that have executed efficiently, and teams who have got bogged down in
process, and everything inbetween. Think of this as a series where I share my
experiences so that you can take them and use them to inform your decisions.
There's no lecturing here.</p>
<p>If you've got any questions, comments, feedback, or just want to say hello,
<a href="https://www.twitter.com/Jack_Franklin">get in touch with me on Twitter</a>. I'm
excited to share these articles and would love to hear what you think, or any
suggestions for content.</p>
VSCode Productivity: The Magit plugin2020-06-25T00:00:00+00:00http://www.jackfranklin.co.uk/blog/vscode-productivity-git-magit/<p>Over the next few weeks I'm going to be sharing some videos demonstrating parts
of my workflow in VSCode - from managing changes with git (today's video), to
reviewing pull requests, to running tests, and so on.</p>
<p>Today I want to share the
<a href="https://marketplace.visualstudio.com/items?itemName=kahole.magit">Magit plugin</a>
for VSCode. It's based on the Magit plugin in Emacs (which I have not used) and
aims to provide an easy to use interface to manage git changes and commits. I've
found it a really great addition to my workflow and I highly recommend giving it
a go.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/kDISNtPYhjk" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" class="youtube"></iframe>
<p><em>You can also watch this video
<a href="https://www.youtube.com/watch?v=kDISNtPYhjk">directly on Youtube</a>.</em></p>
<p>If you've got any questions, comments, feedback, or just want to say hello,
<a href="https://www.twitter.com/Jack_Franklin">get in touch with me on Twitter</a>.</p>
Keeping Code Simple2020-06-30T00:00:00+00:00http://www.jackfranklin.co.uk/blog/keep-javascript-code-simple/<p>When I think about keeping code simple, I think about the progression of your
average software engineer from junior to mid to senior, and this one commonly
mentioned part of that journey:</p>
<ul>
<li><strong>Junior engineer</strong>: writes function implementation over multiple lines,
favouring simple method calls and comments over succinctness. Probably misses
some chances to improve the performance or readability, or doesn't use the
best API method for the task at hand, but the code works.</li>
<li><strong>Mid level engineer</strong>: condenses the function down to as few lines as
possible, using smart coding tricks to reduce lines. Code works, maybe even
performs faster than the junior's version, but is likely harder to understand
or modify.</li>
<li><strong>Senior engineer</strong>: implements function much more closely to the junior;
their code is straightforward, uses the right API methods, ensures good
performance - but doesn't prematurely optimise - and is easy to understand and
modify.</li>
</ul>
<p>I've seen this pattern play out multiple times - and I've been each of those
engineers. I remember refactoring some code in a pull request that a junior
developer on our team wrote, thinking I was so smart. I made so many
improvements - and got it down from 10 lines to 4! That's fantastic, I thought.
The change got merged into the code base and not long after it was largely
reverted back to its original state because people needed to work with that
code, and working with such succinct code with so much squashed into just four
lines was nearly impossible. I learned a good lesson that day: <strong>lines of code
are not a good metric of code quality.</strong></p>
<p>I think about this
<a href="https://twitter.com/jaffathecake/status/1213077702300852224">tweet about using reduce by Jake Archibald</a>
often:</p>
<blockquote>
<p>All code using <code>array.reduce</code> should be rewritten without <code>array.reduce</code> so
it's readable by humans</p>
</blockquote>
<p>Whether or not you agree about the specifics of the
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce">reduce function</a>
isn't important, but the sentiment behind Jake's tweet is. You're not writing
code to impress your colleagues. The "smartness" of your code doesn't matter.
The readability of your code does. Keep code simple and it will be less effort
to understand, less effort to change, and less frustrating to work with. Traits
of simple code include (but are not limited to) the list below:</p>
<ul>
<li>All variables and functions are named based on their behaviour / functionality
and are easy to follow.</li>
<li>Any functions in the code take a reasonable amount of arguments; no function
is so large that it needs five or more arguments to perform its job.</li>
<li>Appropriate API methods are used for the task at hand and API methods are used
over custom implementations.</li>
<li>Using the right data structures to represent your application's data.</li>
<li>Comments are left if appropriate to add context and convey meaning that can't
be conveyed via code alone.</li>
<li>"Smart" shortcuts are not used; you don't have to google the obscurities of
JavaScript's syntax to understand what the code does.</li>
<li>Where code perhaps has to be less readable for performance reasons there is a
comment that explains this and ideally links to a document/email/Slack
thread/your company's internal wiki that adds context.</li>
</ul>
<p>If some of those points feel a bit vague, don't worry. It's hard to summarise in
one quick list; we will be diving into each of the topics above in a dedicated
blog post.</p>
<p>Sometimes, code just cannot be made simple. Maybe you're working with a horrible
legacy API whose interface is bizarre in every way possible, or you're stuck on
an old version of a library that you can't upgrade for a variety of reasons.
Most codebases I've worked on have had a rough edge or a dark corner that
developers shy away from. We'll look at techniques to tackle this too and
migrate away from dark dingy corners to codebases and modules that are a
pleasure to work on.</p>
<p>If you've got any questions, comments, feedback, or just want to say hello,
<a href="https://www.twitter.com/Jack_Franklin">get in touch with me on Twitter</a>.</p>
VSCode Productivity: The rewrap plugin2020-07-02T00:00:00+00:00http://www.jackfranklin.co.uk/blog/vscode-productivity-rewrap-plugin/<p>Over the next few weeks I'm going to be sharing some videos demonstrating parts
of my workflow in VSCode - from managing changes with git (today's video), to
reviewing pull requests, to running tests, and so on.</p>
<p>Today I want to share the
<a href="https://marketplace.visualstudio.com/items?itemName=stkb.rewrap">rewrap plugin</a>
for VSCode. It's a fantastic tool for easily wrapping code comments, Git
commits, or Markdown files to a certain line length and I use it <em>all the time</em>
when writing documentation in code.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/1YDuBhSQglQ" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" class="youtube"></iframe>
<p><em>You can also watch this video
<a href="https://www.youtube.com/watch?v=1YDuBhSQglQ">directly on Youtube</a>.</em></p>
<p>If you've got any questions, comments, feedback, or just want to say hello,
<a href="https://www.twitter.com/Jack_Franklin">get in touch with me on Twitter</a>.</p>
How code gets bad2020-07-07T00:00:00+00:00http://www.jackfranklin.co.uk/blog/how-javascript-code-gets-bad/<p>We've all been there. The one corner (or maybe there's multiple!) of your
application that makes you cringe every time you have to touch that part of the
code. The proposed feature that you hope doesn't make it into the prioritised
list of work because implementing it means diving deep into the guts of the
nasty corner of your codebase that is hard if not impossible to work on with
confidence.</p>
<p>At one company I worked at I had a very frustrated product manager exclaim
"Jack, it feels like whenever I propose a new feature on [site area X], you tell
me it can't be done". The unfortunate truth was that it couldn't; that area of
the site functioned just fine but no one could tell you how or work on it
confidently without causing other bugs. The problem with areas of the site like
this is that they only get worse once they start deteriorating into what I like
to call "quick hack territory" which normally goes something like this:</p>
<ol>
<li>An event happens that causes knowledge and confidence of a feature to be
lost; this could be the developer who built it moving on, a huge quick
rewrite to meet a rushed deadline, or a 3rd party dependency becoming
unmaintained.</li>
<li>The next developer who has to work on that part of the codebase doesn't have
a solid knowledge, or they are up against a tight deadline, so they rush and
"hack" their change into place. They mean to come back to it later - as we
all do - but other work gets in the way.</li>
<li>The next person who touches this area sees the previous person hacked their
way to success and either:
<ol>
<li>decides this code is in need of some attention to get it back to a
satisfactory standard</li>
<li>decides that time pressures are too great and they hack their feature in
too</li>
</ol>
</li>
<li>Rinse and repeat - but every time you don't give the code the attention it
needs, you're making it worse.</li>
</ol>
<p>I want to be very clear: I'm not criticising any of the hypothetical developers
above who made that decision to get their feature out no matter the cost. We
have all been there, whether the pressures be deadlines, start-up fundraising
rounds, a big company event where the latest features have to have landed, and
so on. Sometimes taking the short-cut and sacrificing some code quality is the
right decision and sometimes it simply has to be done for the business.</p>
<p>What we'll spend a lot of time in this series of blog posts talking about is not
only what makes good code, but how to turn bad code into good code in an
incremental way, a path of small improvements that transform your bad corners
into glorious palaces (I'm stretching this analogy but roll with me!) that you
look forward to working on. <strong>Big bang rewrites are not the way forward and
should be a last resort.</strong> They are expensive, full of risk and deliver no value
until the day comes to release them. Instead we can use a variety of techniques
to migrate from within, starting small and growing with every deploy. This is a
technique I've used many times and whilst it can be slow and frustrating at
times it's also a reliable way to improve your system bit by bit whilst keeping
risk low and ultimately your users and stakeholders happy as you replace the
engine as the car runs smoothly.</p>
<p>If you've got any questions, comments, feedback, or just want to say hello,
<a href="https://www.twitter.com/Jack_Franklin">get in touch with me on Twitter</a>.</p>
Better code reviews2020-07-09T00:00:00+00:00http://www.jackfranklin.co.uk/blog/how-to-do-good-code-reviews/<p>When you get a code review request from a colleague, what do you focus on? What
reaches the bar for what you consider something that's worth commenting on? And
do you make it clear when you're making a comment on something vs considering
something so important to change that the code review shouldn't be merged
without it?</p>
<p>Code review is hard. I've seen people do it really well and people do it really
badly, but most of us are somewhere in the middle. Giving feedback to people is
hard, and it takes practice to be comfortable taking feedback on that large
piece of code you've spent the last couple of days thinking about. Code reviews
are so crucial to a team's pace, but also their happiness. I've seen bad code
reviews become almost infamous and hurt a team's culture because people start to
feel unsafe sharing their code for review. A good code review process gets you
better code in the codebase whilst at the same time boding your team, increasing
knowledge sharing and providing a great opportunity for team members to learn
from each other.</p>
<p>With that in mind, here's some things I've learned that have helped me improve
code review - both reviews that I get from others, and reviews I give others:</p>
<ul>
<li>
<p><strong>Automate as much of code review as you can</strong>. Code review isn't for comments
on syntax, or the use of single quotes over double quotes, or for spotting
variables that aren't used. Use ESLint or other such tools rigorously to
enforce your team's coding styles, and reach for a code formatter like
Prettier that auto-formats code to a style. Not everyone may not love every
formatting choice, but that doesn't matter. Time spent arguing the amount of
spaces to indent is not worth it.</p>
</li>
<li>
<p><strong>As the creator of the code, leave comments or links to context where it
makes sense</strong>. We've all made a change that has a piece of code that seems odd
on first glance. Maybe you have to implement some really odd logic that
doesn't make sense until you really dig in, or you had to work around a
browser bug and apply a weird CSS trick to get it to look just right. Someone
reviewing your code is going to see those oddities and ask about them. I like
to proactively comment on my own code reviews with links to
documentation/screenshots/etc that explain why the code is how it is (I often
do this in actual code comments rather than comments on GitHub). That doesn't
mean the code can't be improved, but it saves some back and forth explaining
things to the reviewer. If the reviewer has more context they can spend less
time figuring that out and more time thinking about your approach and any
potential issues it might cause.</p>
</li>
<li>
<p><strong>Assume good intent</strong>. If you're reviewing some code and you can't understand
why the author did it the way they did, one of two things is true: either the
author is a dreadful developer, or they have some context that you don't. And
hopefully it's incredibly unlikely to be the former! They might have tried it
three other ways before settling on that option, or there might be a
requirement for the change that you've misunderstood. Never be afraid to ask
for clarity or check your understanding of something. I learn nearly as much
about a codebase from my colleague's code changes that I review as I do by
making changes myself.</p>
</li>
<li>
<p><strong>Make it clear if you're requesting a change or making a suggestion</strong>. Most
code review comments fall into one of two categories: something you noticed
but don't feel that strongly about, or comments that you think absolutely
should be fixed before merging the change. If you can make it clear in each
comment how strongly you feel about it, and if it's a suggestion the author
should feel free to ignore if they disagree, or if it's something that must be
fixed. That way as the person going through your review on my code I can
easily see the most important comments and focus on those, and I know when to
initiate a discussion if I disagree with your suggestion, or when you're
leaving a comment that I can choose to ignore or not.</p>
</li>
</ul>
<p>We'll definitely be revisiting the topic of code reviews in future blog posts;
they are a great way to think about the code you're writing and its potential
confusion points (in my head I like to think "what would a reviewer say about
this?" or "what is non-obvious to the person reviewing this code?") to help me
improve my code.</p>
<p>In the mean time, I'd love to hear about your team's practices when it comes to
code review; feel free to
<a href="https://www.twitter.com/Jack_Franklin">let me know on Twitter</a>.</p>
Testing event listeners in JavaScript2020-07-14T00:00:00+00:00http://www.jackfranklin.co.uk/blog/testing-event-listeners-javascript/<p>Testing JavaScript code that's asynchronous can prevent its own set of
challenges that you have to ensure you deal with when writing your tests.</p>
<p>I recently came across a test that fell foul to the asynchronous code it was
trying to test and in this post I'll show you how to look out for these tests
and how to fix it.</p>
<h3>The problem</h3>
<p>Let's imagine we're working on an API that lets you make requests to load pages
in a web browser. We have a <code>Page</code> class that provides the <code>makeRequest</code> method
that will emit a <code>request_started</code> event:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> EventEmitter <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'events'</span><span class="token punctuation">)</span><br><br><span class="token keyword">class</span> <span class="token class-name">Page</span> <span class="token keyword">extends</span> <span class="token class-name">EventEmitter</span> <span class="token punctuation">{</span><br> <span class="token function">makeRequest</span><span class="token punctuation">(</span><span class="token parameter">url</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">emit</span><span class="token punctuation">(</span><span class="token string">'request_started'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> url <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>This means any other part of this codebase can listen out for these events:</p>
<pre class="language-js"><code class="language-js">page<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'request_started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">/* do something here */</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>This is useful functionality, so let's write a test for it:</p>
<pre class="language-js"><code class="language-js"><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">'Page class'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'emits an event when a request is started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Page</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br><br> page<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'request_started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> page<span class="token punctuation">.</span><span class="token function">makeRequest</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>This test passes, but it's hiding a problem. What happens if we deliberately
break it? If we remove the <code>this.emit</code> line, look what the test outputs:</p>
<pre><code>PASS src/site/code-for-posts/async-tests/async-tests.test.js
Page class
✓ emits an event when a request is started (6 ms)
</code></pre>
<p>This is less good 😒. But why does it pass?</p>
<p>If we take a look at the test body, think about what happens when the
<code>request_started</code> event never fires. Which of the lines below will end up being
executed?</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'emits an event when a request is started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Page</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br><br> page<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'request_started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> page<span class="token punctuation">.</span><span class="token function">makeRequest</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>Because our <code>expect</code> call is within the event listener callback, it never runs
if the event never fires! This is problematic because most test frameworks
assume a test that doesn't explicitly fail is passing. Most test frameworks
won't notify you if your test never actually makes an assertion.</p>
<blockquote>
<p>You can catch these tests earlier by following this habit: when you write a
test and it passes, <strong>deliberately try to make it fail</strong>. When you write a new
test, <strong>see it fail at least once</strong> to have confidence that you're testing the
right thing.</p>
</blockquote>
<p>Luckily there's a couple of ways we can fix this test.</p>
<h3>Solution one: <code>expect.assertions</code></h3>
<p>If we're using Jest, we have access to
<a href="https://jestjs.io/docs/en/expect.html#expectassertionsnumber"><code>expect.assertions</code> and <code>expect.hasAssertions</code></a>.
These tell Jest to fail the test if there are not the amount of assertions
you're expected, which is a great way to catch the case where you have an
asynchronous assertion that doesn't run. If we update this test and let it fail
we can see the output and now the test is failing, catching the issue with the
implementation code.</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'emits an event when a request is started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Page</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> expect<span class="token punctuation">.</span><span class="token function">assertions</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><br><br> page<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'request_started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> page<span class="token punctuation">.</span><span class="token function">makeRequest</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>And Jest will let us know that there were no assertions:</p>
<pre><code>FAIL src/site/code-for-posts/async-tests/async-tests.test.js
Page class
✕ emits an event when a request is started (2 ms)
● Page class › emits an event when a request is started
expect.assertions(1)
Expected one assertion to be called but received zero assertion calls.
</code></pre>
<p>Now we avoid having a test that passes and hides an actual bug in our code.</p>
<h3>Solution two: a spy</h3>
<p>A <code>spy</code> function is one that records every time it's called, and remembers the
arguments it was given, and what value it returned. You can create a spy based
on a real function in your codebase, or you can generate one on the fly to use
in a test. We can create a spy for our event handler, and in our test write code
to assert that it's called with the right arguments. We're going to use Jest's
API to create a spy (Jest calls them "mocks", but they are mostly the same,
don't worry too much about the different terminology). If you're not using Jest
I highly recommend <a href="https://sinonjs.org/releases/v9.0.2/spies/">SinonJS</a> which
is a great library for creating spies.</p>
<p>We can use <code>jest.fn()</code> to create a spy, and pass it in as the event handler:</p>
<pre class="language-js"><code class="language-js"><span class="token function">describe</span><span class="token punctuation">(</span><span class="token string">'Page class'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'emits an event when a request is started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Page</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token keyword">const</span> handler <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br><br> page<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'request_started'</span><span class="token punctuation">,</span> handler<span class="token punctuation">)</span><br> page<span class="token punctuation">.</span><span class="token function">makeRequest</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br><br> <span class="token function">expect</span><span class="token punctuation">(</span>handler<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>Notice our new assertion for this test:</p>
<pre class="language-js"><code class="language-js"><span class="token function">expect</span><span class="token punctuation">(</span>handler<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span></code></pre>
<p>This means our test will fail unless our handler is called exactly one time. You
can use the <code>toBeCalled()</code> assertion, and that will pass if the handler is
called one or more times. More often than not I prefer to be strict and use
<code>toBeCalledTimes(1)</code>. I want this test to fail if the handler is somehow called
5 times!</p>
<p>With this change we also get a test failure:</p>
<pre><code> FAIL src/site/code-for-posts/async-tests/async-tests.test.js
Page class
✕ emits an event when a request is started (2 ms)
● Page class › emits an event when a request is started
expect(jest.fn()).toBeCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
16 | page.makeRequest('www.foo.com')
17 |
18 | expect(handler).toBeCalledTimes(1)
| ^
19 | })
20 | })
</code></pre>
<p>Compare this test failure to the one when we used <code>expect.assertions</code>. Notice
that it's more descriptive. The other test failed with a vague message that one
assertion was expected and none were found, whereas this test fails and even
provides a code snippet that points us to the exact line where the failure was.
If you're debugging this test failure, the second error message is more useful
and is likely to point you at the problem sooner.</p>
<blockquote>
<p>You should think about error messages when writing your tests - how can you
write a test to improve the message shown when the test fails?</p>
</blockquote>
<p>There's one more improvement we can make to this test; rather than just ensuring
it's called, we can assert that it's called with the right data:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'emits an event when a request is started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Page</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token keyword">const</span> handler <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br><br> page<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'request_started'</span><span class="token punctuation">,</span> handler<span class="token punctuation">)</span><br> page<span class="token punctuation">.</span><span class="token function">makeRequest</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br><br> <span class="token function">expect</span><span class="token punctuation">(</span>handler<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>handler<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeCalledWith</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'www.foo.com'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>This is a thorough test; we ensure it's called once, and with the right
arguments.</p>
<h3>The structure of a test</h3>
<p>I have
<a href="http://www.jackfranklin.co.uk/blog/the-perfect-javascript-unit-test/">blogged before about the structure of the perfect unit test</a>
and the examples today highlight how important that is. A unit test has three
distinct parts to it, in this exact order:</p>
<ol>
<li><strong>Setup</strong>: prepare any test data</li>
<li><strong>Invoke</strong>: call the code you want to test</li>
<li><strong>Assert</strong>: make assertions on the result</li>
</ol>
<blockquote>
<p>This is also known as the
<a href="https://www.thephilocoder.com/unit-testing-aaa-pattern/">"AAA pattern": arrange, act, assert</a>.</p>
</blockquote>
<p>If we look at our initial, flawed test that we started with, that does not
follow the three steps:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'emits an event when a request is started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// Setup</span><br> <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Page</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br><br> page<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'request_started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// Assert</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> <span class="token comment">// Invoke</span><br> page<span class="token punctuation">.</span><span class="token function">makeRequest</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>It's in completely the wrong order! It's odd to read; your eyes have to start at
the top, go to the bottom, and then jump right into the middle again.</p>
<p>Even the test that used <code>expect.assertions()</code> has the same problems:```js</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'emits an event when a request is started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// Setup</span><br> <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Page</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token comment">// Assert</span><br> expect<span class="token punctuation">.</span><span class="token function">assertions</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><br><br> page<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'request_started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// Assert (again)</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> <span class="token comment">// Invoke</span><br> page<span class="token punctuation">.</span><span class="token function">makeRequest</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>It's only the final version of our test that uses spies that has our three steps
in the right order:</p>
<pre class="language-js"><code class="language-js"><span class="token function">it</span><span class="token punctuation">(</span><span class="token string">'emits an event when a request is started'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token comment">// Setup</span><br> <span class="token keyword">const</span> page <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Page</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token keyword">const</span> handler <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br><br> <span class="token comment">// Invoke</span><br> page<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'request_started'</span><span class="token punctuation">,</span> handler<span class="token punctuation">)</span><br> page<span class="token punctuation">.</span><span class="token function">makeRequest</span><span class="token punctuation">(</span><span class="token string">'www.foo.com'</span><span class="token punctuation">)</span><br><br> <span class="token comment">// Assert</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>handler<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><br> <span class="token function">expect</span><span class="token punctuation">(</span>handler<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBeCalledWith</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'www.foo.com'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>If a test isn't following these three steps, there's almost certainly an
improvement that can be made to make it adhere to the steps. They've become a
well known pattern for a reason; a test that has these steps in their logical
order is more likely to be a useful, readable test, and as we've seen in this
blog post, give more useful failure messages.</p>
Writing good comments: the why, not the how2020-07-28T00:00:00+00:00http://www.jackfranklin.co.uk/blog/code-comments-why-not-how/<p>Code comments often get a bad reputation amongst developers as a waste of time,
or a sign that your code could be improved. Here's a quote from a
<code>CONTRIBUTING.md</code> file I found on GitHub (and there's many, many more like it):</p>
<blockquote>
<p>Comments should be avoided. If the code cannot be understood without comments,
re-write the code to make it self-explanatory.</p>
</blockquote>
<p>I think this is pretty poor, incorrect advice the vast majority of the time. I
think this stems back to most people's experience learning code. I have a strong
memory of a lecturer in my first term of my Computer Science degree (although
you'll find this advice in many courses, regardless of if it's University or
not) telling us:</p>
<blockquote>
<p>Every line of code should have a comment explaining what it does. Your
upcoming coursework will be marked on this criteria.</p>
</blockquote>
<p>So, if you're a new student fresh into the course, what do you do? You comment
your code of course!</p>
<pre class="language-js"><code class="language-js"><span class="token comment">// set the input value from the ENV value bar</span><br><span class="token keyword">const</span> inputValue <span class="token operator">=</span> process<span class="token punctuation">.</span><span class="token constant">ENV</span><span class="token punctuation">.</span>bar<br><br><span class="token comment">// now multiply it by 2</span><br><span class="token keyword">const</span> newValue <span class="token operator">=</span> inputValue <span class="token operator">*</span> <span class="token number">2</span><br><br><span class="token comment">// now pass it to the square function</span><br><span class="token keyword">const</span> finalValue <span class="token operator">=</span> <span class="token function">square</span><span class="token punctuation">(</span>newValue<span class="token punctuation">)</span><br><br><span class="token comment">// this function squares a number and returns the new number</span><br><span class="token keyword">const</span> <span class="token function-variable function">square</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">x</span><span class="token punctuation">)</span> <span class="token operator">=></span> x <span class="token operator">*</span> x</code></pre>
<p>The people who say that comments are bad are thinking of this style of
commenting, and <em>they'd be absolutely right!</em> Comments like this that describe
the "how" of programming add absolutely no value. Each of those comments above
added nothing that couldn't be understood from the code immediately below it.</p>
<h3>Comment the <em>why</em></h3>
<p>The problem with the comments above is that they comment the <em>how.</em> They
describe the steps we take. Those comments are very rarely useful; code does a
good job at explaining how we do something. After all, lines of code are
instructions to tell the computer how to do something.</p>
<p>Most of the time you'll find that you don't need to leave a myriad of comments
because you can write the code you want to and you don't hit any oddities or
quirks that cause the code to look unusual. But every now and then you'll hit a
situation where you can't write code that's easy to understand. Maybe it's a bug
that you're working around, or maybe it's a legacy system that means you can't
solve the problem how you'd like, or maybe there's just no easy way to make the
code better.</p>
<p>I once worked for a payments processing company and each day a large SQL query
would run to select payments to pay-out. This query was highly optimised (we
needed it to run pretty quickly) and very complex - there were a number of edge
cases to consider. We put a lot of effort into making it as clear as it possibly
could be, but ultimately it would never be easy to understand, there was just
too much code with lots of conditionals and logic that you'd only understand
with certain context about our business and how it ran.</p>
<p>I wanted to find an example that I could show you, so I went diving into the
React codebase to find one. You don't need to be a React developer to follow
along. Here's the code I wanted to highlight:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token comment">// Currently, key can be spread in as a prop. This causes a potential</span><br><span class="token comment">// issue if key is also explicitly declared (ie. <div {...props} key="Hi" /></span><br><span class="token comment">// or <div key="Hi" {...props} /> ). We want to deprecate key spread,</span><br><span class="token comment">// but as an intermediary step, we will use jsxDEV for everything except</span><br><span class="token comment">// <div {...props} key="Hi" />, because we aren't currently able to tell if</span><br><span class="token comment">// key is explicitly declared to be undefined or not.</span><br><span class="token keyword">if</span> <span class="token punctuation">(</span>maybeKey <span class="token operator">!==</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> key <span class="token operator">=</span> <span class="token string">''</span> <span class="token operator">+</span> maybeKey<br><span class="token punctuation">}</span></code></pre>
<p>(<a href="https://github.com/facebook/react/blob/ddcc69c83b59ef0f895aa5020196e2ae9de36133/packages/react/src/ReactElement.js#L217">And here's the link to it on GitHub</a>).</p>
<p>Notice the code in question:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">if</span> <span class="token punctuation">(</span>maybeKey <span class="token operator">!==</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> key <span class="token operator">=</span> <span class="token string">''</span> <span class="token operator">+</span> maybeKey<br><span class="token punctuation">}</span></code></pre>
<p>It's not hard to understand what this code does. If <code>maybeKey</code> is not
<code>undefined</code>, we set the <code>key</code> property to the stringified version of <code>maybeKey</code>.</p>
<blockquote>
<p>The string conversion is a little JS trick - <code>'' + maybeKey</code> will convert
<code>maybeKey</code> to a string. For example <code>'' + 2</code> returns <code>"2"</code>.</p>
</blockquote>
<p>But here it's all about the <em>why.</em> The comment for this code is great. It calls
out the problem, gives two examples and explains the long term plan as well as
the short term solution.</p>
<p>If you're after a comment that I left in code I wrote,
<a href="https://source.chromium.org/chromium/chromium/src/+/master:third_party/devtools-frontend/src/scripts/component_bridges/generate_closure.ts;l=60?originalUrl=https:%2F%2Fcs.chromium.org%2F">this comment in some TypeScript => Closure Compiler code</a>
is a really good example of the types of comments that I think are super
valuable.</p>
<p>All code can eventually be understood; code is ultimately instructions to the
computer to do something. Code can be confusing but it can't lie, given enough
time any developer can step through code and work out exactly <em>what it does</em>.
But it's much harder to work out <em>why</em> it does that. Give your colleagues (or
future you, in six months time) the context behind <em>why</em> the code does what it
does and you'll be much better for it.</p>
Software Development on Windows 10 with WSL22020-12-20T00:00:00+00:00http://www.jackfranklin.co.uk/blog/software-javascript-development-windows-10-wsl/<p>Back in
<a href="http://www.jackfranklin.co.uk/blog/frontend-development-with-windows-10/">October 2019 I'd taken the plunge and tried Windows for my development work</a>.
It was largely a succesful experiment. By using the
<a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10">Windows Subsystem for Linux (WSL)</a>,
I was able to run most of my tools effectively in Linux, something I'm familiar
with, and with
<a href="https://code.visualstudio.com/docs/remote/wsl">VSCode's WSL Remote plugin</a>, I
could run VSCode in Windows connected to the Linux environment provided by WSL,
and things felt very familiar.</p>
<h3>Shortcomings of WSL</h3>
<p>That said, there were some minor issues and frustrations with WSL and this
workflow. The main one was that WSL 1 was known to be much slower at file reads
and writes. You might think this isn't a huge deal - but if you're running a
package manager like <code>npm</code> and installing a bunch of dependencies, those reads
and writes add up to the point where it's noticably slow (and I'm running on a
fairly beefy XPS laptop).</p>
<p>WSL 1 also had some holes in terms of application support, you couldn't use
Docker - not something I do regularly, but something that's useful to be able to
reach for - and at times I found the VSCode WSL integration to be slightly
laggy. Not much, and not often, but everything wasn't <em>quite</em> as smooth as it
would be on the MacBook I usually worked on.</p>
<h3>Enter WSL 2</h3>
<p>WSL 2 (see an <a href="https://www.youtube.com/watch?v=MrZolfGm8Zk">intro video here</a>)
promised major improvements over WSL 1. I can't go into the details of the
implementation, because frankly it's way over my head, but from the learnings of
the successes and failures of WSl 1 Microsoft were able to make amazing
improvements in WSL 2.
<a href="https://docs.microsoft.com/en-us/windows/wsl/compare-versions#:~:text=WSL%202%20provides%20the%20benefits,user%20experience%20as%20WSL%201.">This comparsion on the MS site shows all the differences</a>,
but the highlight for me was that file IO performance was drastically improved -
the docs quote 2-5x faster for running tools such as <code>git</code> or <code>npm</code>. I haven't
benchmarked, but running WSL 2 feels <em>so much snappier</em> and I don't feel a
noticable delay when running a large <code>npm install</code>. Additionally, WSL 2's
architectural changes enable it to run many, many more apps, so using tools like
Docker is now possible.</p>
<p>And, you could upgrade a WSL 1 install to WSL 2, so the upgrade path was super
smooth!</p>
<h3>Starting fresh</h3>
<p>Given all the experimenting I'd done when I first got the laptop to get WSL 1
installed (I had to install a Windows Insider build to get it, whereas now WSL
is available on the regular build), and the fact that the laptop was a bit
bogged down with various bits of software and accumulated "stuff", I decided
last week to completely reformat the machine and start a fresh.</p>
<p>For my future reference, for when I do it again or get a new machine, and for
others who may be interested in doing software development on Windows 10, I
decided to document the steps I took. Spoiler: there actually aren't that many!</p>
<h3>Reinstalling Windows 10</h3>
<p>You can install Windows however you like; my XPS came with a recovery disk,
which I got at via "Reset this PC" in System Settings. That let me do a factory
reset of the machine and left me with it running the same version that it was
when it first shipped to me. That was a super smooth process, but left me with a
Windows that was over a year out of date, so the first thing I did was let the
software updater do its thing. Many downloads and restarts later, I had a fresh,
up to date Windows 10 all ready to go.</p>
<h3>Browser and 1Password</h3>
<p>I'm a big fan of <a href="https://www.1password.com/">1Password</a> for storing all my
passwords and the main way I access it is via the Google Chrome extension, so my
first port of call is to download Chrome and sign in so all my extensions,
including 1Password, get synced.</p>
<h3>WSL 2 and Ubuntu</h3>
<p>I run the Ubuntu distro on WSL 2, but these steps should be the same regardless
of which distro you'd like to run. I followed
<a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10">this guide on the Microsoft site</a>.
It's got a fair few steps - you first have to enable WSL 1, then upgrade to WSL
2 (I'm not sure if in time this will change), then download a kernel update (far
less scary than it sounds), before setting the default version to WSL 2, and
<em>finally</em> then installing Ubuntu.</p>
<blockquote>
<p>The docs mention that if you're on the Windows Insiders build, you can use the
experimental <code>wsl --install</code> command.</p>
</blockquote>
<p>This process is a bit manual and takes a few minutes as some of the steps
require a restart of your machine, but it's just a case of following the
instructions carefully and you'll be up and running.</p>
<h3>The Windows Terminal</h3>
<p>One of my major sticking points for Windows was the lack of a good terminal
application. On OS X / Linux there's a great choice between the built in
defaults, iTerm 2 (Mac) or others such as Alacritty (cross platform).</p>
<p>Thankfully Microsoft are rectifying that with the
<a href="https://docs.microsoft.com/en-us/windows/terminal/get-started">Windows Terminal</a>,
which is looking great! Whilst it's still got a few rough edges (primarily a
lack of a settings interface, so you configure it via a JSON file only) it's
really come a long way and I highly recommend it. When you run it, it will load
a Windows Powershell by default, but you can
<a href="https://docs.microsoft.com/en-us/windows/terminal/customize-settings/global-settings#default-profile">customise the default profile</a>,
so I've set it to load my Ubuntu WSL 2 environment by default.</p>
<h3>VSCode</h3>
<p>VSCode is my editor of choice and is really the best option on Windows for me
because of the previously mentioned WSL integration. I donwload this onto
Windows and then use the
<a href="https://code.visualstudio.com/docs/editor/settings-sync">VSCode settings sync</a>.
This used to require an extension to VSCode but is now built-in, and I use this
to sync settings between my machines. This means I can download VSCode, log in
and sync, and then all my extensions and settings will be downloaded for me. If
you use VSCode, I highly recommend syncing your settings. Even if you only use
one machine at all times, it's a great way to back up your settings should you
have to reformat your machine in the future.</p>
<h3>Diving into Ubuntu</h3>
<p>At this point I've now got everything set up on the Windows side, and I fire up
the Windows Terminal to get the Ubuntu environment configured. These steps are
largely personal preference, but the tools I reach for are:</p>
<ol>
<li><a href="https://fishshell.com/">Fish</a> as my shell, along with
<a href="https://github.com/jorgebucaran/fisher">Fisher</a> for managing the plugins. I
use <code>chsh -s (which fish)</code> to change the default shell to Fish, so when I
load up the terminal it loads into Fish by default.</li>
<li>I use <a href="https://asdf-vm.com/">asdf</a> to manage all my versions of various
languages, such as Node. I like asdf because it works well, never conflicts
with other tools, and can be used to manage loads of languages - so I don't
have to have separate tools for Ruby, Node, etc, but just use asdf for
everything. I then immediately install Node as that's the main language I
rely on.</li>
<li>I then install the
<a href="https://github.com/cli/cli/blob/trunk/docs/install_linux.md">GitHub CLI</a>. I
love using this to create and clone repositories
(<code>gh repo clone jackfranklin/dotfiles</code>) and also <code>gh pr create</code> to create
pull requests.</li>
<li>I install my <a href="https://github.com/jackfranklin/dotfiles">dotfiles</a> which I've
built up over the years and they have plenty of little snippets that I rely
on, including my custom
<a href="https://github.com/jackfranklin/dotfiles/blob/master/fish/config.fish#L1">aliases</a>
which I have safely in muscle memory and help me go quicker through the
terminal.</li>
<li>I follow the
<a href="https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent#generating-a-new-ssh-key">GitHub guide</a>
to generate a new SSH key (I can <em>never</em> remember the steps!) and add that to
my GitHub profile, so I'm ready to clone, push and pull against both my
public and private repositories.</li>
</ol>
<h3>Conclusion</h3>
<p>I find Windows 10 a great environment to be productive in; the improvements to
WSL 2 along with the ability of VS Code to connect seamlessly to it to create an
environment that is pretty close to the Linux environments I usually have set-up
on the Mac machines I normally work on.</p>
<p>With
<a href="https://www.zdnet.com/article/microsoft-linux-gui-apps-coming-to-windows-10-wsl-along-with-gpu-access/">WSL set to gain the ability to run Linux GUI apps</a>
it's exciting to see how Windows 10 and WSL progresses in the next few years.</p>
Remapping Keys on Windows 10 with Power Toys2020-12-27T00:00:00+00:00http://www.jackfranklin.co.uk/blog/remapping-keyboard-keys-windows-10-power-toys/<p>Since moving to Windows 10 something I've always struggled with is how to remap
keys on a keyboard. I don't remap much, but one remapping that I've used now for
about ten years is that I remap <code>Caps Lock</code> to <code>ESC</code>. This started when I was
learning Vim, and has become so commited to muscle memory that I can't go back
from it and I'm rendered useless on any machine that doesn't have this mapped!</p>
<p>On Mac OS this remapping was easy; the keyboard settings lets you remap certain
keys, and tools like <a href="https://karabiner-elements.pqrs.org/">Karabiner Elements</a>
offered far more control. On Windows however, I could never find a solution. I
used <a href="https://github.com/susam/uncap">uncap</a> and that did the job, but it was a
bit manual, and only (by design) offered limited functionality. I really wanted
a tool I could install, configure and forget about, that also gave me the
ability to remap multiple keys should I need.</p>
<h3>Power Toys</h3>
<p>I then discovered
<a href="https://docs.microsoft.com/en-us/windows/powertoys/">Power Toys</a>, a free set of
programs for Windows 10 "power users" that provide a bunch of additional
functionality. I'm surprised some of these aren't built into Windows by default
(maybe one day they will), but one of the utilities that Power Toys provided is
<a href="https://docs.microsoft.com/en-us/windows/powertoys/keyboard-manager">Keyboard Manager</a>.</p>
<p>Keyboard Manager lets you define mappings intuitively; you hit the key you want
to remap, then press the key ou want to remap it to. In my case, I hit
<code>Caps Lock</code>, then <code>ESC</code>, and it was done! It also provides a visible list of
mappings, and makes it easy to remove them if you make a mistake or change your
mind.</p>
<p>I highly recommend checking out Power Toys, it has much to offer including a
<a href="https://docs.microsoft.com/en-us/windows/powertoys/fancyzones">Window layout manager</a>
and a
<a href="https://docs.microsoft.com/en-us/windows/powertoys/run">OS X Spotlight-esque launcher</a>.
I'll definitely be exploring these further!</p>
VSCode Productivity: Navigating files with Breadcrumbs2021-01-31T00:00:00+00:00http://www.jackfranklin.co.uk/blog/vscode-productivity-navigating-with-breadcrumbs/<p>Over the next few weeks I'm going to be sharing some videos demonstrating parts
of my workflow in VSCode - from managing changes with git (today's video), to
reviewing pull requests, to running tests, and so on.</p>
<p>Today I want to share how I use the
<a href="https://code.visualstudio.com/Docs/editor/editingevolved#_breadcrumbs">VSCode Breadcrumbs</a>
with a handy keyboard shortcut and a bit of configuration to make jumping
between files in the same directory really efficient:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/u3rmf4gEb7Y" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" class="youtube"></iframe>
<p><em>You can also watch this video
<a href="https://www.youtube.com/watch?v=u3rmf4gEb7Y">directly on Youtube</a>.</em></p>
<p>If you've got any questions, comments, feedback, or just want to say hello,
<a href="https://www.twitter.com/Jack_Franklin">get in touch with me on Twitter</a>.</p>
Comparing Svelte and React2021-03-09T00:00:00+00:00http://www.jackfranklin.co.uk/blog/comparing-svelte-and-react-javascript/<p>Last year I created <a href="https://pomod.one/">Pomodone</a>, a small time tracking
application based on the Pomodoro technique of working in 25 minute intervals.
It's a pretty basic app; it has a 25 minute timer (that runs in a Web Worker)
and saves a history of your "poms" to a small Firebase database. I initially
built it using React (well, Preact actually) but I then started to play around
with Svelte, and decided rebuilding the app in Svelte might be a nice way to
blog about the similarities and differences between the libraries.</p>
<p>This is <strong>not a post declaring Svelte to be better than React, or vice-versa</strong>.
This is a post where I'll tell you about my preferences, and what I find easier
or harder with either framework. I'm not here to pick a fight! Plus, Pomodone is
hardily a vastly complex application that could be used to fully put React or
Svelte through its paces. Think of this post as a commentary based on my
experience throwing a side project together, focusing on the developer
experience putting these components together.</p>
<h3>Authentication</h3>
<p>The app uses Firebase Authentication to log a user in via either their GitHub or
Google account. I <em>love</em> Firebase Authentication, it's such an easy way to add
auth to side projects.</p>
<p>React's hooks are a great way to package this up; I create a <code>useCurrentUser</code>
hook which listens out to authentication changes and sets some state
accordingly. I can then trust React to re-render as required when an
authentication change is noted.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">useCurrentUser</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> <span class="token punctuation">[</span>currentUser<span class="token punctuation">,</span> setCurrentUser<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">undefined</span><span class="token punctuation">)</span><br><br> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> firebase<span class="token punctuation">.</span><span class="token function">auth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">onAuthStateChanged</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">details</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token function">setCurrentUser</span><span class="token punctuation">(</span><br> details<br> <span class="token operator">?</span> <span class="token punctuation">{</span><br> <span class="token literal-property property">displayName</span><span class="token operator">:</span> details<span class="token punctuation">.</span>displayName<span class="token punctuation">,</span><br> <span class="token literal-property property">provider</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">'google.com'</span><span class="token operator">:</span> <span class="token string">'Google'</span><span class="token punctuation">,</span><br> <span class="token string-property property">'github.com'</span><span class="token operator">:</span> <span class="token string">'GitHub'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">[</span>details<span class="token punctuation">.</span>providerData<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>providerId<span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token literal-property property">uid</span><span class="token operator">:</span> details<span class="token punctuation">.</span>uid<span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br> <span class="token operator">:</span> <span class="token keyword">null</span><br> <span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><br> <span class="token keyword">return</span> <span class="token punctuation">[</span>currentUser<span class="token punctuation">]</span><br><span class="token punctuation">}</span></code></pre>
<p>Within any component, I can write:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>currentUser<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useCurrentUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre>
<p>This is nice; it's low effort and lets any component quickly access the current
user. The only downside of this is that you potentially have many
<code>onAuthStateChanged</code> listeners; I could mitigate this by only binding one
listener, or by putting the current user in a
<a href="https://reactjs.org/docs/context.html">context instead</a>.</p>
<p>Talking of context, that's much closer to the approach I take with Svelte and
use a <a href="https://svelte.dev/tutorial/writable-stores">writable store</a>.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">export</span> <span class="token keyword">const</span> currentUser <span class="token operator">=</span> <span class="token function">writable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br><br><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function">listenForAuthChanges</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> firebase<span class="token punctuation">.</span><span class="token function">auth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">onAuthStateChanged</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">details</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>details<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> currentUser<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token literal-property property">displayName</span><span class="token operator">:</span> details<span class="token punctuation">.</span>displayName<span class="token punctuation">,</span><br> <span class="token literal-property property">provider</span><span class="token operator">:</span> <span class="token punctuation">{</span><br> <span class="token string-property property">'google.com'</span><span class="token operator">:</span> <span class="token string">'Google'</span><span class="token punctuation">,</span><br> <span class="token string-property property">'github.com'</span><span class="token operator">:</span> <span class="token string">'GitHub'</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">[</span>details<span class="token punctuation">.</span>providerData<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>providerId<span class="token punctuation">]</span><span class="token punctuation">,</span><br> <span class="token literal-property property">uid</span><span class="token operator">:</span> details<span class="token punctuation">.</span>uid<span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><br> currentUser<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>Within the top level Svelte component, I can call this within <code>onMount</code>, which
will run once when the component is mounted (the function is <code>return</code>ed so we
unsubscribe when the component is removed, much like how <code>useEffect</code> lets you
return a function).</p>
<pre class="language-js"><code class="language-js"><span class="token function">onMount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token function">listenForAuthChanges</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>Now anywhere in my Svelte codebase, a component can import the <code>currentUser</code>
writable store, and act accordingly. What I like is that <code>currentUser</code> isn't a
value, it's a store, and therefore you have full control over how you deal with
it. You can either subscribe to it and manually control with state changes:</p>
<pre class="language-js"><code class="language-js">currentUser<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token parameter">newValue</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token operator">...</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>Or, if you want to just read the latest value, you can prefix it with a <code>$</code>:</p>
<pre class="language-js"><code class="language-js">console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>$currentUser<span class="token punctuation">)</span></code></pre>
<p>This is where some of Svelte's syntax trickery begins to shine; this dollar
prefix trick automatically subscribes you to the store's latest value. I both
like and dislike this; it's a nice syntax once you know it, but it's a bit odd
as a beginner to get used to. However I like that Svelte doesn't make me use the
<code>subscribe</code> API every time I need to read the value.</p>
<p>As far as basic authentication goes, both libraries seem to take similar
approaches here. Whilst the terminology and exact syntax differs slightly, both
allow you to subscribe to a Firebase listener and get updated when the
authentication state changes. React's contexts and Svelte's stores play almost
identical roles for their library.</p>
<h3>Using a worker</h3>
<p>Pomodone has to keep a 25 minute timer going and try to be as accurate as
possible. If a browser tab is backgrounded (e.g., not the focused tab), most
browsers will lower the priority of its <code>setTimeout</code> calls and not run them
strictly to time. Most of the time on the web this isn't a massive deal, but
when a user is tracking 25 minutes of work via your app, it is! Plus, over the
course of 25 minutes, any slight time drift will cause the final time to be
quite far off. However, if these timeouts are moved into a web worker, they
should run to time and not get de-prioritised by the browser.</p>
<p>Therefore, in my <code>Tracker</code> component, I need to instantiate a web worker, send
it messages and receive data (such as time remaining) back. This is one area
where I found React more "admin heavy" than Svelte; because React components are
re-executed every time the component re-renders, you can easily end up with
thousands of workers being created! It's essential to use
<a href="https://reactjs.org/docs/hooks-reference.html#useref">useRef</a> to avoid this
problem by maintaining a reference to the worker that you've created.</p>
<p>Firstly I set up the initial state I need for the component:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token punctuation">[</span>currentPom<span class="token punctuation">,</span> setCurrentPom<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><br><span class="token keyword">const</span> <span class="token punctuation">[</span>currentUser<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useCurrentUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br><span class="token keyword">const</span> worker <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span></code></pre>
<p>And then create a <code>useEffect</code> hook that will instantiate the worker, if
required, and bind an event listener to listen for messages:</p>
<pre class="language-js"><code class="language-js"><span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>worker<span class="token punctuation">.</span>current<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> worker<span class="token punctuation">.</span>current <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Worker</span><span class="token punctuation">(</span>workerURL<span class="token punctuation">)</span><br> window<span class="token punctuation">.</span>worker <span class="token operator">=</span> worker<span class="token punctuation">.</span>current<br> <span class="token punctuation">}</span><br><br> <span class="token keyword">const</span> <span class="token function-variable function">onMessage</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>data<span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token string">'tick'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token function">setCurrentPom</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">currentPom</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token punctuation">{</span><br> <span class="token operator">...</span>currentPom<span class="token punctuation">,</span><br> <span class="token literal-property property">secondsRemaining</span><span class="token operator">:</span> event<span class="token punctuation">.</span>data<span class="token punctuation">.</span>counter<span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>data<span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token string">'start'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// More branches removed here to save space...</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span><br> worker<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'message'</span><span class="token punctuation">,</span> onMessage<span class="token punctuation">)</span><br><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> worker<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">'message'</span><span class="token punctuation">,</span> onMessage<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>currentUser<span class="token punctuation">]</span><span class="token punctuation">)</span></code></pre>
<p>And then, when the user hits the "Start" button, I have to send the worker a
message:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> <span class="token function-variable function">onStartPom</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>worker<span class="token punctuation">.</span>current<span class="token punctuation">)</span> <span class="token keyword">return</span><br> worker<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">postMessage</span><span class="token punctuation">(</span><span class="token string">'startTimer'</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>Svelte looks pretty similar, but has two small changes that personally make the
Svelte code easier to read, in my opinion:</p>
<ol>
<li>We don't have to keep the worker in <code>useRef</code>, and can just assign it to a
variable.</li>
<li>We can pull the event listener code out into a function more easily, as that
function won't then become a dependency to a <code>useEffect</code> - at which point we
will have to wrap it in <code>useCallback</code>.</li>
</ol>
<p>Instantiating the worker is now:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> worker<br><span class="token function">onMount</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> worker <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Worker</span><span class="token punctuation">(</span>workerURL<span class="token punctuation">)</span><br> worker<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'message'</span><span class="token punctuation">,</span> onWorkerMessage<span class="token punctuation">)</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> worker<span class="token punctuation">.</span><span class="token function">removeEventListener</span><span class="token punctuation">(</span><span class="token string">'message'</span><span class="token punctuation">,</span> onWorkerMessage<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>We also don't have to set state by using React's <code>setX(oldX => newX)</code>
convention, and can just mutate the local variable:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">onWorkerMessage</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>data<span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token string">'tick'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> currentPom <span class="token operator">=</span> <span class="token punctuation">{</span><br> <span class="token operator">...</span>currentPom<span class="token punctuation">,</span><br> <span class="token literal-property property">secondsRemaining</span><span class="token operator">:</span> event<span class="token punctuation">.</span>data<span class="token punctuation">.</span>counter<span class="token punctuation">,</span><br> <span class="token punctuation">}</span><br> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span>data<span class="token punctuation">.</span>name <span class="token operator">===</span> <span class="token string">'start'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// More branches here removed to save space...</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Here's where I start to have a preference for Svelte; the two are very similar
but once I got used to Svelte I found that React felt like jumping through
hoops. You can't create a worker instance, it has to go in a <code>useRef</code>, and then
you can't easily pull code out into a function without then requiring
<code>useCallback</code> so it can be a safe dependency on <code>useEffect</code>. With Svelte I write
code that's closer to "plain" JavaScript, whereas in React more of my code is
wrapped in a React primitive.</p>
<h3>Conditional rendering</h3>
<p>One part of React that I've always championed is how <em>it's just JavaScript</em>. I
like that in React you don't use a distinct template syntax and instead embed
JavaScript, compared to Svelte's templating language:</p>
<side-by-side first="React" second="Svelte" is-wide-example="">
<pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ul</span><span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token punctuation">{</span>pomsForCurrentDay<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">entryData<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><br> <span class="token keyword">const</span> finishedAt <span class="token operator">=</span> <span class="token function">format</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>entryData<span class="token punctuation">.</span>timeFinished<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'H:mm:ss'</span><span class="token punctuation">)</span><br> <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span> <span class="token attr-name">title</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Finished at </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>finishedAt<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token punctuation">{</span>index <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token plain-text"><br></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>ul</span><span class="token punctuation">></span></span></code></pre>
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>ul <span class="token keyword">class</span><span class="token operator">=</span><span class="token string">"poms-list"</span><span class="token operator">></span><br> <span class="token punctuation">{</span>#each currentDayPoms <span class="token keyword">as</span> value<span class="token punctuation">,</span> index<span class="token punctuation">}</span><br> <span class="token operator"><</span>li<br> title<span class="token operator">=</span><span class="token punctuation">{</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Finished at </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">format</span><span class="token punctuation">(</span><br> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span>value<span class="token punctuation">.</span>timeFinished<span class="token punctuation">)</span><span class="token punctuation">,</span><br> <span class="token string">'H:mm:ss'</span><br> <span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">}</span><br> <span class="token operator">></span><br> <span class="token punctuation">{</span>index <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">}</span><br> <span class="token operator"><</span><span class="token operator">/</span>li<span class="token operator">></span><br> <span class="token punctuation">{</span><span class="token operator">/</span>each<span class="token punctuation">}</span><br><span class="token operator"><</span><span class="token operator">/</span>ul<span class="token operator">></span></code></pre>
</side-by-side>
<p>I was pleasantly surprised by Svelte's templating; in the past I've found
templating languages overwhelming and inflexible, but Svelte offers just the
right amount of templating whilst enabling you to use JavaScript too. That said,
I will always find React's approach easier - at least in my head - and I think
more friendly to people familiar with JavaScript who are learning a library.</p>
<p>However, Svelte does have some nice touches to its syntax when it comes to
rendering components (which feels very JSX-like). My favourite is the ability to
collapse props:</p>
<side-by-side first="Svelte" second="Svelte (collapsed props)">
<pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">History</span></span> <span class="token attr-name">pomodoros</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>pomodoros<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span></code></pre>
<pre class="language-jsx"><code class="language-jsx"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">History</span></span> <span class="token punctuation">{</span><span class="token class-name tag">pomodoros</span><span class="token punctuation">}</span><span class="token punctuation">/></span></code></pre>
</side-by-side>
<p>This is something I've longed for with React!</p>
<h3>Reactivity in Svelte with $</h3>
<p>React requires us to use <code>useEffect</code> and other hooks because it fully controls
how all your code is run and re-runs your code whenever a component is
re-rendered. Svelte is different in that by default most of your code is only
going to run once; a <code>console.log('foo')</code> line in a component will only run when
that component is first rendered. In React, it will run many times.</p>
<p>React's re-rendering approach has its upsides: let's say you are taking in a big
list of data and running some function to convert it into data that you can
render. In React, within your component, you can write:</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> input <span class="token operator">=</span> props<span class="token punctuation">.</span>inputData<br><span class="token keyword">const</span> transformed <span class="token operator">=</span> input<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">transformItem</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">)</span><br><br><span class="token keyword">return</span> <span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>transformed<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></code></pre>
<p>And this will always be up to date - should the user provide new
<code>props.inputData</code>, the component will re-render and the output will be updated.</p>
<p>The same is not true in Svelte:</p>
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>script<span class="token operator">></span><br><span class="token keyword">export</span> <span class="token keyword">let</span> input<span class="token punctuation">;</span><br><span class="token keyword">const</span> transformed <span class="token operator">=</span> input<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">transformItem</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">)</span><br><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span><br><br><span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>transformed<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></code></pre>
<p>Here the output will be rendered the first time the component is rendered, but
then not updated at all. We can solve this in two ways, either by using the <code>$:</code>
label syntax, which marks the code as reactive, or by moving our transform logic
into the template:</p>
<side-by-side first="Using $" second="Transform in template" is-wide-example="">
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>script<span class="token operator">></span><br><span class="token keyword">export</span> <span class="token keyword">let</span> input<span class="token punctuation">;</span><br><span class="token literal-property property">$</span><span class="token operator">:</span> transformed <span class="token operator">=</span> input<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">transformItem</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">)</span><br><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span><br><br><span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>transformed<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></code></pre>
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>script<span class="token operator">></span><br><span class="token keyword">export</span> <span class="token keyword">let</span> input<span class="token punctuation">;</span><br><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span><br><br><span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>input<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">item</span> <span class="token operator">=></span> <span class="token function">transformItem</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></code></pre>
</side-by-side>
<p>This is another example of Svelte taking JavaScript syntax and using it for a
slightly different meaning; it tells Svelte that the statement is <em>reactive</em> and
should be recalculate should any imports change. You might also call it a
"computed property". The second solution simply moves the logic into the
template, thus ensuring that when the component re-renders the logic is executed
again. In my time with Svelte this is the approach I've gone with most of the
time, often pulling out the logic into a function:</p>
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>div<span class="token operator">></span><span class="token punctuation">{</span><span class="token function">calculateOutputForItems</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span></code></pre>
<p>Coming from React to Svelte this did catch me out numerous times but for me I
now prefer Svelte's approach, particularly because it removes some of the
boilerplate around <code>useEffect</code>.</p>
<h3>Component composition</h3>
<p>Component composition is a huge part of what makes working with a component
based framework enjoyable or not and it's something that both React and Svelte
solve well. React's <code>children</code> prop makes it very easy to render any provided
content:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function">Box</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>children<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br><span class="token punctuation">}</span><br><br><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Box</span></span><span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span><span class="token plain-text">hello world!</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">Box</span></span><span class="token punctuation">></span></span><br> <span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>(If you've not read it, the
<a href="https://reactjs.org/docs/composition-vs-inheritance.html">React guide on Composition is well worth a read</a>).</p>
<p>Svelte does similar, using <a href="https://svelte.dev/tutorial/slots">slots</a>:</p>
<pre class="language-html"><code class="language-html"><span class="token comment"><!-- Box component --></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>box<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>slot</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>slot</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br><br><span class="token comment"><!-- App component --></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>Box</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>hello world!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>Box</span><span class="token punctuation">></span></span></code></pre>
<p>They take different approaches when it comes to multiple children, and this is
where I find myself preferring Svelte's approach more. React suggest passing
through multiple props:</p>
<pre class="language-jsx"><code class="language-jsx"><span class="token keyword">function</span> <span class="token function">Box</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token punctuation">(</span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>left<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>left<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>right<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>right<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><span class="token plain-text"><br> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br> <span class="token punctuation">)</span><br><span class="token punctuation">}</span><br><br><span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Box</span></span> <span class="token attr-name">left</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span><span class="token plain-text">hello</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span><span class="token punctuation">}</span></span> <span class="token attr-name">right</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span><span class="token plain-text">world!</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">P</span></span><span class="token punctuation">></span></span><span class="token plain-text">}</span></span> <span class="token punctuation">/></span></span><br><span class="token punctuation">}</span></code></pre>
<p>One gripe I've had with this approach is that you lose the visual cues that
you're passing children into the Box component; they now aren't nested within
the Box when you render them like we're used to in HTML; it's now up to you to
read the props and spot which ones are being used to provide children. It's
easily done on this dummy example, but harder in "real world" applications - or
at least, I find it harder!</p>
<p>Svelte's approach is to define multiple slots with explicit names to let the
user provide the elements that should fill those slots:</p>
<pre class="language-html"><code class="language-html"><span class="token comment"><!-- Box component --></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>box<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>slot</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>left<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>slot</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>slot</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>right<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>slot</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><br><br><span class="token comment"><!-- App component --></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>Box</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>left<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>hello<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span><br> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">slot</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>right<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>world!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span><br><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>Box</span><span class="token punctuation">></span></span></code></pre>
<p>I like this approach more because I can scan the code that renders the <code>Box</code>
component and easily spot that it takes two children. If the <code>Box</code> took any
props, they'd be within the opening <code><Box></code> tag, and they would be distinct from
any children props.</p>
<p>My preference here is biased by the fact that I spend everyday at work building
web components, so Svelte's approach feels very familiar to
<a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots">slots in web components</a>.</p>
<h3>Styling</h3>
<p>I enjoy that Svelte has an opinion about styling; especially in the context of
small side projects like Pomodone, it's great to have that decision made for me.
The fact that Svelte can also detect unused CSS is great, and this is one of the
reasons why I suspect I'll reach more for Svelte in future projects.</p>
<p>This isn't really a downside to React; one of React's strengths is that it lets
you control so much and slot React into your environment, but I like that Svelte
comes with a good CSS story out the box.</p>
<h3>Conditional classes</h3>
<p>One small feature I love about Svelte is how I can apply classes conditionally
to an element:</p>
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>div <span class="token keyword">class</span><span class="token operator">:</span>is<span class="token operator">-</span>active<span class="token operator">=</span><span class="token punctuation">{</span>isActive<span class="token punctuation">}</span><span class="token operator">></span></code></pre>
<p>This will apply the class <code>is-active</code> to the element, but only if the value
<code>isActive</code> is truthy. This reads well, is clear and is great that it comes out
of the box.</p>
<p>I have used <a href="https://www.npmjs.com/package/classnames">classnames</a> to achieve
similar functionality in React, and it's a good solution, but I enjoy that
Svelte provides this out the box.</p>
<h3>Binding event listeners</h3>
<p>Similarly to conditional classes, Svelte packs in some extra utilities for
binding event listeners in the form of
<a href="https://svelte.dev/tutorial/event-modifiers">modifiers</a>. These let you modify
event listeners to ask Svelte to include common functionality, such as calling
<code>event.preventDefault()</code>, for you.</p>
<side-by-side first="Manual preventDefault" second="preventDefault modifier">
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>script<span class="token operator">></span><br><span class="token keyword">function</span> <span class="token function">click</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> event<span class="token punctuation">.</span><span class="token function">preventDefault</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token comment">// logic here</span><br><span class="token punctuation">}</span><br><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span><br><br><span class="token operator"><</span>button on<span class="token operator">:</span>click<span class="token operator">=</span><span class="token punctuation">{</span>click<span class="token punctuation">}</span><span class="token operator">></span><br> Click me<span class="token operator">!</span><br><span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span></code></pre>
<pre class="language-js"><code class="language-js"><span class="token operator"><</span>script<span class="token operator">></span><br><span class="token keyword">function</span> <span class="token function">click</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token comment">// No need to preventDefault ourselves</span><br> <span class="token comment">// logic here</span><br><span class="token punctuation">}</span><br><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span><br><br><span class="token operator"><</span>button on<span class="token operator">:</span>click<span class="token operator">|</span>preventDefault<span class="token operator">=</span><span class="token punctuation">{</span>click<span class="token punctuation">}</span><span class="token operator">></span><br> Click me<span class="token operator">!</span><br><span class="token operator"><</span><span class="token operator">/</span>button<span class="token operator">></span></code></pre>
</side-by-side>
<h3>Conclusion</h3>
<p>I like both React and Svelte. Put me in a codebase with either of them and I'll
enjoy it, be productive and happy putting new features together or fixing bugs.
I have side projects in React, and others in Svelte, and I'm in no rush to
convert any from one to the other. React and Svelte are very similar in many
ways, but what I've found is that in all the little ways that they are
different, I prefer Svelte. The codebase for Pomodone makes more sense to me in
Svelte, not React. I find it easier to navigate and work with.</p>
<p>If I were to sum up why in one sentence, it's because <strong>I don't miss
<code>useEffect</code></strong>. I understand why it exists, I understand the approach React
takes, and there are benefits of its approach. But writing complex React
components feels more like admin; a constant worry that I'll miss a dependency
in my <code>useEffect</code> call and end up crashing my browser session. With Svelte I
don't have that lingering feeling, and that's what I've come to enjoy. Svelte is
there when I need it with useful APIs, but fades into the background as I put my
app together.</p>
Working in small chunks2021-03-09T00:00:00+00:00http://www.jackfranklin.co.uk/blog/coding-javascript-small-chunks/<p>Although occasionally you'll be given a task to complete which can be completed
in no more than a few hours, most of your work is likely going to consist of
features that will take multiple days or even weeks to complete. I've found that
the longer a piece of work takes, the more likely I am to lose track of my
progress, forget which part of the feature I was going to build next, or realise
I've done work in the wrong order and have lost time because of it.</p>
<p>Regardless of how easy or hard the new feature is to build, the longer it takes
the more important it is to break the work down into manageable steps and make
sure you keep on top of it. You cannot keep weeks worth of work in your head;
taking the time upfront to plan your work will pay off, keeping your head clear
to work on the feature and ensuring you have a sense of where you're at at any
given point.</p>
<p>In this post I'll share some strategies I've found useful to help me plan and
stay productive when working on features that span multiple weeks and even
months.</p>
<h2>Plan the small steps ahead of time</h2>
<p>The first thing I'll do when starting on a new feature is create a new document
(this can be whatever format you prefer - I use Google Docs but know others who
always use a pen and paper, it's really down to your personal preference) and
write down a really rough list of bullet points that list all the different
pieces of work I need to complete to consider the overall feature complete. This
list is only for my eyes so I don't worry about formatting or structure and
instead use it as a way to brain-dump everything I can think of that I need to
do, or consider. Most features I work on are backed by a design doc, which lists
the scope and goals of the work, so I'll refer to that when creating my list.</p>
<p>Once I have this list, I can start to order it and decide which parts make sense
to prioritise first. When deciding where to start I'm considering the following:</p>
<ul>
<li>Are there any parts of the project that need to be completed first? Does doing
one piece of work first unlock everything else?</li>
<li>Are there any unknowns or risks with the feature? Do I need to get something
working to validate the approach first? If so, I'll want to tackle this as
soon as possible to avoid wasted effort later on.</li>
<li>Do any of the pieces require help from another team member? If so, I might
want to kick that off soon so I give my colleague some notice and don't force
them to drop everything and help me immediately.</li>
</ul>
<p>The planning here is very much an art not a science; even once I've created my
priority list it's highly likely that the list will change over time as the
project progresses. You're not trying to create the perfect, rigid plan, you're
trying to get a rough plan out of your head and written down so you can track
your progress and know what you're working on next.</p>
<h2>Using your doc as the work progresses</h2>
<p>Once I dive into working on the feature I'll regularly refer back to my doc and
make changes. This might be adding bits of work that I've thought of as I've
been working, or reordering the list as I learn more about the required work.
I'll also tend to keep two more sections in my doc, one for open questions and
another for deferred features.</p>
<h3>Open questions</h3>
<p>I use this part of the doc to track questions I have as I work. I like doing
this because sometimes I don't want to pause coding to ask a colleague a
question. I can instead write down the question and continue with my current
task. At the same time I then get the benefit of offloading that question from
my head and into the doc. I like keeping my head clear to focus on the current
task and the only way I find I can do that is to offload everything else into a
doc.</p>
<h3>Deferred features and preventing scope creep</h3>
<p>Like with any big project, once you start you'll inevitably find further work to
be done, or corners to consider cutting. There's no rule here for if you should
take the quick hack or solve the problem "properly", and the answer for which
path to take will depend heavily on the context of the feature and the situation
at hand.</p>
<p>To avoid getting sidetracked into adding features that weren't initially
planned, I'll note them down in my doc under a "Deferred Features" heading. This
means I stay focused on my work but note down the feature to consider later, and
most of the time I'll ask a colleague for their opinion. If we decide the work
is definitely needed, we can incorporate it into the current workload - whilst
also asking ourselves if we could have planned better to see this work ahead of
time. If the work is important but not critical to the current feature we will
defer it for later, in which case we'll log a bug report into our bug tracking
system describing the feature, why we think we need it and why we've deferred
the work for now. You can use whichever tool(s) you or your company prefer here.</p>
<p>I've found that being explicit with the features that you defer is a great way
to avoid scope creep, because at anytime you've considered all the different
features that <em>could</em> be added to your project. It also gives you ammunition
when someone asks "did you consider adding X?", because you can explain that you
did, but you deferred the work, and here's the link to the bug report/Trello
card/GitHub issue/JIRA ticket/e.t.c that explains your decision.</p>
<h2>Landing changes in small steps and working incrementally</h2>
<p>Big changes that ship all at once are risky. The more you change in one go the
higher the risk of something breaking is when you put it in front of users. Once
I've got my list of steps and I've broken down the work into smaller pieces I'm
then trying to figure out if I can deploy my changes in these small steps. This
reduces the risk but also has the advantage of getting your code reviewed by
colleagues sooner, and enabling your colleagues to review fewer lines of code in
one go. Picture two developers; the first asks their colleague to review 200
lines that they've spent a week working on, and the other asks their colleague
to review 3,000 that they've spent 3 weeks working on. Which code review do you
think will be more thorough?</p>
<p>Now picture two different deployment strategies for a new feature:</p>
<ol>
<li>The first deploys 8 weeks of work, spanning multiple thousands of lines of
code, all in one go, turning on the new feature to all users at once.</li>
<li>The second deploys one to two hundred lines of changes weekly, behind a flag
that enables the feature to be turned on/off quickly. At first it's deployed
only for internal users, and as it nears competition it's then rolled out to
a percentage of the user base before eventually being turned on for everyone.</li>
</ol>
<p>The second strategy there reduces the risk right down. You can never eliminate
risk because any code change, however small, is risky, but with some planning
and upfront thought the risk can be kept to a minimum. Getting regular code
review on your smaller changes is also highly beneficial; we'll discuss this
more in the code reviews chapter.</p>
<h2>Small steps and git commits</h2>
<p>Working in these small steps has also helped me become much better at leaving a
detailed trail of work in the form of git commits. Early on in my career I would
work solidly on a feature for days at a time without making a single git commit,
which now terrifies me just thinking about it! Regularly committing your work to
git (or any similar version control system) has many benefits: you can easily
get back to a working state if you break something, you can try things knowing
that you can undo them easily, and you can easily push your work up to GitHub
(or similar) so its backed up should your machine suddenly stop working.</p>
<p>One of the reasons I didn't get into the habit of committing often was because I
didn't want to spend time writing detailed commit messages. My company at the
time would squash all those commits into one before merging, so I didn't see
value in writing large commit messages that would then get squashed down. It all
changed for me when I realised that <em>I could do the squashing</em> and I should
commit frequently largely for <em>my own benefit</em>.</p>
<p>My workflow now is to commit whenever I reach a natural stopping point, whether
that be fixing a small bug, finishing the first of ten steps on the path to
building a feature, or even writing a failing unit test that's going to be what
I now work on turning green. If I ever step away from my computer for a few
minutes to make a coffee, you can be sure I'll have committed my work.</p>
<p>Because when my work is merged into the main branch it's squashed into one
commit, the frequent commits I make as part of my workflow are really only ever
seen by me. So I don't need to be thorough and detailed, I just need to write
commits that make sense to me. Before I upload my work for code review, I can
rebase and update the git history.</p>
<p>If we take a typical feature, my local git commits might look like so:</p>
<ul>
<li>Write failing unit test</li>
<li>Build initial module and implement <code>someFunc</code></li>
<li>Add UI component with basic functionality working</li>
<li>Flesh out UI component and tackle edge cases</li>
<li>Fix bug with fetching data from the API</li>
<li>CSS tweaks</li>
<li>Final unit tests and fixes</li>
</ul>
<p>Notice that I don't ever really describe the actual high level feature I'm
building. I don't need to, because that's all in my head! And if I need more
context, I've got my doc where I've listed the steps, deferred features and any
open questions.</p>
<p>Once I've done all the work locally and I'm ready to upload my change I can now
rebase those commits. I rebase, squashing them into one large commit, and then
I'll write a brand new description, that might look like so:</p>
<pre class="language-md"><code class="language-md">Add column resizing to data-grid component<br><br>This commit adds the ability for the user to resize the columns of the data-grid<br>using their mouse. It will resize relative to the overall size of the data-grid,<br>and when resizing a column all other columns are left untouched.<br><br>If you're rendering a data-grid and don't want to allow the user to resize the<br>column, you can set the <span class="token code-snippet code keyword">`no-resizing`</span> attribute on the <span class="token code-snippet code keyword">`data-grid`</span> component.<br><br>The column resizing logic is also aware of hidden columns, and won't resize<br>those, and it will re-adjust the column widths if the container is resized. Once<br>a user has resized the column, it will never have it sized changed<br>automatically. If you want to programmatically reset a column, you can call<br><span class="token code-snippet code keyword">`resetColumnWidths()`</span> on the data-grid instance.<br><br>You can find more info here:<br><br><span class="token list punctuation">-</span> Design doc: https://...<br><span class="token list punctuation">-</span> Tracking bug: https://...</code></pre>
<p>Now I take the time to dive into detail and write a thorough description of the
work (this will also make up the description of my pull request, so it's good to
be thorough here and leave lots of context). By doing this at the end I can call
out any particular edge cases or nuances that any other developer might want to
know about, and I leave a good trail in the history for me or any other
developer on my team working on the data-grid in the future.</p>
<h2>Being resilient to interruptions</h2>
<p>It's a fact of life that you'll be interrupted when working by something. As I
write this the majority of us are working from home, so many have even more
chance of disturbance from family members as well as being pinged on Slack by
their colleagues. We've all seen the guidance that suggests software developers
should avoid being interrupted to avoid losing the mental context that's been
built up when a task is being worked on, but it's impossible to not have
interruptions on a daily basis. Your colleagues, very reasonably, will ask for
advice, your boss might want a quick chat about something (hopefully something
positive!) or, in my case, the dog will decide they need to go on a walk.</p>
<p>I still suggest you try to avoid being disturbed too regularly so that you have
time to get your head into work, and I will regularly turn my work chat off,
close my email, log out of other distractions and get my head down, but for
those times when you are interrupted mid-flow, working in the small steps that
we've discussed in this chapter will be very beneficial. You'll not be in the
middle of a huge change, where the entire product you work on is broken, and
you've a list of ten steps in your head you need to finish to get it back
working. You'll instead be part way through step five of ten, with the first
four already done and committed, and all other thoughts listed in your work doc.
For me now an interruption is a case of "give me five minutes to finish off",
where I leave the code in a state I can pick up again, often including a large
<code>// TODO: jack, make this function...</code> type comment that I'll pick up. I will
then add and commit my changes to git (literally using
<code>git commit -m 'WIP: step 4, add CSS'</code>, because as discussed I'll reword them
later) and at that point I've tucked my work away and I'm ready to give my
colleague/boss/dog full focus. It's vital when you do this that you offload all
the thoughts you have about your current work out of your head, so you can pick
up more easily. This might be <code>TODO</code> comments in the code, it might be in your
doc, or it might be hastily scribbled on a Post-It note. It doesn't matter
where, but get them out of your head. This frees up your mind to focus fully on
whatever now needs your attention</p>
<p>Working in small chunks has been very beneficial for my productivity, my mental
health, and my ability to offload tasks to documents (or paper) and focus on the
most relevant task at hand. What tips and tricks have you found useful -
particularly during these last 12+ months of primarily working from home? Get in
touch on Twitter, I'd love to hear them!</p>
Why you should check-in your node dependencies2021-12-06T00:00:00+00:00http://www.jackfranklin.co.uk/blog/check-in-your-node-dependencies/<p>On every team at every company I've been at prior to my current role, the advice was simple: don't check your <code>node_modules</code> folder into your version control system (which I'll refer to as “Git” for the rest of this article…). This seemed like solid advice for multiple reasons:</p>
<ul>
<li>The code within <code>node_modules</code> isn't authored by the team directly.</li>
<li>The code within <code>node_modules</code> is often quite large and would cause a lot of noise in git diffs and pull requests.</li>
<li>The code within <code>node_modules</code> can easily be replicated with an <code>npm</code> install.</li>
</ul>
<p>I currently work at Google on the Chrome DevTools team and we check our <code>node_modules</code> folder into source control. At first this struck me as unusual, but I've come to believe that there are some major benefits to this approach that I think more people should consider.</p>
<h2>No need for npm installs</h2>
<p>Once you check your <code>node_modules</code> in, there's no need to run an install step before you can get up and running on the codebase. This isn't just useful for developers locally, but a big boost for any bots you might have running on a Continuous Integration platform (e.g. CircleCI, GitHub Actions, and so on). That's now a step that the bots can miss out entirely. I've seen projects easily need at least 1-2 minutes to run a complete <code>npm install</code> from scratch - and on bots that could be even longer. If you think that a bot runs on every pull request and deploy, you could easily have 50+ bots run each day. That's a lot of minutes (and bandwidth!) saved.</p>
<h2>Guaranteed replicated builds</h2>
<p>Having your <code>node_modules</code> checked in guarantees that two developers running the code are running the exact same code with the exact same set of dependencies. Yes, this can be managed by a package-lock.json file, or other tools, but I've seen all of them slip up rarely or allow a slight variation in a minor version number that causes issues. Once the dependencies are in git, you cannot possibly run with anything other than those and each developer will be running the exact codebase.</p>
<h2>Better awareness of the code you're shipping</h2>
<p>I've been surprised at how more aware I am of adding dependencies when the git diff shows me the entirety of the code that is being added to the project. This has lead us to make contributions to tools to help reduce their file size on disk and have a better awareness of the impact a dependency will have on our bundle size.</p>
<h2>More consideration to adding a dependency because it's not invisible</h2>
<p>I mentioned earlier that people see the noise in a git diff as a downside to adding dependencies to version control, and I do acknowledge that it can be a downside to this approach, but I've found that noise to often be a useful signal. Adding that one extra dependency because I don't want to write a few lines of code myself is something I used to do frequently - but now I'm much more considered because I can see the code that's being added and can reflect on if it's worth it.</p>
<p><em>Note: this doesn't mean that we don't have dependencies!</em> There are times where it is worth it to add a dependency - but seeing the code in version control has made me more considered about doing it - the cost is no longer invisible.</p>
<h2>You can manage the large diffs</h2>
<p>There is no shying away from the fact that if a developer works on a change that adds a new dependency, there could be a lot of noise in the diff. One of our dependencies that we check in is TypeScript, and every time we update that, the git diff is huge and frankly not worth looking at (beyond the CHANGELOG). We've come up with a rule that helps us here: a change that updates <code>node_modules</code> may not touch any other code in the codebase. So if I update <code>node_modules/typescript</code> with its latest version, I will be warned by our tooling if any other folder outside of <code>node_modules</code> is changed.</p>
<p>This rule serves us well the majority of the time, because any work that relies on a new or updated dependency can be split into two changes:</p>
<ol>
<li>Update the dependency</li>
<li>Use the dependency in the code</li>
</ol>
<p>There are times where this doesn't work; updating TypeScript may require us to update some code to fix errors that the new version of TypeScript is now detecting. In that case we have the ability to override the rule.</p>
<blockquote>
<p>As with anything in software engineering, most "rules" are guidelines, and we're able to side-step them when required.</p>
</blockquote>
<h2>Protection from another left pad</h2>
<p>The <a href="https://qz.com/646467/how-one-programmer-broke-the-internet-by-deleting-a-tiny-piece-of-code/">now infamous left_pad incident</a>, where a popular npm package was removed from the repository all of a sudden, causing builds everywhere to break, would not have impacted a team who checked all their dependencies into git. They would still have to deal with the long term impact of "what do we do with this now unsupported dependency", but in the short term their builds wouldn't break and they wouldn't be blocked on shipping new features.</p>
<h2>Conclusion</h2>
<p>If I was starting a new codebase this week, or joining a small start-up just getting their first version off the ground, I would advocate strongly for checking <code>node_modules</code> into version control. It absolutely takes some getting used to, but in my experience over the last two years of working this way the benefits I've listed above strongly outweigh the additional git noise and slight overhead.</p>
Why I don't miss React: a story about using the platform2022-05-03T00:00:00+00:00http://www.jackfranklin.co.uk/blog/working-with-react-and-the-web-platform/<p>Just over two years ago I left a role at a London based startup where I lead development of a large, React based e-commerce frontend to join Google to work on Chrome DevTools. My initial focus was to introduce Web Components as the new fundamental building block of all new DevTools features and UI. With the recently launched <a href="https://developer.chrome.com/docs/devtools/recorder/">Recorder</a> panel along with others, there are now large parts of DevTools that are almost exclusively web components.</p>
<p>When I left my React focused role behind I expected to find the transition hard, and miss what React had to offer. I've ended up finding the transition easier than expected and have come to really relish working closer to the platform’s primitives and maintaining more control over the software I write and in this blog post I’d like to share why that is.</p>
<p>Firstly, because some people on the internet like to get angry over opinions that may not match their own, I want to make clear what this blog post is not:</p>
<ul>
<li>It is not a call for everyone to immediately drop React and move to web components.</li>
<li>It is not a blog post declaring React “dead”, or the wrong choice for every project.</li>
<li>It is not a blog post declaring web components the best solution to all projects.</li>
<li>It is not a blog post declaring all web frameworks useless or a bad choice.</li>
<li>It is not a blog post suggesting that, because this approach works for me and the team I’m on at Google, that it works for you. All projects are different, and Chrome DevTools almost certainly has a different set of requirements and constraints to your project. And that's fine :)</li>
</ul>
<p>This blog post should be read as the musings of someone who went from working with React every day to not touching it, and the experiences of doing so. I am writing this post because I have been pleasantly surprised on how much I've enjoyed working more closely with the web platform.</p>
<blockquote>
<p>Whilst I will use “React” as my comparison, you could reasonably substitute it for any of the large modern frameworks.</p>
</blockquote>
<h2>Using the platform</h2>
<p>“Using the platform” has become a bit of an overused and abused phrase in recent years, but the core principle resonates with me: can we use the APIs built into the browser and JavaScript to build features for our users without paying the cost of third party dependencies?</p>
<blockquote>
<p>Note: the answer here is not always “yes”! There are still plenty of features I’d like to see built into browsers, but compared to ten years ago the landscape of native functionality has expanded massively.</p>
</blockquote>
<p>One classic example here is building forms: this used to be a justifiable reason to reach for React because browsers offered us very little here beyond primitive functionality. Fast forward a few years and on a recent side project I was able to use 100% native functionality to build my form with a solid user experience:</p>
<ul>
<li>I used <a href="https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation#using_built-in_form_validation">HTML validation attributes</a> to enforce required fields (and could have done more with pattern based validation)</li>
<li>I used the <a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects">FormData API</a> to read values out of the form rather than track their values in state (which I didn’t need to, because the validation was done by the browser).</li>
<li>If I wanted to, I could even customise the error messages using the <a href="https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation#validating_forms_using_javascript">Constraint Validation API</a> - an API I didn't even know existed until a few days ago!</li>
</ul>
<p>Was this slightly more work than using a library from npm that wraps this all up for me? Maybe! But I was able to achieve the same result, writing a few extra lines of code myself, but without weighing my application down with an extra dependency.</p>
<h2>Maintaining control</h2>
<p>Adjusting to <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements">Custom Elements</a> was the main concern I had when moving on from React, but I've come to really enjoy working with them.</p>
<p>Custom Elements may lead to more code being written but with a little bit of work you can create something that will feel surprisingly familiar if you've worked with any of the popular component libraries, with one crucial difference: <strong>you don’t give up control</strong>.</p>
<p>React will not allow you to dictate how and when you render your component onto the page. You write code using its constructs and it determines when to render. 9 times out of 10 - even 99 out of 100 or more - this works exactly as you’d expect. But the web platform isn't perfect, and I suspect most React developers have come across a situation where you’d love to be able to just tweak how your component is being rendered.</p>
<p>Giving up control of your rendering process can lead to confusion, as per <a href="https://twitter.com/garybernhardt/status/1516099364611047436">this tweet from Gary Bernhardt</a>:</p>
<blockquote>
<p>Why does this code:</p>
<p><code>console.log(<code>mark ${Math.random()}</code>)</code></p>
<p><code>alert(<code>mark ${Math.random()}</code>)</code></p>
<p>print one log but show two alerts? Because <code>React.StrictMode</code> hides one log to "help" me prepare for concurrent mode. React is great but concurrent mode feels like a mistake for 99.9% of apps.</p>
</blockquote>
<p>This behaviour has now changed in React v18, but the fact that React had to work to suppress extra <code>console.log</code> calls that occur as a result of how it renders my application is surprising to me; it's this lack of control in my own application that has become something I'm wary of.</p>
<p>In software development this is known as <a href="https://martinfowler.com/bliki/InversionOfControl.html">Inversion of Control</a>. When you use a framework like React, your code is no longer in direct control of when components (or functions) are called. Your components don't directly tell React when to re-render them, but React decides. Your components have ceded control to React.</p>
<p>Our Custom Elements solution doesn't have this inversion of control; we control every render by explicitly calling a function (in the case of lit-html, it is a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals?retiredLocale=nl">tagged template literal</a> called <a href="https://lit.dev/docs/v1/lit-html/introduction/#lit-html-templates"><code>html</code></a>).</p>
<p>The downside of not picking a framework like React is that you have to consider recreating pieces that are otherwise built-in, such as a basic scheduler that ensures we batch renders or a library of test helpers to make testing these components easier. You have to carefully consider your options in situations like this: if we avoid React but end up re-implementing the majority of what it offers, we might have been better off using the framework. In our case, we still felt this decision was justified because we don't have to recreate a scheduler with all the complexity of React's; we can build a small, self-contained implementation that only implements what we need.</p>
<p>Having built our basic scheduler, we know exactly why and when every component renders, and on those times where we have to deviate from the standard path, we are able to. This feels very valuable: every software project I've ever worked on has had at least one component that needed to do something differently to solve a peculiar edge case.</p>
<h2>Pick dependencies that can be easily replaced.</h2>
<p>One area where custom elements are lacking is some form of HTML templating solution that provides efficient re-rendering of HTML. I'd definitely recommend using a library for this, and we settled on <a href="https://lit.dev/docs/libraries/standalone-templates/">lit-html</a>. What appeals about lit-html is that it makes up just one small piece of our solution. We could have gone for Lit, a more fully featured components library formed around custom elements, but that would have led to us increasing our dependencies and forgoing some control (<em>to reiterate the points I made earlier in this blog post: this is not a criticism of Lit, and for many people Lit is the right choice!</em>).</p>
<p>Lit-html ensures that our HTML is rendered efficiently and comes with a nice set of directives that allow us to easily do common tasks like <a href="https://lit.dev/docs/templates/directives/#classmap">conditionally applying classes</a>. It’s not quite as seamless as JSX, but gets pretty close.</p>
<p>The best part? It’s a very small dependency (<a href="https://bundlephobia.com/package/lit-html@2.2.2">3.3kB gzipped</a>) and even more crucially could easily be replaced if we needed to. It might sound negative or even pessimistic, but when we adopt a new dependency one of the main questions we ask is “what happens if this disappears”?</p>
<p>Let's say React disappears (this is not to say I think it will). What's the cost to us of dealing with that? We have a few options:</p>
<ol>
<li>Maintain a fork of React at whichever version we are currently using.</li>
<li>Migrate all our components from React to something else.</li>
</ol>
<p>Neither of those options appeal to me; maintaining a library means we either do nothing and miss out on improvements and/or security fixes, and migrating all our components would be a huge undertaking. I'm sure React forks would spring up should this event occur, but regardless it would involve a lot of churn and work to get things on a healthier footing. Migrating all of our components would be a costly exercise with little tangible benefit to end users - and therefore an incredibly hard sell to the business and leadership. We'd also have to learn a new framework (even if it was similar to React) and increase our expertise in that framework.</p>
<p>Contrast this with custom elements and lit-html. We can have a good level of confidence that custom elements won't suddenly disappear; it's baked into the browser and backwards compatibility is a core tenet of the web platform.</p>
<blockquote>
<p>If you're thinking about custom elements v0 being removed in favour of v1, remember that v0 was a Chrome specific experimental spec, whereas v1 is a cross-platform standardised specification. The purpose of v0 was to gather feedback from developers that could inform the future standardised specification.</p>
</blockquote>
<p>And if lit-html were to vanish from the internet? We have the same two choices: maintain a fork, or replace it. Maintaining a fork wouldn't be ideal for the same reasons maintaining a React fork isn't ideal, with one slight difference: the scope of lit-html is much smaller, and it is a much smaller library generally. It would be less work to get our heads around and learn to a point where we could land fixes or improvements if we required.</p>
<p>Replacing lit-html would be an undertaking but much less so than replacing React: it’s used in our codebase purely for having our components (re)-render HTML. Replacing lit-html would still mean that we can keep our business logic, ultimately maintaining the value they provide to end-users. Lit-Html is one small Lego brick in our system, React (or Angular, or similar) is the entire box.</p>
<h2>The cost of third party dependencies</h2>
<p>Third party dependencies, however big or small, have a set of costs that your users and/or developers will pay. Everyone's opinion on if that cost is worth it or not will differ, and it will depend on your application and tech stack, but when I think about adding new dependencies the following set of costs appear:</p>
<ol>
<li><strong>Bundle size</strong>: how much weight is this dependency adding to our final JavaScript that we have to deliver and execute in the browser? Is that bundle size appropriate and worth it for what this dependency provides?</li>
<li><strong>Breaking changes and upgrades</strong>: what happens if the package has a big overhaul and needs work to upgrade to the latest version? Do we stay on the older version (not ideal if it's not getting updates or security fixes) or invest the work to upgrade? Can the work to upgrade be prioritised soon or is it the type of work that we might never get around to?</li>
<li><strong>Risk of unmaintained code or issues</strong>: who is to say that a third party dependency might have a particular vulnerability or issue that might cause issues? (this is not a criticism of all those who work tirelessly to maintain open source software - but these things happen).</li>
</ol>
<p>Jeremy Keith in <a href="https://adactio.com/journal/19021">his recent post on trust</a> states:</p>
<blockquote>
<p>Every dependency you add to a project is one more potential single point of failure.</p>
</blockquote>
<p>The same is true of your own code (swap "dependency" for "file"), but crucially you have full control, you presumably are more familiar with its workings as it was written in house, and you are not beholden to others to fix the issue upstream. This is not to say that you should recreate the world on every project; there will always be a fine balancing act of building it yourself versus adding a dependency, and there is no rule that will determine the right outcome every time.</p>
<h2>Conclusion</h2>
<p>This post is not to say that you shouldn't reach for dependencies. In response to Jeremey Keith's post on trust and third party dependencies, <a href="https://charlesharri.es/stream/libraries-over-browser-features">Charles Harries suggests that cross browser compatibility was historically the driver for dependencies</a>:</p>
<blockquote>
<p>Browser compatibility is one of the underlying promises that libraries—especially the big ones that Jeremy references, like React and Bootstrap—make to developers.</p>
</blockquote>
<blockquote>
<p>I'm on a budget and I can't spend my time reading through the caniuse.com page for Array.prototype.includes or MutationObserver. Lodash promises cross-platform compatibility right there at the bottom of its homepage.</p>
</blockquote>
<p>I completely agree with Charles' opinion, and this is one area where working on the DevTools for one browser has an advantage because we know our audience's browser choice.</p>
<p>My hope is that with the baseline feature set supported by browsers now more uniform - especially with the death of Internet Explorer - that we as an industry can over time move to reaching for the extensive built-in functionality of browsers by default, polyfilling where absolutely necessary, and look beyond frameworks as a default starting point.</p>
<p><em>Thank you to <a href="https://twitter.com/TimvdLippe">Tim van der Lippe</a> and <a href="https://twitter.com/aerotwist">Paul Lewis</a> for their help reviewing drafts of this post.</em></p>
Learning to say "I don't know"2022-07-07T00:00:00+00:00http://www.jackfranklin.co.uk/blog/learning-to-say-i-dont-know/<p>In October 2021 I took on a new role within the Chrome DevTools team as a
Technical Lead (TL) of the DevTools Performance Tooling team, who are
responsible for all things website performance inside of DevTools, the most
well known being the Performance Panel.</p>
<p>My journey to this point had begun a year prior when we started building a new
panel that would come to be named Performance Insights. I was asked to build
the panel, and for the first time in my career I came face to face with Chrome
trace files. These are large JSON files that contain all the trace data that
Chrome generates when asked to perform a trace, and it’s these that contain the
information that we parse and present in the DevTools panels. It’s also part of
what other tools like Lighthouse, or third-party tools like
<a href="https://www.webpagetest.org/">WebPageTest</a>, use to display data.</p>
<p>There was a lot of knowledge and information about performance that I didn't
know. This is something that I’m never comfortable with, but as a contributor
to the team I felt happy admitting to my manager (and TL of the team) when I
didn't know things, and asking them to jump on a video call to walk me through
something. I’d never even used the HTML Canvas API, which I had to learn along
with the intricate details of Performance tracing.</p>
<p>When I then became TL of the team, I was suddenly the person who people would
ask questions to. On the first "official" day that I became TL, someone asked
me a question about traces and how certain trace events are represented. I
realised I didn't know, and I was going to <em>have to admit it</em>. But I'm the TL,
I'm supposed to know that! I panicked; assuming that my lack of knowledge would
now be unearthed and I'd quickly be "found out" as not being ready for this
role.</p>
<p>As you've probably guessed, none of that happened. I decided to embrace not
knowing, and put my efforts into figuring out <em>how to find out</em> and fill the
gaps in my own knowledge. Sometimes I could do that by spending thirty minutes
reading a trace file and understanding how the data is linked. Other times I
could find an old design doc, or documentation that would give me the answer.
And sometimes, best of all, I had to email someone else who I thought might
well know the answer. This has been one of the best decisions I've made
recently; emailing people to ask for help has not only given me the answers I
need but helped me build relationships with a bunch of folks who I would never
have otherwise engaged with, from all over the world. One of them even
explicitly thanked me for being curious, and reaching out to ask!</p>
<p>Becoming comfortable saying "I don't know", or "I don't know, but I bet X
will", or "I don't know, but I'll find out for you" has become one of the most
powerful tools at my disposal. I've learned that being a good TL isn't about
knowing everything - there is simply too much to know! - but about being able
to fill those knowledge gaps and help your team be more productive as a result.</p>
Running command line tasks in Neovim2022-07-23T00:00:00+00:00http://www.jackfranklin.co.uk/blog/executing-tasks-in-neovim/<p>My daily workflow often involves repeatedly running tasks, whether that be build commands, unit tests, or some other scripts. My ideal workflow is to have a terminal split on the right hand side, and then be able to send tasks to it.</p>
<h2>The built in terminal</h2>
<p>Neovim's built in <code>:terminal</code> allows me to easily open a terminal as a split in Neovim, and I have a few custom keymaps to jump to and from it.</p>
<p>Rather than use <code><C-w>{h,j,k,l}</code> to navigate splits, I remap to <code><C-{h,j,k,l></code>, and I add the same mappings to the terminal splits, along with mapping <code><Esc></code>:</p>
<pre class="language-bash"><code class="language-bash">tnoremap <span class="token operator"><</span>Esc<span class="token operator">></span> <span class="token operator"><</span>C-<span class="token punctuation">\</span><span class="token operator">></span><span class="token operator"><</span>C-n<span class="token operator">></span><br>tnoremap <span class="token operator"><</span>C-h<span class="token operator">></span> <span class="token operator"><</span>C-<span class="token punctuation">\</span><span class="token operator">></span><span class="token operator"><</span>C-n<span class="token operator">></span><span class="token operator"><</span>C-w<span class="token operator">></span>h<br>tnoremap <span class="token operator"><</span>C-j<span class="token operator">></span> <span class="token operator"><</span>C-<span class="token punctuation">\</span><span class="token operator">></span><span class="token operator"><</span>C-n<span class="token operator">></span><span class="token operator"><</span>C-w<span class="token operator">></span>j<br>tnoremap <span class="token operator"><</span>C-k<span class="token operator">></span> <span class="token operator"><</span>C-<span class="token punctuation">\</span><span class="token operator">></span><span class="token operator"><</span>C-n<span class="token operator">></span><span class="token operator"><</span>C-w<span class="token operator">></span>k<br>tnoremap <span class="token operator"><</span>C-l<span class="token operator">></span> <span class="token operator"><</span>C-<span class="token punctuation">\</span><span class="token operator">></span><span class="token operator"><</span>C-n<span class="token operator">></span><span class="token operator"><</span>C-w<span class="token operator">></span>l</code></pre>
<p>I also prefer to always be in insert mode by default when entering a terminal split:</p>
<pre class="language-bash"><code class="language-bash">autocmd BufEnter * <span class="token keyword">if</span> <span class="token operator">&</span>buftype <span class="token operator">==</span> <span class="token string">'terminal'</span> <span class="token operator">|</span> :startinsert <span class="token operator">|</span> endif</code></pre>
<h2>Neoterm plugin</h2>
<p>To make things a little easier to manage, I also use the <a href="https://github.com/kassio/neoterm">Neoterm plugin</a>. This gives me the ability to run:</p>
<pre class="language-bash"><code class="language-bash">:T <span class="token function">ls</span></code></pre>
<p>To open a terminal and execute the <code>ls</code> command. If you then run this command again, it will re-execute the terminal command but <em>in the same terminal</em>. You may start to see how this is going to form the building blocks of my setup of a terminal that I continuously execute tasks in...</p>
<p>I can then set <code>neoterm_size</code> and <code>neoterm_default_mod</code> to define how the terminal appears. I set it to approximately 30% of the screen width, and to be vertical on the right hand side:</p>
<pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>g<span class="token punctuation">.</span>neoterm_size <span class="token operator">=</span> <span class="token function">tostring</span><span class="token punctuation">(</span><span class="token number">0.3</span> <span class="token operator">*</span> vim<span class="token punctuation">.</span>o<span class="token punctuation">.</span>columns<span class="token punctuation">)</span><br>vim<span class="token punctuation">.</span>g<span class="token punctuation">.</span>neoterm_default_mod <span class="token operator">=</span> <span class="token string">'botright vertical'</span></code></pre>
<blockquote>
<p>This config is in Lua rather than Vimscript because I only use Neovim. The previous configuration code shown is due to be migrated but I've not got round to it yet!</p>
</blockquote>
<h2>Mapping a key to execute a command</h2>
<p>I don't want to have to manually run <code>:T my-command-here</code> every time I want to run tests. So I started manually setting a shortcut when I would need to have a command setup, such as running tests:</p>
<pre class="language-bash"><code class="language-bash">:nnoremap <span class="token operator"><</span>leader<span class="token operator">></span>e :T <span class="token function">npm</span> test<span class="token operator"><</span>CR<span class="token operator">></span></code></pre>
<p>This worked well, but had some caveats. Firstly, I use Neoterm to fire up multiple terminals (I often have some in other tabs for other commands), and <code>:T</code> would reference the latest terminal. So to fix that, I adjusted the command to <code>:1T</code>, which would target the first terminal.</p>
<p>I also wanted to have the terminal cleared between each execution of the command. I did that at first by using the <code>clear</code> command:</p>
<pre class="language-bash"><code class="language-bash">:nnoremap <span class="token operator"><</span>leader<span class="token operator">></span>e :1T <span class="token function">clear</span> <span class="token operator">&&</span> <span class="token function">npm</span> test<span class="token operator"><</span>CR<span class="token operator">></span></code></pre>
<p>But I then discovered Neotree's <code>:1Tclear</code> command which would clear the terminal for me, without me having to include <code>clear</code> as the first task.</p>
<p>My final problem is that I was bored of typing this mapping manually! So I set out to automate it...</p>
<h2>Building the task execution command</h2>
<p>I wanted to have a mapping for <code><leader>e</code> that would:</p>
<ol>
<li>Create a terminal if required, or re-use the existing one otherwise.</li>
<li>Prompt for a command to automatically run.</li>
<li>Once a command is given, store that and use it again for future runs (e.g. only prompt once for a command).</li>
<li>Clear the terminal between each run.</li>
<li>Provide an option to reset the command.</li>
</ol>
<p>Requirements (1) and (4) are easy; Neoterm's behaviour gives me those for free. To create a command that I can then bind to a key I can use <a href="https://neovim.io/doc/user/api.html#nvim_create_user_command()"><code>nvim_create_user_command</code></a>:</p>
<pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_create_user_command</span><span class="token punctuation">(</span><span class="token string">'TaskPersist'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><br> <span class="token comment">-- implementation here</span><br><span class="token keyword">end</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> nargs <span class="token operator">=</span> <span class="token string">'*'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>And I know already that I can execute a command (stored here as <code>cmd</code>) by using Neoterm:</p>
<pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_command</span><span class="token punctuation">(</span><span class="token string">":1Tclear"</span><span class="token punctuation">)</span><br>vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_command</span><span class="token punctuation">(</span><span class="token string">":1T "</span> <span class="token operator">..</span> cmd<span class="token punctuation">)</span></code></pre>
<p>So now I need to store a command, and find a way to set it if it's not provided. I could do this via setting some global variable, but I want it to be a nice UI! This is where <a href="https://github.com/MunifTanjim/nui.nvim">nui.nvim</a> comes in. I already have it in my <code>init.vim</code> file, because another plugin I use depends on it. And it has an <a href="https://github.com/MunifTanjim/nui.nvim/tree/main/lua/nui/input"><code>Input</code> component</a>!</p>
<p>I create a variable, <code>stored_task_command</code>, which will be a variable within this Lua module that tracks the current command. Initially it's set to <code>nil</code>.</p>
<p>I can create <code>trigger_set_command_input</code> as a function which will create and mount an <code>Input</code> component. When the input is submitted, we set <code>stored_task_command</code> to the input, and trigger a callback function that is provided:</p>
<blockquote>
<p>Most of this code is straight from the <code>nui.nvim</code> example; I've just modified the text prompts and the width of the input!</p>
</blockquote>
<pre class="language-lua"><code class="language-lua"><span class="token keyword">local</span> stored_task_command <span class="token operator">=</span> <span class="token keyword">nil</span><br><br><span class="token keyword">local</span> trigger_set_command_input <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>callback_fn<span class="token punctuation">)</span><br> <span class="token keyword">local</span> input_component <span class="token operator">=</span> <span class="token function">Input</span><span class="token punctuation">(</span><span class="token punctuation">{</span><br> position <span class="token operator">=</span> <span class="token string">"50%"</span><span class="token punctuation">,</span><br> size <span class="token operator">=</span> <span class="token punctuation">{</span><br> width <span class="token operator">=</span> <span class="token number">50</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> border <span class="token operator">=</span> <span class="token punctuation">{</span><br> style <span class="token operator">=</span> <span class="token string">"single"</span><span class="token punctuation">,</span><br> text <span class="token operator">=</span> <span class="token punctuation">{</span><br> top <span class="token operator">=</span> <span class="token string">"Commmand to run:"</span><span class="token punctuation">,</span><br> top_align <span class="token operator">=</span> <span class="token string">"center"</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> win_options <span class="token operator">=</span> <span class="token punctuation">{</span><br> winhighlight <span class="token operator">=</span> <span class="token string">"Normal:Normal,FloatBorder:Normal"</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><br> prompt <span class="token operator">=</span> <span class="token string">"> "</span><span class="token punctuation">,</span><br> default_value <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">,</span><br> on_submit <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><br> stored_task_command <span class="token operator">=</span> value<br> <span class="token function">callback_fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br> <span class="token keyword">end</span><span class="token punctuation">,</span><br> <span class="token punctuation">}</span><span class="token punctuation">)</span><br><br> input_component<span class="token punctuation">:</span><span class="token function">mount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> input_component<span class="token punctuation">:</span><span class="token function">on</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span>BufLeave<span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> input_component<span class="token punctuation">:</span><span class="token function">unmount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token keyword">end</span><span class="token punctuation">)</span><br><span class="token keyword">end</span></code></pre>
<p>And with that, I can now provide a nice UI to set the command.</p>
<h2>Putting the pieces together</h2>
<p>So, the final implementation should:</p>
<ol>
<li>Use Neoterm to create or re-use an existing terminal</li>
<li>If <code>stored_task_command</code> is <code>nil</code>, trigger the <code>Input</code> box to set the command.</li>
<li>Run the command in the terminal (via Neoterm), after calling <code>:Tclear</code>.</li>
</ol>
<pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_create_user_command</span><span class="token punctuation">(</span><span class="token string">'TaskPersist'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><br> <span class="token keyword">local</span> execute <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>cmd<span class="token punctuation">)</span><br> vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_command</span><span class="token punctuation">(</span><span class="token string">":1Tclear"</span><span class="token punctuation">)</span><br> vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_command</span><span class="token punctuation">(</span><span class="token string">":1T "</span> <span class="token operator">..</span> cmd<span class="token punctuation">)</span><br> <span class="token keyword">end</span><br><br> <span class="token keyword">if</span> stored_task_command <span class="token operator">==</span> <span class="token keyword">nil</span> <span class="token keyword">then</span><br> <span class="token comment">-- Load up the Input component to get a value, then run it</span><br> <span class="token function">trigger_set_command_input</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token function">execute</span><span class="token punctuation">(</span>stored_task_command<span class="token punctuation">)</span><br> <span class="token keyword">end</span><span class="token punctuation">)</span><br> <span class="token keyword">else</span><br> <span class="token function">execute</span><span class="token punctuation">(</span>stored_task_command<span class="token punctuation">)</span><br> <span class="token keyword">end</span><br><span class="token keyword">end</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> nargs <span class="token operator">=</span> <span class="token string">'*'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>And with that, it works! I can bind to a key:</p>
<pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_keymap</span><span class="token punctuation">(</span><span class="token string">"n"</span><span class="token punctuation">,</span> <span class="token string">"<leader>e"</span><span class="token punctuation">,</span> <span class="token string">":TaskPersist<CR>"</span><span class="token punctuation">,</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>And the behaviour is as desired :)</p>
<p><img src="http://www.jackfranklin.co.uk/images/nvim-task.png" alt="Executing a task in NeoVim"></p>
<h2>Allowing random one-off tasks</h2>
<p>Sometimes I do need the ability to reuse the terminal I'm running my tasks in for a quick one-off task. For that, I can make the custom <code>TaskPersist</code> command optionally take a command to use for just this one run:</p>
<pre class="language-bash"><code class="language-bash">:TaskPersist <span class="token builtin class-name">echo</span> <span class="token string">"some one off task"</span></code></pre>
<p>Which can be done by reading the arguments when defining a custom command:</p>
<pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_create_user_command</span><span class="token punctuation">(</span><span class="token string">'TaskPersist'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span>input<span class="token punctuation">)</span><br> <span class="token keyword">local</span> execute <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span>cmd<span class="token punctuation">)</span><br> vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_command</span><span class="token punctuation">(</span><span class="token string">":1Tclear"</span><span class="token punctuation">)</span><br> vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_command</span><span class="token punctuation">(</span><span class="token string">":1T "</span> <span class="token operator">..</span> cmd<span class="token punctuation">)</span><br> <span class="token keyword">end</span><br><br> <span class="token keyword">local</span> one_off_command <span class="token operator">=</span> input<span class="token punctuation">.</span>args<br><br> <span class="token keyword">if</span> one_off_command <span class="token keyword">and</span> string<span class="token punctuation">.</span><span class="token function">len</span><span class="token punctuation">(</span>one_off_command<span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span> <span class="token keyword">then</span><br> <span class="token function">execute</span><span class="token punctuation">(</span>one_off_command<span class="token punctuation">)</span><br> <span class="token keyword">elseif</span> stored_task_command <span class="token operator">==</span> <span class="token keyword">nil</span> <span class="token keyword">then</span><br> <span class="token function">trigger_set_command_input</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token function">execute</span><span class="token punctuation">(</span>stored_task_command<span class="token punctuation">)</span><br> <span class="token keyword">end</span><span class="token punctuation">)</span><br> <span class="token keyword">else</span><br> <span class="token function">execute</span><span class="token punctuation">(</span>stored_task_command<span class="token punctuation">)</span><br> <span class="token keyword">end</span><br><span class="token keyword">end</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> nargs <span class="token operator">=</span> <span class="token string">'*'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>Setting the <code>nargs</code> option to <code>*</code> tells Vim that this command takes any number of arguments (Vim sees each space in the command as a different argument). These are collected for us as <code>input.args</code>, and we can execute those arguments as a command if they are supplied.</p>
<h2>Resetting the command</h2>
<p>I've also created another command to enable me to be re-prompted for a new command to store:</p>
<pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_create_user_command</span><span class="token punctuation">(</span><span class="token string">'SetTaskCommand'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token function">trigger_set_command_input</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><br> <span class="token comment">-- Don't need to do anything here beyond set it</span><br> <span class="token keyword">end</span><span class="token punctuation">)</span><br><span class="token keyword">end</span><span class="token punctuation">,</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre>
<p>And with that, it's done!</p>
<p>I hope you enjoyed this walk through the process of combining a couple of Vim plugins with some Lua to enable the desired workflow. This post also demonstrates why I was so keen to dive into Neovim rather than stick to Vim. I'd never written a line of Lua six months ago, and whilst I remain a complete beginner, it is a language that I think anyone with some programming experience can get to grips with, and I'm loving the ability to have more fine-grained control over my editing experience by writing code.</p>
<p>If you want to grab any of the code from this post, you can find it <a href="https://github.com/jackfranklin/dotfiles/blob/bda3964360ebf60330880416450357d3d672b815/nvim/after/plugin/neoterm.lua">in my dotfiles, which are on GitHub</a>.</p>
Things I've learned about building computers2023-05-31T00:00:00+00:00http://www.jackfranklin.co.uk/blog/learning-about-building-computers/<p>Recently a computer upgrade went from one graphics card to a new case, new fans
and a new graphics card. Along the way I learned a bunch and I'm writing this
blog post for future reference when I next perform a PC upgrade.</p>
<h2>Check your graphics card fits the case</h2>
<p>I was upgrading from a very old, and small, GTX 1060 up to a very large
GTX3080...naively assuming that my existing case would fit. It did not!</p>
<p>Lesson learned is to measure or find online the GPU dimensions; all cases will
specify the max size GPU that they support.</p>
<h2>Stock CPU coolers are loud</h2>
<p>I had been running the stock AMD CPU cooler since upgrading CPU about 4 years
ago, but when I plugged it in after upgrading the graphics card, it was running
incredibly loud. Not just that, but it would ramp up and down drastically for no
apparent reason.</p>
<p>Swapping this out for a better CPU fan (I went for the
<a href="https://noctua.at/en/products/cpu-cooler-retail/nh-u9s">Noctua NH-U9S</a>) made a
huge difference. However, the ramping up noise was still there...</p>
<h2>Upgrading the BIOS isn't so scary</h2>
<p>My motherboard is roughly 4 years old and I have never upgraded the BIOS. Given
that there had been so many updates over the years since purchase, I decided to
see if any of those might help with the fan ramp-up issue. I also figured it
generally would unlock more efficient running by installing years of bug fixes
and improvements.</p>
<p>The process wasn't too scary; I didn't go for the Q-Flash approach and instead
put the firmware onto a USB, booted into the BIOS and navigated through to the
ugprade options. Just make sure you get the right firmware! I came very close to
running the wrong firmware which would have left me with an expensive brick and
more money to spend on a mobo...</p>
<p>Once the BIOS is updated you might need to re-enable some settings. I had to set
the XMP profile again to make the most out of my RAM, and re-enable
virtualisation (SVM mode for AMD) so that WSL2 functioned correctly.</p>
<h2>Upgrade case fans to PWM</h2>
<p>Similarly to the stock cooler, I wasn't that impressed with the fans that came
with my new case
(<a href="https://www.scan.co.uk/products/fractal-design-pop-xl-silent-black-solid">Fractal XL Silent</a>)
and they were also 3 pin not 4 pin, which means they are not PWM fans. This
means that the computer can't smartly ramp their RPM up and down based on
temperatures.</p>
<p>Embracing Noctua once more, I went for a few Noctua 120mm PWM fans. I got two of
their premium <a href="https://noctua.at/en/products/fan/nf-a12x25-pwm">A12x25</a>. These
are a bit more expensive, but are incredibly quiet. I then got three more
cheaper <a href="https://noctua.at/en/nf-p12-redux-1700-pwm">P12 Redux</a> fans to ensure a
lot of airflow through the case.</p>
<p>Going into the BIOS and setting the fan mode to PWM has noticably reduced the
noise of the fans (and temps seem fine still). According to the internet, the
computer should detect PWM fans automatically, but not always. It is best to
explicitly set it if you only have PWM fans setup.</p>
<h2>Positive airflow</h2>
<p>Turns out it is important to think about the fans and what direction they are
blowing! It is best to maintain positive pressure in the case, which means more
fans bringing air into the case than blowing it out. Otherwise, in a negative
pressure setup, it is more likely that dust will get sucked into a case that is
desparate for fresh air.</p>
<p>Ideally the air should flow neatly through the case. I have 3 fans at the front
taking air in, and 1 at the front and 1 on top taking air out. I also aligned
the CPU fan with this so it sucks air in the same direction.</p>
Cracking Neovim code folding2024-02-29T00:00:00+00:00http://www.jackfranklin.co.uk/blog/code-folding-in-vim-neovim/<p>I have used Vim or variants like Neovim ever since the second year of
university, which means I've been using Vim for nearly 13 years (!).</p>
<p>In that time I have gotten very comfortable navigating my way through code and
codebases using Vim, and migrating to Neovim and its LSP setup has replicated an
experience very close to what VS Code provides, but with all the benefits (in my
opinion) of Vim.</p>
<p>One feature that I have never been able to get confident with is code folding. I
relied on it a lot during my roughly year long stint of VSCode + Vim mode but
just could not get a satisifying configuration and set of commands to make it
stick in Vim...until now!</p>
<p>The first step was
<a href="https://www.youtube.com/watch?v=f_f08KnAJOQ">Andrew Courter's video on code folding</a>
which helped me get some basic settings in place and understand my different
options for how folding should work in Neovim. Neovim is able to use many
sources of truth for folds, from basic options like code indentation, through to
LSP servers supplying that information.</p>
<blockquote>
<p>Andrew recommends the plugin
<a href="https://github.com/kevinhwang91/nvim-ufo">nvim-ufo</a>, but when I tried it I
found it decreased performance and felt "janky" - your mileage may vary as
it's clearly a popular plugin!</p>
</blockquote>
<h2>Folding configuration</h2>
<p>From Andrew's video I decided to try and set up folding again - firstly using
the UFO plugin as described above - before then deciding that I wanted to stick
to what was built in. After some experimentation I found the best combination of
settings that work for me:</p>
<h3>foldmethod and foldexpr</h3>
<p>I chose to use
<a href="https://github.com/nvim-treesitter/nvim-treesitter?tab=readme-ov-file#folding">treesitter</a>
as my source of truth for folding. I chose this over the LSP option as I don't
always work in codebases that have an LSP configured - especially if I am
quickly hacking on a script. By using the treesitter grammar, I ensure every
file I load will have it.</p>
<pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>opt<span class="token punctuation">.</span>foldmethod <span class="token operator">=</span> <span class="token string">"expr"</span><br>vim<span class="token punctuation">.</span>opt<span class="token punctuation">.</span>foldexpr <span class="token operator">=</span> <span class="token string">"v:lua.vim.treesitter.foldexpr()"</span></code></pre>
<h3>foldcolumn</h3>
<p>I don't like taking up room with an extra column to display information on
folds, so I turn this off.</p>
<pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>opt<span class="token punctuation">.</span>foldcolumn <span class="token operator">=</span> <span class="token string">"0"</span></code></pre>
<h3>foldtext</h3>
<p>By setting this to an empty string, it means that the first line of the fold
will be syntax highlighted, rather than all be one colour. I prefer this
visually to a formatted line representing the fold with no syntax highlighting.</p>
<pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>opt<span class="token punctuation">.</span>foldtext <span class="token operator">=</span> <span class="token string">""</span></code></pre>
<blockquote>
<p>At the time of writing this feature is only in Neovim nightly and not in the
stable 0.9.X releases.</p>
</blockquote>
<h3>foldlevel and foldlevelstart</h3>
<p>Setting <code>foldlevel</code> sets the minimum level of a fold that will be closed by
default. Therefore I set this to <code>99</code> as I don't want this behaviour at all.</p>
<p>However, I discovered that I can use <code>foldlevelstart</code> to dicate upon editing a
buffer what level of folds should be open by default vs closed.</p>
<p>After some experimenting, I settled on <code>1</code> for this value, meaning top level
folds are open, but anything nested beyond that is closed. I've found this helps
with navigating a large file as not all the contents will be expanded initially.</p>
<pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>opt<span class="token punctuation">.</span>foldlevel <span class="token operator">=</span> <span class="token number">99</span><br>vim<span class="token punctuation">.</span>opt<span class="token punctuation">.</span>foldlevelstart <span class="token operator">=</span> <span class="token number">1</span></code></pre>
<h3>foldnestmax</h3>
<p>This limits how deeply code gets folded, and I've found that I don't really care
for nesting some object 20 levels deep into a function (however rare that is!).
So I set this value to <code>4</code>, meaning that once code gets beyond 4 levels it won't
be broken down into more granular folds. I've found this means I can easily
toggle larger chunks of nested code as they are treated as one fold. I think
this a very subjective setting though!</p>
<pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>opt<span class="token punctuation">.</span>foldnestmax <span class="token operator">=</span> <span class="token number">4</span></code></pre>
<blockquote>
<p>You can find my folds config
<a href="https://github.com/jackfranklin/dotfiles/blob/master/nvim/lua/jack/folds.lua">as part of my dotfiles</a></p>
</blockquote>
<h2>Keyboard shortcuts</h2>
<p>I have to thank
<a href="https://gist.github.com/lestoni/8c74da455cce3d36eb68">Lestoni on GitHub for this gist</a>
which lists out all the shortcuts. I don't use them all but have come to rely
on:</p>
<ul>
<li><code>zR</code> open all folds</li>
<li><code>zM</code> close all open folds</li>
<li><code>za</code> toggles the fold at the cursor</li>
</ul>
<p>I'm also trying to get used to navigating via folds with <code>zk</code> and <code>zj</code> which
move up/down to the next fold, but that's not made it into muscle memory just
yet.</p>
<h2>Any suggestions?</h2>
<p>If you have any ideas for how I could further improve this setup, or suggestions
based on how you use folds, I would love to chat about it! You can find my
social accounts in the footer of this site :)</p>
Exhaustive branch checks with TypeScript2024-03-04T00:00:00+00:00http://www.jackfranklin.co.uk/blog/typescript-exhaustive-branches/<p>It's very common when working with TypeScript that you will have a type that
declares a list of values, such as an enum or union type:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">enum</span> SupportedColour1 <span class="token punctuation">{</span><br> <span class="token constant">RED</span><span class="token punctuation">,</span><br> <span class="token constant">YELLOW</span><span class="token punctuation">,</span><br> <span class="token constant">BLUE</span><span class="token punctuation">,</span><br><span class="token punctuation">}</span><br><br><span class="token keyword">type</span> <span class="token class-name">SupportedColour2</span> <span class="token operator">=</span> <span class="token string">'RED'</span> <span class="token operator">|</span> <span class="token string">'YELLOW'</span> <span class="token operator">|</span> <span class="token string">'BLUE'</span></code></pre>
<p>And then you will often have functions that need to run differently or return
different values based on what variant is passed in:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function</span> <span class="token function">codeForColour1</span><span class="token punctuation">(</span>colour<span class="token operator">:</span> SupportedColour1<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">string</span> <span class="token punctuation">{</span><br> <span class="token keyword">switch</span> <span class="token punctuation">(</span>colour<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">case</span> SupportedColour1<span class="token punctuation">.</span><span class="token constant">BLUE</span><span class="token operator">:</span><br> <span class="token keyword">return</span> <span class="token string">'#0000ff'</span><br> <span class="token keyword">case</span> SupportedColour1<span class="token punctuation">.</span><span class="token constant">RED</span><span class="token operator">:</span><br> <span class="token keyword">return</span> <span class="token string">'#ff0000'</span><br> <span class="token keyword">case</span> SupportedColour1<span class="token punctuation">.</span><span class="token constant">YELLOW</span><span class="token operator">:</span><br> <span class="token keyword">return</span> <span class="token string">'#ffff00'</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span><br><br><span class="token keyword">function</span> <span class="token function">codeForColour2</span><span class="token punctuation">(</span>colour<span class="token operator">:</span> SupportedColour2<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">string</span> <span class="token punctuation">{</span><br> <span class="token keyword">switch</span> <span class="token punctuation">(</span>colour<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">case</span> <span class="token string">'BLUE'</span><span class="token operator">:</span><br> <span class="token keyword">return</span> <span class="token string">'#0000ff'</span><br> <span class="token keyword">case</span> <span class="token string">'RED'</span><span class="token operator">:</span><br> <span class="token keyword">return</span> <span class="token string">'#ff0000'</span><br> <span class="token keyword">case</span> <span class="token string">'YELLOW'</span><span class="token operator">:</span><br> <span class="token keyword">return</span> <span class="token string">'#ffff00'</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<h2>Updating code when types change</h2>
<p>One thing that can catch you out is if the list of valid values in the type
changes. Let's say we want to add <code>GREEN</code> as a value to our union type (I will
drop the <code>enum</code> example for brevity, but the functionality for the sake of this
post is equivalent):</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">type</span> <span class="token class-name">SupportedColour2</span> <span class="token operator">=</span> <span class="token string">'RED'</span> <span class="token operator">|</span> <span class="token string">'YELLOW'</span> <span class="token operator">|</span> <span class="token string">'BLUE'</span> <span class="token operator">|</span> <span class="token string">'GREEN'</span></code></pre>
<p>In this case we will now get an error in this function. TypeScript will realise
that the function does not return anything in the case that <code>GREEN</code> is passed
in, but the error is not very obvious:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function</span> <span class="token function">codeForColour2</span><span class="token punctuation">(</span>colour<span class="token operator">:</span> SupportedColour2<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">string</span> <span class="token punctuation">{</span><br> <span class="token keyword">switch</span> <span class="token punctuation">(</span>colour<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">case</span> <span class="token string">'BLUE'</span><span class="token operator">:</span><br> <span class="token keyword">return</span> <span class="token string">'#0000ff'</span><br> <span class="token keyword">case</span> <span class="token string">'RED'</span><span class="token operator">:</span><br> <span class="token keyword">return</span> <span class="token string">'#ff0000'</span><br> <span class="token keyword">case</span> <span class="token string">'YELLOW'</span><span class="token operator">:</span><br> <span class="token keyword">return</span> <span class="token string">'#ffff00'</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<pre class="language-txt"><code class="language-txt">Function lacks ending return statement and return type does not include 'undefined'.</code></pre>
<p>If the function did not return a value, <strong>TypeScript will not error</strong> and it
would be easy to miss that we now have a branch (for <code>GREEN</code>) that is not dealt
with:</p>
<pre class="language-ts"><code class="language-ts"><span class="token comment">// This will not error in TypeScript, even though we are not</span><br><span class="token comment">// dealing with the GREEN case.</span><br><span class="token keyword">function</span> <span class="token function">logForColour</span><span class="token punctuation">(</span>colour<span class="token operator">:</span> SupportedColour2<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><br> <span class="token keyword">switch</span> <span class="token punctuation">(</span>colour<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">case</span> <span class="token string">'BLUE'</span><span class="token operator">:</span><br> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'User picked blue'</span><span class="token punctuation">)</span><br> <span class="token keyword">case</span> <span class="token string">'RED'</span><span class="token operator">:</span><br> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'User picked red'</span><span class="token punctuation">)</span><br> <span class="token keyword">case</span> <span class="token string">'YELLOW'</span><span class="token operator">:</span><br> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'User picked yellow'</span><span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<h2>Meet <code>ensureExhaustive</code></h2>
<p>To help prevent these cases falling through the cracks, and to improve compiler
errors to point us to the problem, all of my TypeScript projects contain this
<code>ensureExhaustive</code> helper:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">ensureExhaustive</span><span class="token punctuation">(</span>_x<span class="token operator">:</span> <span class="token builtin">never</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">never</span> <span class="token punctuation">{</span><br> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Reached a branch with non-exhaustive checks'</span><span class="token punctuation">)</span><br><span class="token punctuation">}</span></code></pre>
<p>To use it, ensure that whenever you are branching based on values, you have a
default case that calls <code>ensureExhaustive</code>:</p>
<pre class="language-ts"><code class="language-ts"><span class="token keyword">function</span> <span class="token function">logForColour</span><span class="token punctuation">(</span>colour<span class="token operator">:</span> SupportedColour2<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token keyword">void</span> <span class="token punctuation">{</span><br> <span class="token keyword">switch</span> <span class="token punctuation">(</span>colour<span class="token punctuation">)</span> <span class="token punctuation">{</span><br> <span class="token keyword">case</span> <span class="token string">'BLUE'</span><span class="token operator">:</span><br> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'User picked blue'</span><span class="token punctuation">)</span><br> <span class="token keyword">break</span><br> <span class="token keyword">case</span> <span class="token string">'RED'</span><span class="token operator">:</span><br> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'User picked red'</span><span class="token punctuation">)</span><br> <span class="token keyword">break</span><br> <span class="token keyword">case</span> <span class="token string">'YELLOW'</span><span class="token operator">:</span><br> <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'User picked yellow'</span><span class="token punctuation">)</span><br> <span class="token keyword">break</span><br> <span class="token keyword">default</span><span class="token operator">:</span><br> <span class="token function">ensureExhaustive</span><span class="token punctuation">(</span>colour<span class="token punctuation">)</span><br> <span class="token punctuation">}</span><br><span class="token punctuation">}</span></code></pre>
<p>Because <code>ensureExhaustive</code> takes in an argument of type <code>never</code>, which
represents values that cannot be observed, this code will now cause a compiler
error:</p>
<pre class="language-txt"><code class="language-txt">Argument of type 'string' is not assignable to parameter of type 'never'.(2345)<br>(parameter) colour: "GREEN"</code></pre>
<p>And TypeScript is able to tell us the exact value that we are missing from the
function.</p>
<p>This doesn't have to be used with <code>switch</code> statements either - it will work just
as well on large <code>if {} if else {}</code> branches too or in any other situation where
TypeScript is applying type narrowing as it reads through your code.</p>
<h2>Always ensure exhaustive checks</h2>
<p>I can't overstate how helpful this technique has become in my TypeScript
codebases. By getting into the habit of using it every time I have code that
deals with branching over multiple values I am reminded to ensure I have dealt
with every value explicitly, and I get told which code to update should the set
of possible values change.</p>