Node at Work: A Walkthrough

In my first article, “Even Better In-Browser Mockups with Node.js,” I explained why Node.js makes designing applications easier and more efficient, and how to get started. Now it’s time to see your new design process in action.

Article Continues Below

Rather than figuring out all your requirements and API schemas just to design your comps with mockup content hard-coded and server interactions faked—only to throw it all away when you go back and implement things “for real”—you can use Node.js to skip the hard-coding and produce client-side code that’s ready for beta at the end of the design stage.

The process looks a lot like good ol’ designing in the browser, but with more JavaScript and an additional layer:

  1. Design the layout and styling
  2. Convert the markup to a JavaScript template
  3. Create an initialization function
  4. Create a simple Node.js server
  5. Add a mockup data object to the server
  6. Add server functions to serve static pages and JSON
  7. Request and consume the JSON on the client

Sound daunting? Don’t worry. The first step takes approximately a zillion times longer than any of the others. So if you’ve already mastered the design, you’ll find the rest of these steps more than manageable.

In this walkthrough, we’ll build a feature for a mock art store. If you want to follow along at home, you can clone my GitHub repository. (If you need help installing, see the README, or just take a peek at the live demo—I’ll cover all the steps and code below.)

Creating templates#section2

Once you have a solid design and the markup to accompany it, converting it to a template you can use for all examples is more efficient than creating duplicate markup for each one. The hard part’s over; you already thought about where data points would be used in the design when you created it. With those choices fresh in your mind, go back and mark up your HTML with data in whatever template language you prefer.

For my example, I’m using a store selling art prints. Here’s a snippet of my initial markup:

<h2>Two Acrobats with a Dog</h2>
<h3>Pablo Picasso</h3>
<img src="img/102.jpg" alt="Two Acrobats with a Dog" class="active" />
<ul class="info">
	<li>8" x 11"</li>
	<li>acid-free paper</li>
	<li>suitable for matting</li>
</ul>
<span class="price">$49.99</span>

Think of your templates as places to define your requirements for both data and its formatting on the client side. If you can also reuse it for client-side rendering, that’s awesome—but that may not be relevant to your application. As long as you have good data, converting from one template language to another is trivial, so don’t agonize over which template engine to use.

You do need a template engine that will work in both the browser and Node.js, however. If you’re unsure, search for your template engine on GitHub and verify that there’s a guide to installing it via npm in the manual, as well as a minified script for use on the client. I prefer doT.js, so here’s that snippet again marked up to add data using doT:

<h2>{{=it.title}}</h2>
<h3>{{=it.artist.name}}</h3>
<img src="img/{{=it.id}}.jpg" alt="{{=it.title}}" class="active" />
<ul class="info">
	{{~it.info :info_item}}
	<li>{{=info_item}}</li>
	{{~}}
</ul>
<span class="price">{{=it.price}}</span>

I like to save my templates in their own directory at the same level as my JavaScript directory, so now I store that as tmpl/detail.dot.

Initializing the client#section3

Since we want to be able to use our templates in both Node and the browser, they need to be stored outside of the HTML and loaded and compiled when we open the page. To start, save the minified version of your template engine and add a script tag to your page to include it. Once that’s done, you can fetch the template, compile it, and then continue on with any other initialization work in your main JavaScript file. I’m using jQuery in my example, so my code looks like this:

var detailTmpl;

$.when( 
	$.get( "tmpl/detail.dot", function( tmpl ) {
		detailTmpl = doT.template( tmpl );
	}, "text" ) 
).then( init );

That mysterious init function? That’s where I’ll put any interactivity I want to add to my currently static mockup. For the moment I’m only creating one interaction, so my init function is pretty simple:

function init() {
	$( "div.content" ).on( "click", "div.result", showDetail );
}

This code can be made much more elegant using Require.js with its text plugin. That’s beyond the scope of this demo, but I highly encourage it for production.

