News

Generate fast HTML applications with Harp.js

Discover the speed, workflow and financial benefits of creating a static site using Harp.js

harp01

With the advent and continued development and enhancement of blogging and CMSs, whether open source or commercial, everyone can have an online presence. People have the option to populate their own little slice of the web with whatever content they choose to.

While it may be insignificant to the majority of creative professionals, the hosting options still have an effect, not only on the performance and reliability of a site, but also the financial implications. It may be nominal, but even the cheapest of hosting solutions still cost money.

In this tutorial we dive into Harp.js, an open-source framework that has been built to make a site manager’s life easier. We’ll see how easy it is to build custom pages and routes, define meta data for not only global values but also specific pages, and ultimately export the app as compiled HTML, ready to be placed on any web server. It will save you time to develop and maintain and will reduce your hosting costs. It’s time to embrace the static sites again and make some music with Harp.js.

Install Harp

The Harp framework uses Node.js, so this must be installed first if you don’t already have it. Once installed we can use the package manager to install Harp onto our system. Open up a Terminal or a command window and enter the following command to install Harp as a global package.

001 > sudo npm install -g harp

Directory structures

Harp can run as a root application or within a sub folder of the root called ‘public’. We’ll use the latter version. Create a folder for your project, inside which we’ll also create a public directory. This will house the files that we want to serve publicly and helps define the URLs exposed by the application.

001 > mkdir harp_app
002 > cd harp_app
003 > mkdir public

Create pages

Let’s create two pages for our application. Harp has the ability to process and serve Jade, Markdown and EJS templates, as well as processing for CSS and JS files. Create the default homepage within the public directory, called ‘index.ejs’. We’ll also create a page using Markdown for the static contact information. Call this file ‘about.md’

 Global JSON data
We now need to define a JSON file that we can use to hold global variables. Without this file, the server will not find the files. Create ‘harp.json’ in the root of the project. Add in the name of your application and any other details you may wish to use throughout the site.

001 {    
002   “globals”: {
003     “title”: “Static Visions”,
004     “company”: “monkehComms”,
005     “pageTitle”: “Static Visions”
006  }

007 }

Global variables

With some global variables defined, we can use Harp to obtain these values from the ‘harp.json’ file and use them within our templates, with the exception of Markdown files, which cannot process dynamic values. Open ‘index.ejs’ and add the following code to the page to draw in the variables defined for display on the page.

001 <h1>Welcome to <%= title %> from <%= company %>!</h1>
002 <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>

Start the server

With the basic structure in place, we can now start the Harp server so that we can see our application as we work on it. Open the Terminal or command window and enter the following code to start the server. You can also change the default port number from 9000 if you wish by using the optional port flag in the command.

001 > harp server --port 9898
002 > harp server ./harp_app --port 9898

Create a layout

Let’s apply a layout structure to our application. Create a file called _layout.ejs within the public directory. The underscore at the start means it will not be publicly accessible. Add any HTML you require to build your design. The contents of the body tag must contain the yield variable, which will display the contents of each file served.

001 <html>
002   <head>
003     <title><%= title %></title>
004   </head>
005   <body>
006     <%- yield %>    
007   </body>
008 </html>

File meta data

Not all variables should be stored globally. Let’s create a new file called ‘_data.json’ in the pubic directory. This file will make any values included available to all templates within this directory and, if the value names match those in the global JSON file, it will override them. Here we are going to add some meta data for each page in our application.

001 {
002   “index”: {
003     “pageTitle”: “Home”,
004     “menuLabel”: “Home”
005   },
006   “about”: {    
007    “pageTitle”: “About”,
008     “menuLabel”: “About Us”
009   }    

010 }

Revise layout

As we have the potential to customise the layout for each entry using any of the provided meta data, we can adjust the generic layout file to include these values. Let’s amend the HTML title value to include the pageTitle value as well as the global title variable value.

001 <html>
002   <head>
003     <title><%= pageTitle %> - <%= title %></title>
004   </head>

Partial includes

Partials are a great way to separate content and structure code for reuse and modularity. Create a new directory called ‘_partials’ in your public directory and inside this create a new file called ‘_header.ejs’. This private file will be included on all pages as we’ll add it to the layout file, like so:

001 <body>
002   <%- partial(“_partials/_header”) %>
003   <%- yield %>
004 </body>

Loop over content

To keep our main menu as dynamic as possible – and to reduce hard coding paths – we can loop over the ‘_data.json’ file we created earlier and create a new list item for each value in the returned object. Here we reference the ‘_data’ file within the public directory and generate a link for each item, complete with custom menu label.

01 <nav id=”mainnav”>
002 <ul>
003 <% for(var slug  in public._data){ %>
004 <li>
005   <a href=”<%- slug %>”><%= public._data[slug].menuLabel %></a>
006 </li>
007 <% }; %>
008 </ul>
009 </nav>

Current state

Harp makes an object called ‘current’ available to each page request. This object holds the path and source identifier for the current page and is a great way to manage active states for navigation elements to highlight the selected menu item. Add the following code to the ‘_header.ejs’ partial file to set an active class on the selected menu item.

Add CSS

Harp has the ability to process and compile assets automatically for you, as we’ll see now. Create a new file called ‘main.less’ within an assets directory inside the public folder. Add your CSS rules here to apply to the application, and add the link reference to the ‘_layout.ejs’ file as ‘main.css’.

Add blog route

Add an additional object to the ‘_data.json’ file in the public directory to define the route for the blog posts. This will generate the relevant top menu button with the link to the resource once compiled. Create a new directory called ‘blog’ in the public directory inside of which our blog posts will reside.

001 “blog”: {
002  “pageTitle”: “Blog”,
003  “menuLabel”: “Blog”
004 }

Create posts

Each post within the blog directory can be written as static Markdown files, as nothing dynamic should be happening. You can, of course, write in any template language you choose if you wanted to. Name each post with the convention of the URL you wish to apply to it. Two sample posts have been included in the project files for you.

Combine tasks

With more than one task defined we would have to run each task individually from the command line. We can combine as many tasks as we wish and create a default that will run when we write ‘grunt’ or ‘grunt default’ in the command line. This new task will run each task specified, saving us time.

Post layout file

The blog posts will use a variation on the default layout file as we want to output information such as the blog title and the meta information for the date posted. Create a new ‘private’ file called ‘_postLayout.ejs’ within the blog directory and add the following code to create the HTML structure.

<html>
002   <head>
003     <title><%= title %></title>
004     <link rel=”stylesheet” href=”/assets/css/main.css” />
005   </head>
006   <body>
007       <div class=”container”>
008         <%- partial(“../_partials/_header”) %>
009         <h1><%= title %></h1>
010         <%- yield %>
011         <div class=”subMeta”>
012         Posted: <%= date %> by <%= author %>
013         </div>
014       </div>
015   </body>
016 </html>

Post listing

Create ‘index.ejs’ in the blog directory. This will be the default page loaded for the blog view, and we want to list the available blog posts. To do so, we can loop over the ‘_data.json’ file in this directory and generate the list with the blog excerpt and meta data, as seen below.

Write JavaScript functions

To obtain the excerpt of the blog post, we called a function called ‘excerpt()’ in the previous code block. This function is added to the top of the ‘index.ejs’ file, wrapped within the <% %> tags to produce and execute the JavaScript. This finds an instance of the <!– more > tag in the content and only displays content up to that point.

001 <% function excerpt(content) { %>
002   <% return content.split(“<!-- more >”)[0]; %>
003 <% }%>

Menu issue

Our partial include for the header menu will not set the active class to the blog menu item when we view that page, as it doesn’t pick up the correct slug value. Add the following function to the top of the ‘_header.ejs’ file to find the index of the slug within the current.path value instead.

Change class setting

To change the menu list item to use the new function we need to amend the conditional statement within the list item in the ‘_header.ejs’ file. If the index value matches and equals 0, the active class will be set to the element. Save the change and test the menu in the browser.

Compile static content

The beauty of HTML static sites is that they can be hosted anywhere without any specific server-side language requirements. To export the project as a complete compiled HTML structure, open the Terminal or command window and enter ‘harp compile’, followed by the location of the application and the destination location to send the compiled pages, as demonstrated in the following code snippet below.

001 > harp compile ./ ~/Desktop/compiled_export
×