
Let's Build: a static blog with Harp - Part 1
As part of my first Let's Build, we are going to build a static blog site utilizing Harp. Harp is a Node based toolset that includes a static web server and preprocessing / compilation tools to take a variety of formats (EJS, Markdown, Jade, LESS, Sass, CoffeeScript) and convert them into their compiled / static assets (HTML, CSS, and Javascript).
Harp makes it easy to focus on writing instead of configuration and layout. In this series, we are going to utilize EJS for our views, Markdown for our blog articles, and some simple CSS for styling. Our demo site will be based on Twitter Bootstrap (specifically this Blog Demo Component)
At the end of Part 1, we will have :
- A site layout with partials
- A couple content pages
- A functional site hosted on Surge
You can follow along with me via Github by viewing the end of each step here: Step 1 Code
Let's get started
First things first, make sure you have NodeJs installed. Once you have done that, we need to use NPM to install Harp. I like to do this globally so I can use it to generate new sites when needed.
$ npm install -g harp
Once installed, let's make a new directory to hold our site. I should note
that Harp does come with an init
command that will initialize
a new boilerplate project for you, however, I like to start from
scratch in order to understand the structure a bit better. For this article
we are going to start from scratch.
At the start, we are going to need the following structure.
/ROOT
|-- /public
`-- harp.json
The /public
folder will be used to contain the public facing content for
this blog. Anything outside of this folder will be inaccessible when running
on a server. The /public
folder is a Harp construct, so it must be named public
in order for Harp to know how to handle the files. Alternatively, Harp does allow
you to treat the root as a public folder, but I like to play it safe and explicitly
provide the folder I want to use in case I need to keep things outside of it secret
(for example a readme.md for version control, etc.)
The harp.json
file will contain global meta data to be used throughout
the site. Harp will make the contents of this file accessible in our
templates.
In this harp.json
file we will add the following content:
{
"globals": {
"siteTitle": "Our Harp Blog",
"seoDescription" : "Our harp Blog"
}
}
The globals
section will be exposed to our templates so we can use any of
the properties within for rendering. For example, we will
use the siteTitle
property to set the site's Title. Feel free
to add any properties (with proper JSON structure) to this globals
section
in order to use them throughout your site.
Define our Layouts / Views
Now that we have the basic project structure set up, we can start adding our views and view layouts via EJS.
In our /public
folder let's add the following files:
-- public/
|-- _layout.ejs
|-- index.ejs
`-- about.ejs
Our _layout.ejs
file introduces an important rule for Harp: any files or folders prepended with
an underscore ('_') will be excluded from our final compiled output. However,
these files can still be used to provide data or layout assistance to those files
that are exposed publicly (in this case, the index
and about
pages.
The _layout.ejs
file will be used to house our global layout markup to be rendered
for every page in our site. This includes things like navigation and footer elements.
Essentially everything that wraps your article content will go in here.
In this file let's add the following markup:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="<%= seoDescription %>">
<title><%= siteTitle %></title>
<!-- Bootstrap core CSS -->
<link href="//getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="//getbootstrap.com/examples/blog/blog.css" rel="stylesheet">
</head>
<body>
<div class="blog-masthead">
<div class="container">
<nav class="blog-nav">
<a class="blog-nav-item active" href="/">Home</a>
<a class="blog-nav-item" href="/about">About</a>
</nav>
</div>
</div>
<div class="container">
<div class="blog-header">
<h1 class="blog-title">The Bootstrap Blog</h1>
<p class="lead blog-description">The official example template of creating a blog with Bootstrap.</p>
</div>
<div class="row">
<div class="col-sm-8 blog-main">
<%- yield %>
<nav>
<ul class="pager">
<li><a href="#">Previous</a></li>
<li><a href="#">Next</a></li>
</ul>
</nav>
</div><!-- /.blog-main -->
<div class="col-sm-3 col-sm-offset-1 blog-sidebar">
<div class="sidebar-module sidebar-module-inset">
<h4>About</h4>
<p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p>
</div>
<div class="sidebar-module">
<h4>Elsewhere</h4>
<ol class="list-unstyled">
<li><a href="#">GitHub</a></li>
<li><a href="#">Twitter</a></li>
<li><a href="#">Facebook</a></li>
</ol>
</div>
</div><!-- /.blog-sidebar -->
</div><!-- /.row -->
</div><!-- /.container -->
<footer class="blog-footer">
<p>Blog template built for <a href="http://getbootstrap.com">Bootstrap</a> by <a href="https://twitter.com/mdo">@mdo</a>.</p>
<p>
<a href="#">Back to top</a>
</p>
</footer>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="//getbootstrap.com/dist/js/bootstrap.min.js"></script>
</body>
</html>
This is slightly modified markup from the Twitter Bootstrap Blog Example. Within this layout, you will notice some EJS templating functionality.
<meta name="description" content="<%= seoDescription %>">
<title><%= siteTitle %></title>
<div class="col-sm-8 blog-main"> <%- yield %> <nav>
In the first example, you can see how we are pulling in the seoDescription
property from our harp.json -> globals
property. The same is true
for our use of the siteTitle
property. However, the <%- yield %>
example is used by Harp / EJS to know where to place the current content
within the template. This is where we are going to render all of our blog articles
and article listing pages (along with other supplementary pages like About).
Let's add the content for our index.ejs
and about.ejs
files:
index.ejs
<div class="blog-post">
<h2 class="blog-post-title">Sample blog post</h2>
<p class="blog-post-meta">January 1, 2014</p>
<p>This blog post shows a few different types of content that's supported and styled with Bootstrap. Basic typography, images, and code are all supported.</p>
<hr>
<p>Cum sociis natoque penatibus et magnis <a href="#">dis parturient montes</a>, nascetur ridiculus mus. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum.</p>
<blockquote>
<p>Curabitur blandit tempus porttitor. <strong>Nullam quis risus eget urna mollis</strong> ornare vel eu leo. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
</blockquote>
<p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p>
</div><!-- /.blog-post -->
<div class="blog-post">
<h2 class="blog-post-title">Another blog post</h2>
<p class="blog-post-meta">December 23, 2013</p>
<p>Cum sociis natoque penatibus et magnis <a href="#">dis parturient montes</a>, nascetur ridiculus mus. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum.</p>
<blockquote>
<p>Curabitur blandit tempus porttitor. <strong>Nullam quis risus eget urna mollis</strong> ornare vel eu leo. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
</blockquote>
<p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p>
<p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
</div><!-- /.blog-post -->
<div class="blog-post">
<h2 class="blog-post-title">New feature</h2>
<p class="blog-post-meta">December 14, 2013</p>
<p>Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean lacinia bibendum nulla sed consectetur. Etiam porta sem malesuada magna mollis euismod. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
<ul>
<li>Praesent commodo cursus magna, vel scelerisque nisl consectetur et.</li>
<li>Donec id elit non mi porta gravida at eget metus.</li>
<li>Nulla vitae elit libero, a pharetra augue.</li>
</ul>
<p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p>
<p>Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue.</p>
</div><!-- /.blog-post -->
Our index.ejs
file contains what we want to display when the user first
accesses our site. In this case, we want to display a list of our blog posts.
For now, we are going to leave the content static but we will eventually list out
our dynamic blog list.
about.ejs
<div class="blog-post">
<h2 class="blog-post-title">About</h2>
<p>Some information about this blog</p>
<hr>
<p>Cum sociis natoque penatibus et magnis <a href="#">dis parturient montes</a>, nascetur ridiculus mus. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum.</p>
<blockquote>
<p>Curabitur blandit tempus porttitor. <strong>Nullam quis risus eget urna mollis</strong> ornare vel eu leo. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
</blockquote>
<p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p>
</div><!-- /.blog-post -->
Our about.ejs
page is used to display the About content for our site. Usually,
this would give the user more information about you or the subject of your blog.
Compile and Running with Harp
With our current site:
ROOT
|-- public/
| |-- _layout.ejs
| |-- index.ejs
| `-- about.ejs
`-- harp.json
we are ready to compile and run the site locally. From the root of our project run
$ harp compile
The compile command will scan your folders and compile your site. If Harp runs
into any issues, it will let you know. If it was successful, a new www
folder will
be generated that will contain your static site in its entirety. It should
result in the following output:
ROOT
`-- www/
|-- about.html
`-- index.html
Likewise, as I often do, I will utilize HarpsJs's server
command to compile
and host the site locally. This utilizes a simple NodeJs server to watch
your solution and automatically render the site as you create it without
having to run the compile
command each time. Let's do this to view the site
we have created:
$ harp server
This, by default, will spin up a new server running locally at
http://localhost:9000.
If you run into Error: listen EADDRINUSE
issues it is because you
already have a server up and running on the localhost with the port of 9000.
You will need to specify a new unique port to use, something like:
$ harp server --port 8000
Now when you navigate to your site URL, you should see a functional
site with body content. In the navigation, click between the Home
and About
pages to see how the body content changes.
Deployment to Surge
Now that we have a functional site, we should push it up live so others can access it. For that, we are going to use Surge, which is a free static site hosting service. It has some seriously great, free features like:
- Custom Domain support
- Free SSL for surge.sh subdomains
- CLI deployments
In order to use surge, we need to install it via NPM:
$ npm install --g surge
One installed, let's make sure we compile one last time:
$ harp compile
then, we need to navigate into the www
folder
$ cd www
then simply run
$ surge
Surge will step you through setting up a new account (which it remembers for
subsequent commands). Once you confirm your project path, Surge
will let you know the size of your static site along with providing you
an auto-generated domain name. Feel free to change the subdomain to something
that works for your project (ex. harp-demo.surge.sh
).
After hitting enter, Surge should provide some context as to how long the deployment will take along with providing a progress bar. Once complete, the endpoint you pushed to should be available for browsing your site.
End of Part 1
With a functional static site hosted on Surge, we are done with Part 1. Recall you can find the final Part 1 source here: Part 1 Code For Part 2, we will:
- Updating our _layout.ejs with a cleaner layout using EJS Partials
- Utilize
_data.json
meta data files for more granular, per-page metadata - Create a few blog posts
- Dynamically list our blog posts on our
index.ejs
home page. - Update our navigation to display active states