We’ll handle template rendering in showDetail(), but we have to add a server and data store before writing that function, since right now we lack any data to render.

Creating a server#section4

If I reload my page now and open the browser console, I get a JavaScript error. That’s because I’m trying to load my template via an XMLHttpRequest (XHR) on a page being served from the file system, in violation of the same origin policy. I can’t even check that my template works until the page is served properly (i.e., from a server).

To whip up a simple Node server that allows me to run my XHRs, I do a few things:

  • Move all my existing assets into a new subdirectory called public
  • Open my terminal or command line to my working directory and run npm install express
  • Add a server.js file to the working directory

We could write everything from scratch, of course, but it’s more work than is necessary for a basic server. The Express framework provides a number of abstractions of server and application concepts. For the initial version of the server, the only one we’ll need is its ability to serve static resources. We can use it by adding four lines of code to server.js:

var express = require( "express" ),
	app = express();

app.use( express.static( __dirname + "/public" ) );

app.listen( 3000 );

Once you start your server by typing node server.js in your open terminal or command line, you can view your page at http://localhost:3000 (adding a filename if necessary), and the error related to loading the template ought to disappear.

Adding server-side data#section5

While it’s certainly nice to be able to use XHRs, we’re creating the Node server to use it as a representation of the real server—and real servers store data. Though it’s not hard to create a data store that works with a Node server, it’s even less difficult to create one big object literal. For a mockup, that’s all we really need. One of the goals here is to define the data objects we need to support in our new design, so the format of this object can be determined by the template we just added. For my example, I need an object structured something like this:

var products = {
	"102": {
		id: 102,
		title: "Two Acrobats with a Dog",
		artist: {
			name: "Pablo Picasso"
		},
		price: "$49.99",
		info: [
			"8\" x 11\"",
			"acid-free paper",
			"suitable for matting"
		]
	}
};

Note that products could just as easily be an array, but I want to be able to quickly find my products—once I have more than one in my fake data store—by ID. Aside from that little twist, the data look exactly like the content hard-coded in my original HTML. If I want to add more data, including things that might break the layout in unpredictable ways, I can just copy this structure and make substitutions. Well, almost.

Returning data from the server#section6

If you’ve dealt with other server-side frameworks, creating endpoints for XHRs might seem intimidating, but Express makes it really easy. We don’t need any special setup to define a server endpoint as a target for asynchronous requests. All we have to do is define the path on the server where we want to accept requests and a callback. The callback receives a request object (for doing things like getting passed-in data) and a response object (for defining what we return to the client). To return the data in my products object, I add a few lines of code at the bottom of server.js:

app.get( "/detail/:id", function( req, res ) {
	res.send( products[ req.params.id ] );
});

app.listen( 3000 );

See? Easy. If I restart my server and go to http://localhost:3000/detail/102, I should see my object data. To break down what’s going on with the ID in the path, we’ve named the data at that position in the path "id" with the :id bit, and it then becomes available as a property of req.params.

The names and positions of parameters are up to us, and if our path were super complex, we could also use regular expressions to split out multiple pieces of data. Express also gives us the option of accepting data from the query string or from a POST. Of all the pieces we’re creating, however, the paths are the most likely to change in production, so it’s to our advantage to keep them as readable as possible.

Besides sending pure data to the client, we also want to be able to send rendered HTML, in case a user is linked directly to a product detail or doesn’t have JavaScript available. We might also want HTML for our own consumption via XHR, if we find that client-side rendering is slowing us down. So we add a second endpoint below the one we just created to do that:

app.get( "/product/:id", function( req, res ) {
	res.render( "detail", products[ req.params.id ] );
});

For simplicity’s sake, and because the first path served JSON for an overlay while this provides a full page, I’ve used a different pathname, but kept the same pattern. This time, instead of the response’s send function, I use render(). Express provides some magic to make template rendering work out of the box, but since I’m using doT instead of Jade (the default template engine of Express), I have to do some additional setup.

