Where to Discuss?

Local Group


Step Zero: Prepare modular HTML using Nunjucks template

A template system can help you produce healty code. Instead of long HTML, you can separate chunks of HTML element, into different files. You can find your element easily this way. So you can focus on specific HTML element.

Now I can put recurring long parts such as navbar, in separate file, and focus on small parts, such as widget, or blog post layout. Using one big HTML only without template used to be exhausting, but now it is easier with modular files.

This is basically a template introduction. It looks like learning frontend, using backend approach. Of course you need some adaptation to use template approach. Learning process may take while, but it is worth to learn.

1: Ready to Use Examples.

Bootstrap examples provided in with this article series. I intentionally make result of compiled templates for each chapter. You can just open HTML file in the browser, and see the result. This way is easier for beginner.


You can start the journey by clone the git repository.

❯ git clone https://gitlab.com/epsi-rns/tutor-html-bootstrap5/

You can see all chapters here, form Step-00 to Step-10.

Bootstrap5: All Chapters

Open HTML using File Manager

There is two ways to open this file.

  1. Using file protocol
  2. Using http protocol

You just can open the ready to use HTML file for each chapter, by right-clicking the file in file manager and open the HTML file, in your favorite browser, such as chrome, edge, or firefox.

Bootstrap5: File Protocol

This compiled HTML files are available for all chapters.

Open HTML using Browser Sync

For convenience, you can also open HTML file using HTTP protocol. This can be done using using a few options, such as javascript based browser-sync.

❯ browser-sync start --server --directory

Alternatively you can use Python.

❯ python -m http.server

Or even PHP

❯ php -S localhost:8000

Since we want to also use Nunjucks template later on, we’d better use browser-sync for easy integration with Nunjucks.

❯ npm i -g browser-sync
❯ cd ~/bs5/tutor-html-bootstrap5
❯ browser-sync start --server --directory
[Browsersync] Access URLs:
       Local: http://localhost:3000
          UI: http://localhost:3001
 UI External: http://localhost:3001
[Browsersync] Serving files from: ./

Bootstrap5: BrowserSync

Now you can open localhost:3000 in your browser. You can change also change the port number if you need. The browser can navigate into all chapters.

Bootstrap5: Open File in BrowserSync

Then you can open the file that you need.

Bootstrap5: HTTP Protocol

You can check the URL in below section of that Qutebrowser, is different than previous file protocol.

2: Modularization

I use different approach, while developing each case. Instead of just giving raw HTML files, I modularized each HTML parts into chuncks.

Gulp, Grunt, Webpack?

The thing is I don’t want to repeat myself. This could be done using Nunjucks and Grunt.

Since I have already make an article about Nunjucks and Grunt. I think I’d better use other method. After some research, I found this good article below:

I decide to use Gulp instead of Grunt.

Directory Structure

Modular approach is easier for beginner. For each steps, we have this directory structure.

Bootstrap5: Step One

❯ tree
├── 001-html-layout.njk
├── contents
│   └── main.njk
├── heads
│   └── meta.njk
├── layouts
│   └── base.njk
└── shared
    ├── footer.njk
    └── header.njk

You can see all the separated templates here.

Bootstrap5: Summary One

Using Nunjucks

We need to install Nunjucks first.

❯ npm i -g nunjucks nunjucks-cli

We can operate the Nunjucks in CLI.

❯ cd ~/bs5/tutor-html-bootstrap5
❯ cd step-00/views
❯ nunjucks 001-html-layout.njk -p . -o .
Rendering: 001-html-layout.njk

Now check the directory, we can see a new HTML file has generated there

❯ exa
001-html-layout.html  contents  layouts
001-html-layout.njk   heads     shared

We are going to automate this later, in this article.

3: Partials Nunjucks

For better explanation, consider examine the HTML source, as partial templates.

Source Code: Step-00

Source code for this chapter can be obtained here:

Simple Layout

You can begin learning HTML document, without any framework. Our simple HTML5 layout could be like this.

<!DOCTYPE html>

  {% include './heads/meta.njk' %}

  {% include './shared/header.njk' %}
  {% include './contents/main.njk' %}
  {% include './shared/footer.njk' %}


Base Layout

For flexibility reason we can split code above using inhertance.

Base file:

<!DOCTYPE html>

  {% block htmlhead %}
  {% endblock %}

  {% block header %}
  {% endblock %}

  {% block content %}
  {% endblock %}

  {% block footer %}
  {% endblock %}


Paired with blocks:

