Home >Web Front-end >JS Tutorial >Serving Dynamic HTML With Pug And Express
Before Single Page Applications became a thing, templating languages like Pug were super popular because they allowed developers to render a page on the server side before sending it over to the client. Express is the most popular backend application framework for Node.js. It prides itself on being lightweight, unopinionated, and minimal to use. In this guide, you will learn how to serve dynamic HTML with Pug from an Express.js server application.
HTML can be cumbersome to write sometimes. The language has no support for features like "components", which can lead to code duplication unless you rely on external tools like JavaScript.
Pug is a templating engine that makes it easier to write HTML. With Pug, you can split your code and reuse "components" in as many places as you'd like. Regarding syntax, Pug differs from traditional HTML as it uses indentation instead of closing tags. In HTML, you define an element like this:
<div class='hello'>This is something worth noting</div>
In Pug, however, you define an element like this:
div(class='hello') This is something worth noting
The tag name is defined on the left, with its attributes in brackets. The tag is separated from its contents by the space next to it. The Pug transpiler will transpile your code back to the proper HTML code recognized by the browser. Child elements are defined by indentation. This means if you wanted to have a div inside a main tag, you'd do something like this:
main div Hello from the children of planet Earth!
To add Pug to your Express.js project, simply install Pug with any package manager of your choice. For this example, I'm working with NPM:
npm i pug
This will add Pug to your list of dependencies in your package.json file. Now, you'll need to set your view engine to pug, so in your project's entry file (usually main.js, app.js, or index.js ), import express properly and configure the application settings with the set method.
import express from 'express'; const app = express(); app.set('view engine', 'pug');
By setting view engine to 'pug', you're telling Express to use Pug as its templating engine. So, when you call the render method on the response object, you must pass a valid 'view' for Express to render. Views in Express must be placed in a special views directory, in the project's root directory. If you haven't created a views directory, you can do so with the following:
mkdir views # Make sure you are in your project root
Now, that you've got things set up, let's proceed to writing our first view in Pug.
Create a views/index.pug file, and add the following to it:
html head title Welcome to my website body div Hello World
Now that your index.pug file is ready, you'll need to serve it to the client on a route. Go to your project's entry file and define a get request handler that will render and return the views/index.pug file to the client.
app.get("/", (req, res) => { res.render("index.pug"); });
When you open localhost:
res.render(view [, locals] [, callback]);
First, we have view, which is simply the path of the .pug file you want to render. Remember that Express locates the .pug files relative to the views directory. So, if you have a Pug file located at views/layouts/main.pug, you should refer to it as layouts/main when setting the view in your route.
app.get("/", (req, res) => { res.render("layouts/main"); });
Next, the locals is an object with properties that define local variables that should be passed into the specified view for interpolation. When callback is provided, the resulting HTML from the render operation is not sent to the client. Instead, you can access it via a parameter in the callback function, like this:
app.get("/", (req, res) => { res.render("index.pug", {}, (err, html) => { console.log(html); }); });
When the client makes a get request to '/', a response is not sent. Instead, html is logged to the server console. You can manually send the HTML to the client with the send method:
res.send(html)
Now it's time to take things to the next level. You'll learn how to interpolate data with Pug to create dynamic content on the fly. In Pug, string interpolation is done with the syntax #{
// greet.pug html head title Welcome to my website body div Hello #{name}
In the code block above, name will be replaced the actual value from the locals object passed into the render method. If name is undefined, no error is thrown. Here it is in action.
app.get('/greet', (req, res) => { const {name} = req.query; res.render('greet.pug', {name}) })
When the client hits /greet?name=David, the following HTML will be returned
<html> <head> <title>Welcome to my website</title> </head> <body> <div>Hello David</div> </body> </html>
The string interpolation syntax (#{}), is escaped by Pug. This is useful in situations where the content comes from users. If you want Pug is render the string as is without escaping, you'll need to use the !{} syntax.
- var example = <strong>very risky</strong> div !{example}
Pug provides a handy syntax for tag interpolation #[], which you can use like this:
p This is a #[strong very important] message.
This will render as:
<p>This is a <strong>very important</strong> message.</p>
- var username = 'John' p Hello, #[strong #{username}]!
You don't have to worry about self-closing tags, because Pug knows what tags are self closing. But if you really need to self-close a tag, you can append the / character to the end of the tag like this:
div/
To save space, You can use the : shorthand instead of indentation to specify nested tags.
label: input(type='text' name='username')
The code block above is just as valid as:
label input(type='text' name='username')
In the last code block, notice the use of the var keyword from JavaScript to create a variable. Pug allows you to insert valid JavaScript code on any line that starts with an -. For example, you can create an array and iterate over it to render a list of items. Pug has its native syntax for this, but in this example, you can use JavaScript.
html head title Welcome to my website body div List of items - var items = ['milk', 'peas', 'bread'] - items.forEach((item)=>{ li #{item} - })
Study the previous example. Notice how Pug and JavaScript are combined. The forEach method is not part of the Pug API, it belongs to JavaScript. Likewise, the string interpolation symbol is not part of the #{} JavaScript API. The lines with valid JavaScript code are marked with the - symbol. On the second to last line, there is no - symbol, because that is Pug code.
For common things like conditionals and iteration, Pug provides its syntax that you can use instead of JavaScript. The most popular keyword for iteration in Pug is each. each must come in the form each VARIABLE_NAME of JS_EXPRESSION. Here's how you can use it:
each item in ['milk', 'peas', 'bread'] li #{item}
When dealing with objects, the expected format for each is each VALUE, KEY OF JS_EXPRESSION. For example:
each val, key in {1:'milk', 2:'peas', 3:'bread'} #{key} : #{val}
You can use the if syntax to handle conditionals. Here's an example:
╴ var loggedIn = false if !loggedIn p Sorry you cannot access this item because you're not logged in
Conversely, Pug has an unless keyword that you can use like this:
unless loggedIn p Sorry you cannot access this item because you're not logged in
Pug offers many features beyond just string interpolation and conditionals. If you are working on a large website, you might need to use advanced features that Pug provides, such as layouts and partials.
Layout files allow you to define a common structure for your pages and extend it in other templates, ensuring consistency across your website. Here's an example of how you can use layout files.
//- views/layout.pug html head title My Website Title body header h1 My Website block content footer p Footer content
Notice the block keyword in the code block above. A block in a layout file acts as a placeholder. Each block must have a name. In this example, block is defined as content. Whenever you want to use your layout file, you use the extends syntax to tell Pug that a template should include a layout.
//- views/index.pug extends layout block content p Welcome to the homepage!
In this example, index.pug extends the layout.pug template, which provides the page's base structure, including the header and footer. The block content line defines a block named content where the indented paragraph "Welcome to the homepage!" is inserted. When index.pug is rendered, the final HTML will look this this:
<html> <head> <title>My Website Title</title> </head> <body> <header> <h1>My Website</h1> </header> <p>Welcome to the homepage!</p> <footer> <p>Footer content</p> </footer> </body> </html>
Partials are reusable pieces of templates that can be included in other templates, which helps to keep your code DRY (Don't Repeat Yourself). You can create partials in Pug with the include syntax.
//- views/partials/sidebar.pug aside p This is the sidebar content.
In sidebar.pug defines a partial template for a sidebar with an aside element containing a paragraph of text.
//- views/layout.pug html head title My Website Title body include partials/sidebar block content footer p Footer content
In layout.pug, a layout template is created with a basic HTML structure. It includes the header and sidebar partials using the include keyword, places a block content placeholder for dynamic content, and adds a footer with a paragraph of text. The final render should look something like this:
<html> <head> <title>My Website Title</title> </head> <body> <header></header> <aside> <p>This is the sidebar content.</p> </aside> <p>Welcome to the homepage!</p> <footer> <p>Footer content</p> </footer> </body> </html>
1. Use partials and layouts wherever you can: Using partials, layouts, and helpers in Pug enhances template organization and efficiency. Partials are reusable snippets that prevent code repetition, while layouts provide a consistent structure for pages by defining common elements and extending them in individual templates.
2. Minimize the use of inline JavaScript: When writing your templates, try to use inline JavaScript sparingly. Adding huge blocks of JavaScript to your code can create issues with debugging and maintainability.
One way to reduce inline JavaScript is through the use of helpers. Helpers, defined in the server-side code, allow dynamic content within templates. You can pass a helper function to a template using the locals method on the express app.
const express = require('express'); const app = express(); app.set('view engine', 'pug'); app.locals.formatDate = function(date) { return new Date(date).toLocaleDateString(); }; app.get('/', (req, res) => { res.render('index', { title: 'Home', currentDate: new Date() }); }); app.listen(3000, () => { console.log('Server is running on port 3000'); });
With the formatDate helper function set, you can use it in your Pug template like this:
p Welcome to the homepage! p Today's date is #{formatDate(currentDate)}
In this guide, you learned how to serve dynamic HTML with Pug and Express. We covered basic Pug syntax, integrating Pug with Express, building dynamic pages, and advanced techniques like using layout files and partials.
Templating engines are very powerful especially when building a server-side web application. They are great for Search Engine optimization too because unlike single-page applications, the content is rendered on the server on each request.
The above is the detailed content of Serving Dynamic HTML With Pug And Express. For more information, please follow other related articles on the PHP Chinese website!