First I have to go back to the terminal or command line, stop my Node server, and install my template engine using npm install doT and the consolidate module (which provides Express compatibility for a number of popular template engines) using npm install consolidate. Now I’ve got both of those in my node_modules directory and can use them in server.js.

Since doT (and probably your template engine of choice, as well) is accessed through consolidate, consolidate is the only additional module I need to require at the top of server.js:

var express = require( "express" ),
	app = express(),
	cons = require( "consolidate" );

I want to continue serving some of my other pages statically, so I add my template configuration stuff below the existing app.use line in my code:

app.use( express.static( _dirname + "/public" ) );
app.engine( "dot", cons.dot );
app.set( "view engine", "dot" );
app.set( "views", _dirname + "/public/tmpl" );

Those three new lines set doT (as exposed by consolidate) as the view engine, register files ending in .dot as templates, and tell Express to look in /public/tmpl for templates to use. So when Node sees res.render( "detail", { ... } ), it knows to expand "detail" to /public/tmpl/detail.dot and render it as a doT template. Now I can restart my server, go to http://localhost:3000/product/102, and see my template rendered statically, without creating a separate server-side file.

Fetching dynamic data#section7

Our template now works as a static page, but there’s still one more step to get our mockup populated with the data from the server. Remember the showDetail function from our main client-side script? It’s time to flesh that out.

In my simple example, the overlay my template will populate already exists as a hidden div on the main page, and it appears when the user clicks a div containing a summary of the content. This div has a data attribute storing the ID of the product that corresponds to the key and id property in my server-side data object. Once that click event happens and showDetail() is called, I just need to do this:

function showDetail( e ) {
	var id = $( this ).data( "id" );
	$.get( "detail/" + id, function( info ) {
		$( "div.detail" ).html( detailTmpl( info ) );
		$( "div.detail" ).show();
	}
}

The path above is the same one I defined in server.js. If you chose a different name for yours, use that name here on the client. When I receive the data object from the server, I pass it to detailTmpl(), the compiled version of my template. The result of the detailTmpl function is the HTML to populate my overlay.

Onward#section8

So there you have it! A mockup that mimics the interactions it will have with its production server precisely on the client, without the need for hard-coded data or temporary workarounds. Despite the simple exercise, the process I’ve outlined accomplishes a good deal of the setup necessary to create other workflows that require server interactions. For instance, I can fill my fake data store with more products and use that to render the initial page that triggers my overlay without having to revisit my mockup data, and my application will show the correct values in any view I add to it.

If you’d like to explore beyond just serving HTML and JSON, consider adding in Socket.io to allow real-time interaction for multiple clients or Require.js to manage your assets on the client. You could also move your CSS into templates and serve different builds of your site for different browsers or devices. Your mockup can be as sophisticated and reflect as many of its production requirements as you choose. At the end, the lion’s share of your client-side code is done and ready to use.

20 Reader Comments

  1. Another option for controlling AJAX responses is Robohydra written by Opera. It gives you an admin interface where you can easily attach and detach responses, however I would first recommend going through the article just to have an understanding of how the node.js underbelly works in this situation.

  2. @Daniel Grocock – That’s a pretty broad question.. I think the correct answer is: probably. It really depends on what you need to do, though. It likely won’t come down to an issue of power so much as whether using Node offers an advantage for the kind of work your app is doing.

    @Matt Frysh – Absolutely, good call. Once you’re comfortable with generic tools and modules that fit a wide range of use cases, there’s a ton to explore to abstract away boilerplate code for more specific tasks.

  3. I was able to get the Cool Art Store site to render just fine on a unix box once I unblocked port 3000. You may want to point this out, since any decent firewall closes off all ports by default and those which are needed for some purpose have to be explicitly opened. It looks like you are using a model-view-controller framework here but without a longer introduction most of your excellent article is lost on me. I’m sure I need to study the documentation better — for example, learn about Express and XHR. Thanks for a most helpful getting-started download.

  4. Interesting idea, but in my opinion using Node.js for a simple mockup with a handful of templates is overkill. Node.js is still a very new technology, and it has a significant learning curve for the uninitiated.

    What’s more, the main feature of Node.js is asynchronous I/O. For the example given in this article, virtually no I/O takes place (minimal file reading, no database, no socket / network stuff). So, what’s the payoff in using Node.js instead of a more established technology?

    I’ve built basic mockups with templates on several occasions, over the years, using PHP (by itself, without a CMS or framework). Write some clean template files (e.g. for base, header, footer, article, sidebar, etc). Define structured data in some associative arrays. Really quick ‘n’ easy.

    The example presented in this article isn’t rocket science, and it isn’t anything that’s never been possible before now. The only reasons that I can really think of, for building such a simple tool in Node.js, would be (a) for novelty’s sake; and (b) as a beginner learning exercise in Node.js.

  5. @Jeremy, I’m extremely grateful that Garann published these articles because otherwise I’d never have looked at node.js. My experience is that any tool that offers good mockups with the option to make those mockups a lot more complex is worth looking at and implementing. All programming languages and web-based technologies are difficult to learn. The term “mockup” can mean different things to different people, so I would say that any tool that offers a way to render and inspect the final design and its many interactions at low cost is worth investigating and working with. It is up to the user to squeeze some juice from the tool in light of his or her particular project. Garann presents a technology that is interesting to explore.

  6. @Bob Cochran – That’s a good point about ports. Thanks for adding it – I hadn’t even considered it.

    If you mean Express when you mention MVC, it definitely has much more power than what’s shown here, but it’s also a great tool for getting started. And, as you mention later, it can be extended into something much more involved, which is why I’m a fan of the framework.

    @Jeremy P Epstein – The two main reasons I’d choose Node for this over PHP would be 1) being able to share resources between the client and server, and 2) not knowing PHP. The latter is an annoyance I feel personally, as a former .NET and Java developer. The former, to me, is the big payoff.

    Especially for mocking-up (but also for production where possible) I like the DRYness of not translating logic and templates for two different languages. As single-page apps become more prevalent and more logic exists on the client, this becomes more and more valuable in my non-mockup work, and starting in Node makes it really easy.

    You’re absolutely correct that this demo doesn’t show off Node’s real strengths in terms of what you can do when everything is async. But it’s only meant to help people unfamiliar with Node get comfortable using it. I’d love to see another more focused article on A List Apart someday talking about some of the awesome possibilities it opens up!

  7. This is the start of my 4th night of working with Node, Express, and doT. It is a big challenge for me. I downloaded the “coolartstore” code from GitHub, got the index.html page from that to render completely as a check on how correctly I had installed Node and also whether whether there were networking issues.

    Then I set out to create my own page, my own template, and my own app, using coolartstore as a guide. My goal: create a doT template which can be rendered to hold the heading “Hello world from Bob”, and then move that template inside the index.html content. The name of the template is hello.dot.

    The template renders just fine, that is I can go to http://localhost:3000/hello and see the rendered template. Since it is just an h2 heading inside a div, it of course shows on the browser as black text on a white background.

    The index.html page renders just fine, too: I can go to http://localhost:3000/ and see a the page rendered very nicely in coolartstore regalia, since I reused the css. I took out all the coolartstore markup and replaced it with a line of my own, an h1 heading. Only the header and footer content shows. I can’t get the template to render inside the index.html page.

    I closely read this article each day. I have two printed copies of it with copious notes penned in the margins. I believe I have to load the hello.dot template into index.html using javascript that is in the script.js file from coolartstore. That must be what is escaping me. I thought Express was using some magic in app.get to cause the template to be injected into the index.html. Since I’m new to JavaScript, that is a fun challenge, too. I’m aware that the Javascript is actually using jQuery. I’m hoping to use plain old Javascript since jQuery would add more complexity to my learning curve.

    Tonight I’m hoping to figure out how to get my hello.dot template to work inside the index.html. Slowly I am succeeding.

  8. The index.html page renders just fine, too: I can go to http://localhost:3000/ and see a the page rendered very nicely in coolartstore regalia, since I reused the css. I took out all the coolartstore markup and replaced it with a line of my own, an h1 heading. Only the header and footer content shows. I can’t get the template to render inside the index.html page.

    ���ジカメ撮影の方法

  9. @Bob Cochran – You’re correct, you’ll need to modify script.js to load and render your new template. Wanting to start with vanilla JavaScript instead of jQuery is a noble goal, but it might be easier to begin by substituting your template for the templates currently being loaded with $.get(), then replacing everything in the init() function with a simple assignment to innerHTML for an element that exists in your new index.html page. Hope you’re able to get it working!

  10. @Garann — Thank you very much for your help. I’m still playing with trying to code JavaScript myself. I’m stubborn and trying to succeed with it without using jQuery. I hope to succeed with an XMLHttpRequest at some point. I can see the results of the http requests because I turned on the logging feature in Express. For instance I see the GET for template tmpl/hello.dot showing up in the console log, but I can’t “find” the actual template content (not yet anyhow.) It took me a while to understand that an HTTP 304 response means no file data will be returned in the response object. It is in the browser cache. I learned how to code a time stamp and append that to the tmpl/hello.dot URL, and now the GET has a 200 status code, but I still need to find the actual data. I will read about the XMLHttpRequest documentation on the W3C site and keep trying.

    If all else fails, I will use jQuery and hope to go on and learn the techniques I missed later.

  11. I’m still working on doing a direct XMLHttpRequest for my template file “tmpl/hello.dot”. I’m closer to success but not quite experiencing success yet. If you issue an XMLHttpRequest and set the responseType to “document”, as one would seem to need to do for html, and then display all of your response headers that come back from the server in an alert box (a lovely beginner’s debugging method), you will notice that Express will list the mime type of the content as ‘application/msword’. Well, normal.dot has been around quite a long time as a Microsoft Word template, right? So it is understandable if Express thinks a dot template is something from Microsoft Office. This affects what data is going to be returned in the entity body of the response. I used the overrideMimeType method to change the final mime type to ‘text/html’ and now a reference to, e.g. this.response is returning something like: “HTML-object’, so I think I am getting warmer. I will continue working on this puzzle later this evening. I’m learning useful stuff — I think — and hope to succeed with continued patient try, try, try again. There’s always jQuery if I flub it.

  12. I succeeded at last! Reading the whatwg.org documentation for asynchronous XMLHttpRequest helped a lot, and getting a few quick lessons on Firebug and then just examining the Document Object Model output helped even more. My JavaScript is slowly improving. Now I have the beginning of a vegetable gardening website that I can mock up. I focused so much on the XMLHttpRequest stuff that I got sidetracked from learning and using Express, but that is okay, I am happy to be on a success track now. I’m still learning. Now if I can put Young’s mapping tutorial to use in a Node.js context, I might just have a gardening website that will prompt visits to the actual gardens.

  13. Node does make an excellent platform for mockups. However, I highly recommend using Lineman.js (built on grunt/node) that makes it even easier to get up and running with client-side webapps.

    I forked the Cool Art Store demo project and created a ‘lineman’ branch to show how easy it is to build mockups and other fat-client webapps with Lineman.

    I also wrote up a blog post on some of the benefits you get with Lineman.

  14. If you think Francisco`s story is super,, five weeks ago my brothers mother in-lw basically broght in $4217 sitting there an eleven hour week from there apartment and their roomate’s step-mother`s neighbour done this for nine months and recieved a check for over $4217 parttime from a laptop. use the information here… http://m3mi.com/3621CHECK IT OUT

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career