{% extends './layouts/base.njk' %}

{% block htmlhead %}
  {% include './heads/meta.njk' %}
{% endblock %}

{% block header %}
  {% include './shared/header.njk' %}
{% endblock %}

{% block content %}
  {% include './contents/main.njk' %}
{% endblock %}

{% block footer %}
  {% include './shared/footer.njk' %}
{% endblock %}

Bootstrap5: Nunjucks: Base

Mostly I start from page layout, then HTML elements later.

Meta and Main

And the rest, Meta and Main.

  <title>Your mission. Good Luck!</title>

Bootstrap5: Nunjucks: Meta

  <!-- main -->
    <p>To have, to hold, to love,
    cherish, honor, and protect?</p>

    <p>To shield from terrors known and unknown?
    To lie, to deceive?</p>

    <p>To live a double life,
    to fail to prevent her abduction,
    erase her identity, 
    force her into hiding,
    take away all she has known.</p>

Bootstrap5: Nunjucks: Main

Also Header and Footer.

  <!-- header -->
  <p><i>Your mission, should you decide to accept it.</i></p>
  <!-- footer -->
  <p><i>As always, should you be caught or killed,
  any knowledge of your actions will be disavowed.</i></p>

Bootstrap5: Nunjucks: Header and Footer

HTML Output

Static Page

The compiled output is long,

This would be shown as below figure:

Bootstrap5: HTML Output: Source

Now we can open it in browsersync or using file directly.

Bootstrap5: HTML Output: in Browser

4: Automation

Disclaimer: For new bootstrap user, you can skip this part entirely.

Typing command to compile Nunjucks is cumbersome. We can utilize Gulp and automate each chapter. We need to configure Gulp to do these task:

  • Generate HTML: One chapter at a time
  • Generate All HTML
  • Watch Changes

Gulp Configuration

The configuration can be obtained here:


You can refer to:

With exception I add ‘merge-stream’ package.

Prepare Gulpfile

First we need to initialize required variables:

const gulp = require("gulp")
const nunjucksRender = require("gulp-nunjucks-render")
const browserSync = require("browser-sync").create();
const merge = require('merge-stream');

And also defined all chapters, that need to be automated.

const folders = [

Bootstrap5: Gulpfile.js: Require Const

One chapter at a time

Generate HTMLs

folders.map( (task) => {
  const folder = './'+task;
  gulp.task(task, () => {  
    return gulp.src(folder+'/views/*.njk')
        path: [folder+'/views'],

Bootstrap5: Gulpfile.js: Task Step

Then you can run in CLI

❯ gulp step-00
[22:23:18] Using gulpfile ~/bs5/tutor-html-bootstrap5/gulpfile.js
[22:23:18] Starting 'step-00'...
[22:23:18] Finished 'step-00' after 50 ms

All chapters at once

Generate HTMLs

gulp.task("all-html", () => {
  const tasks = folders.map( (folder) => {
    return gulp.src(folder+'/views/*.njk')
        path: [folder+'/views']

  return merge(tasks);

Bootstrap5: Gulpfile.js: Task All HTML

In CLI, you can type.

❯ gulp all-html
[22:23:41] Using gulpfile ~/bs5/tutor-html-bootstrap5/gulpfile.js
[22:23:41] Starting 'all-html'...
[22:23:42] Finished 'all-html' after 522 ms

Watching Task

Regenerate for any changes.

gulp.task("watch", () => {
    server: {
      baseDir: "./"
    directory: true

    .on("change", browserSync.reload);

  folders.map( (task) => {
    folder = './' + task

In CLI, you can type.

❯ gulp watch
[22:24:04] Using gulpfile ~/bs5/tutor-html-bootstrap5/gulpfile.js
[22:24:04] Starting 'watch'...
[Browsersync] Access URLs:
       Local: http://localhost:3000
          UI: http://localhost:3001
 UI External: http://localhost:3001
[Browsersync] Serving files from: ./

Bootstrap5: Gulpfile.js: Task Watch


Is Gulp overkill?

Making this configuration is considered easy for me. And once it runs, I can automate all chapters, So I can sit on my chair, and get my brain focused on HTML code. But I know gulp is not for everyone. So it is your choice to decide.

Again, for new bootstrap user, you can skip this part entirely. You don’t need Gulp to learn bootstrap. But you’d better go back later, when you have time, to learn javascript.

What is Next 🤔?

After prepartion, we can use bootstrap right away.

Consider continue reading [ Bootstrap 5 - Minimal ].