Nested Layouts in HarpJS

Currently it isn’t possible to use nested layouts in HarpJS. But with a little work you can support it easily enough. Here is a solution (with an alternative) that you can use until (if) HarpJS supports it natively in the future.

First, a reminder. By default, if you have a _layout.ejs (or .md, or that other template engine) in your folder, Harp will take the content of your current page and send it to the layout script as a variable, yield. So a simple layout could look like this:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
</head>
<body>

	<%- yield %> 
	
</body>
</html>

If you have a subdirectory, it can also specify a _layout.ejs file. When Harp encounters this file, it runs that layout instead of one higher in the directory structure. While you have the option to select a different layout template (in data.json) or ask for no layout, you can’t have wrapped layout – i.e., use the current layout and then send the result to the parent layout.

This can solved by simply using partials in your layout file. These partials can then be loaded by other layout scripts. So imagine this as your main site layout.

<%- partial("_main_header") %>

<%- yield %>

<%- partial("_main_footer") %>

All I’ve done is taken the code that would have normally been above and below the yield statement and moved them into a partial. Now imagine I’ve got an articles folder with its own layout. I want to include the main site layout as well. This is all I do:

<%- partial("../_main_header") %>

<h3>Article Header</h3>

<%- yield %>

<h3>Article Footer</h3>

<%- partial("../_main_footer") %>

Boom. That’s it. This works, but the more I use Harp, the more I become concerned with creating nice, maintainable scripts. I’ve noticed that many themes (including the one on my blog), suffer from “Div-Itis”. You all know what Div-Itis is. You view source on a page and see approximately 30 different layers of div tags. I cant tell you how many times I’ve accidentally broken a layout because I screwed this up. I also can’t tell you how many times I’ve said, “Screw it, let me add a closing div tag” in an attempt to fix something.

The solution above works, but separates my layout into two files (ok, technically three, but I’d never update the main layout again), so I wondered if it could be done better. I came up with another solution that uses the ability to pass variables to partials. Remember, partials in Harp are more than just include. You can pass data to them and they can react accordingly. I’m going to use a trick I’ve used for over a decade now when building ColdFusion templates.

<%- partial("_main", {mode:"header"}) %>

<%- yield %>

<%- partial("_main", {mode:"footer"}) %>

I’ve made a new partial, called main, and I pass a mode value to it. Now let’s look at main.ejs.

<% if(mode === "header") { %>

<h1>MAIN HEADER</h1>

<% } else { %>

<h2>MAIN FOOTER</h2>

<% } %>

As you can see, I’ve simply added an IF clause that selects which branch of my layout to render. I’ve got some code intertwined in there, but at least I can look at the entirety of the template all at once.

I’ve included both demos as an attachment.

Download attached file.