Rebuilding my first website ... with pug!
Intro
I was cleaning up some old files in my macbook the other day and found the first website I’ve ever built. I was into book design and typography by that time, so I self-published some books with one of my friends and we needed a nice website to show off our books. I did not know much about web development and all I had was some basic HTML, CSS, and JS skills. I created a bunch of .html
files that contain all the text chunks for each page and one single .css
file that handles the style of the whole website. After putting in hours of hard work, I was able to build a static site that introduces our projects.
However, even though I was very proud of my work, something just did not feel right. I was taught to avoid code repetition from my first programming class at my university, but I was repeating the same code again and again throughout the website because I could not find any other way. For example, when I tried to add a navigation bar to the website, I had to repeat the same code for generating the nav bar in index.html
, book1.html
, book2.html
, about.html
, and so on. I only had to repeat seven times because there were a total of seven .html
files, but obviously it was not the best way to build a website in terms of scalability. And this was not only for the nav bar. I had to include the same <head></head>
section for each page so that I can inject the style to each page. It would have been much easier if I had used some kind of template to generate the basic structure of the website.
Rebuilding the website with pug
Pug is a template engine that generates .html
files using its own syntax. It is powerful not only because it enables to write reusable HTML, but also it understands Javascript and makes the code dynamic.
Rewrite the head section
The main problem with the original code for the head section was that because every page needs the head tag, I had to include the same code block in every .html
file. However, this can be easily solved with pug. Let’s see the actual use case.
<!--
index.html
-->
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>파킹스페이스*</title>
<script defer src="p5/libraries/p5.min.js"></script>
<script defer src="p5/libraries/p5.dom.js"></script>
<script defer src="asterisk.js"></script>
<script defer src="asteriskClass.js"></script>
<link
rel="apple-touch-icon"
sizes="180x180"
href="favicon/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="favicon/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="favicon/favicon-16x16.png"
/>
<link rel="manifest" href="favicon/site.webmanifest" />
<link rel="stylesheet" href="_base.css" />
<link rel="stylesheet" href="styles.css" />
</head>
This can be rewritten with pug like this:
// head.pug
head
meta(name='viewport', content='width=device-width')
meta(charset='utf-8')
title parkingspace*
// loading p5 animation
script(defer, src='/p5/libraries/p5.min.js')
script(defer, src='/p5/libraries/p5.dom.js')
script(defer, src='/asterisk.js')
script(defer, src='/asteriskClass.js')
// favicon
link(rel='apple-touch-icon', href='favicon/apple-touch-icon.png')
link(rel='icon', href='favicon/favicon-32x32.png')
link(rel='image/png', href='favicon/favicon-16x16.png')
link(rel='manifest', href='favicon/site.webmanifest')
// style
link(rel='stylesheet', href='_base.css')
link(rel='stylesheet', href='styles.css')
Base layout
With pug, it is now possible to have one single layout and customize it for different context. This helps us to manage the overall consistency of the website and avoid rewriting the repeating parts.
// layout.pug
// This is like a function in pug
// I'm defining a function that takes href attribute and name
mixin link(href, name)
h1.title
a(href=href)= name
mixin nav-link(href, name)
li
a(href=href)= name
doctype html
head
// I'm injecting the head section I wrote above using the include syntax
include includes/head.pug
body
.container
header.top
// this is how you use the mixin function
+link('/', 'parkingspace')
+link('/about', 'about')
// Add a nav bar to the page
nav.bottom-nav
ul
+nav-link('/name-card-2020', 'name card')
+nav-link('/asterisk-emitter', 'asterisk_emitter')
+nav-link('/imsibogwanham-2020', '임시보관함')
+nav-link('/perfect-circle-2019', '완벽한 동그라미를 그리는 법')
+nav-link('/tmmg-2017', '타오르지 못하고 명멸하는 것들에 관하여')
.right-display
block right-display
Now that I have the base layout, I can easily construct all other pages based on this layout. This means that I don’t need to repeat my code for adding the nav bar/head section for other pages.
To add this layout to the page, you just use the extends keyword.
// index.pug
// Add the layout using the extends keyword
extends layout.pug
block right-display
.img-gallery
.tmmg
img(src='/img/img2.jpg')
Customize the page
To make your website more dynamic, you need to be able to customize each page that uses the same layout. You can use the block syntax to achieve that.
In the layout.pug
, I added a block with a name at the very last, meaning that I will add a block at this location. To add your custom code block, you use the block [your-blockname]
syntax in the file that extends the layout.
// layout.pug
// ...
block right-display
// index.pug
extends layout.pug
// ...
block right-display
// block content
Outro
This was my first experience building a website with pug. I’ve only looked at a very small portion of what pug is capable of, but that was enough to see how powerful this template engine can be. If you are interested in reviewing the code, it is on my github repository, and you can also visit the website I published via heroku. Please note that the code is not properly optimized for production, but only to demonstrate how pug can be used to reduce the amount of code blocks that are repeating. If you want to learn more about the pug, I recommend reading through the documentation .