So far in this series, I have covered basic templating and how to use logic when creating a frontend with Pug. Those things are enough to get a frontend up and running, but there's still more to learn which can make your developer experience much better. That's what I will be talking about in today's post.
How do I create layouts in Pug?
Pug allows you to use inheritance to create a layout for the frontend and then insert blocks of data into the layout where appropriate. If you've ever worked with something like Laravel, React, or even WordPress then this concept should feel somewhat familiar. If you haven't don't fret. I will explain what this means and why it's useful.
Imagine a time when you built a website using plain HTML and had to copy and paste the header and footer to every single HTML file you wrote. Then if you needed to update something down the road, you'd have to check EVERY SINGLE PAGE to make sure you updated it, lest you end up with broken links or images.
Template inheritance
Pug solves this issue using inheritance. What that means is that you can write your header and footer once, then extend it where you want it. This is beneficial for a few reasons: first, it saves lots of time because you don't have to write the same thing over and over (or copy and paste while checking formatting), and second because when an update is needed it can be done in one place. This is one way Pug allows you to follow a DRY (Don't Repeat Yourself) pattern when building things. The example below shows how you can set up a layout with a header and footer.
// layout.pug
html
head
title My Site - #{title}
body
header
a(href='/') Home
footer
p Site Footer
Great! Now you've created a layout that doesn't actually do anything at the moment. How is that useful? In order to understand that, we need to talk about the other part of this section: blocks.
Adding blocks to a layout
To take advantage of the inheritance system, you will need to understand the concept of blocks. In short, you can specify places in your layout where content should be filled in. These places are called "blocks" and you create them by assigning them a name and then filling them out in other files. Think of it like a hamburger: We know we need a bun and patty on every burger, but we don't know what toppings are needed. In this example, the buns and patty would be the layout and the toppings would be the block so we can change the content without having to rewrite everything around it. Below is an example on how to set up blocks in the layout.
// layout.pug
html
head
title My Site
body
header
a(href='/') Home
block content
footer
p Site Footer
The change in the example above is pretty small. If you weren't looking for it, you might even miss it. All I did was add a block content
where I wanted dynamic content to go. The block
keyword is what indicates to Pug that this section is a block. The content
is just an arbitrary name I created to indicate which block I wanted to place the content into. Blocks can be created wherever you like in the layout. Now that you have a block in place, how do we put content there?
Adding content to blocks
// hello.pug
extends layout.pug
block content
h1 Hello, world!
The example above shows how to add dynamic content into the layout of a site using blocks. The first line is where you extend your layout file to include the contents of this file. It should be noted that the layout.pug
portion of this line is actually a location relative to the current file, so in this example the current file and the layout file would be located in the same folder.
Below the extends line, you can see a block content
section just like in the layout file. This is where you will insert dynamic content which will replace the block content
line in the layout file when the page is rendered. Using the example I've created, the markup would look like this:
<!-- output -->
<html>
<head>
<title>My Site</title>
</head>
<body>
<header>
<a href="/">Home</a>
</header>
<h1>Hello, world!</h1>
<footer>
<p>Site Footer</p>
</footer>
</body>
</html>
You could then create a second file with the following code to reuse the block with different content. This illustrates how beneficial the concepts of inheritance and blocks can be when building anything from small websites to enterprise level apps.
// second.pug
extends layout.pug
block content
h1 This is the second page!
The code above would create a second page on our website with the following markup:
<!-- output -->
<html>
<head>
<title>My Site</title>
</head>
<body>
<header>
<a href="/">Home</a>
</header>
<h1>This is the second page!</h1>
<footer>
<p>Site Footer</p>
</footer>
</body>
</html>
Can I use multiple blocks?
Notice how quick and easy it was to create the second page! 3 lines of code in the second.pug
file generates a whole DOM for the new page complete with any styles attached to the layout. But what if you want to use more than one block? That's really not much different. You would just put another block somewhere in the layout file and call it the same way. The following example demonstrates how this works with a scripts block.
// layout.pug
html
head
title My Site
body
header
a(href='/') Home
block content
footer
p Site Footer
block scripts
// hello.pug
extends layout.pug
block content
h1 Hello, world!
block scripts
script console.log('Hello, world!')
By adding a second block to the layout, you have the ability to add any script needed for a specific page to the DOM structure without having to load it on every page. Having this ability can greatly increase performance since libraries only needed on a single page don't have to be loaded on every other page as well.
Wrapping Up
Creating a layout can save lots of time and energy when building a website or application because it allows you to build it once and just extend it wherever needed. In addition, updates are a lot easier because you can simply update the layout file and it will change everywhere. In the next post, I will talk about how to use includes and mixins to further your ability to use a DRY approach to building things with Pug.
Have questions? You can find me on Twitter @iam_timsmith.