Preface

Goal: Build static HTML files using partial EJS utilizing Grunt.

With EJS (embedded javascript), you can directly use javascript inside your template. It has no extend and block concept. But you can have similar result with parameterized include.

Official Documentation

Source Examples

You can obtain source examples here:


1: EJS Case

We use EJS as html preprocessor to build html documents. Consider transform our last HTML Case into EJS Case.

Directory Structure

Consider ejs structure.

└── views
    ├── css.ejs
    ├── html.ejs
    ├── index.ejs
    ├── javascript.ejs
    ├── partials
    │   ├── head.ejs
    │   ├── layout.ejs
    │   ├── navbar.ejs
    │   └── sidebar.ejs
    └── php.ejs

We want the ejs to build html artefacts as below:

└── build
    ├── css.html
    ├── html.html
    ├── index.html
    ├── javascript.html
    └── php.html

EJS: Example: Tree

Now we can separate each html parts.

Layout

<!DOCTYPE html>
<html lang="en">

<head>
  <%- include('head',{title: title}) %>
</head>
<body>
  <%- include('sidebar') %>

  <div id="main">
    <%- include('navbar') %>

    <div class="w3-container">
      <p><%= content %></p>
    </div>
  </div>

</body>
</html>

As shown in order we have three include artefacts.

  • include head.ejs,
  • include sidebar.ejs,
  • include navbar.ejs,

And one output variable <%= named content.

<p><%= content %></p>

This output value, will simply print variable, in HTML escape fashioned.

EJS: ViM NERDTree Panes

It is almost the same with the original head.

  <title><%= title || "Link Example: Default" %></title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
  <script src="../js/script.js"></script>
  <script src="//localhost:35729/livereload.js"></script>

Here we put the default title if we cannot find title variable.

<title><%= title || "Link Example: Default" %></title>

I also add livereload for use with grunt later.

It is a simply a verbatim copy-paste from the original html.

  <div class="w3-sidebar w3-bar-block w3-card w3-animate-left" 
       style="display:none" id="mySidebar">
    <button class="w3-bar-item w3-button w3-large"
       id="closeNav" >Close &times;</button>
    <a class="w3-bar-item w3-button"
       href="index.html">Home</a>
    <a class="w3-bar-item w3-button"
       href="html.html">HTML Link</a>
    <a class="w3-bar-item w3-button"
       href="css.html">CSS Link</a>
    <a class="w3-bar-item w3-button"
       href="php.html">PHP Link</a>
    <a class="w3-bar-item w3-button"
       href="javascript.html">Javascript Link</a>
  </div>

It is also a an exact copy from the original html.

    <div class="w3-teal">
      <button class="w3-button w3-teal w3-xlarge"
              id="openNav">&#9776;</button>
      <div class="w3-container">
        <h1>My Page</h1>
      </div>
    </div>

    <div class="w3-bar w3-black">
      <a class="w3-bar-item w3-button"
         href="index.html">Home</a>
      <a class="w3-bar-item w3-button"
         href="html.html">HTML</a>
      <a class="w3-bar-item w3-button"
         href="css.html" >CSS</a>
      <a class="w3-bar-item w3-button"
         href="php.html" >PHP</a>
      <a class="w3-bar-item w3-button"
         href="javascript.html">Javascript</a>
    </div>

Index

By including the partials/layout.ejs, we can pass both the variable title and content.

<% 
  var title = "Link Example: Home";
  var content = "Home Page";
%>
<%-
  include('partials/layout',
  {title: title, content: content})
%>

2: EJS Content Propagation

How does it works ?

Passing Value

In partials/layout.ejs we have this output variable <%=.

<p><%= content %></p>

Then we can replace the content, of the block in child layout index.ejs.

<%  var content = "Home Page"; %>
<%- include('partials/layout', {content: content}) %>

Title

Variable Propagation Between Template

In index.ejs we have this variable.

<%  var title = "Link Example: Home"; %>
<%- include('partials/layout', {title: title}) %>

And in partials/layout.ejs, we pass the variable again.

<head>
  <%- include('head',{title: title}) %>
</head>

This variable will be utilized in partials/head.ejs

<title><%= title || "Link Example: Default" %></title>

This is also almost self explanatory.

Main Files

Instantly, all the main files can be so short as below:

<% 
  var title = "Link Example: CSS";
  var content = "CSS Page";
%>
<%-
  include('partials/layout',
  {title: title, content: content})
%>
<% 
  var title = "Link Example: PHP";
  var content = "PHP Page";
%>
<%-
  include('partials/layout',
  {title: title, content: content})
%>

Result

As usual, check build/index.html against the original html.

<!DOCTYPE html>
<html lang="en">

<head>
  
  <title>Link Example: Home</title>
  ...
</head>
<body>
  ...

  <div id="main">
    ...
    <div class="w3-container">
      <p>Home Page</p>
    </div>
  </div>

</body>
</html>

3: Grunt Configuration

Command Line Interface

I won’t bother looking for a CLI guidance. I already comfortable with this good grunt.

package.json

All you need to know is the devDependencies.

  "devDependencies": {
    "ejs": "^3.1.3",
    "grunt": "^1.0.1",
    "grunt-contrib-watch": "^1.1.0",
    "grunt-ejs": "^1.0.0"
  }

To begin with grunt, you need to run npm install first.

Gruntfile.js

You also need to a configuration file named Gruntfile.js.

module.exports = function(grunt) {
  // configure the tasks
  let config = {

    ejs: {
      all: {
        cwd: 'views',
        src: ['**/*.ejs', '!partials/**/*'],
        dest: 'build/',
        expand: true,
        ext: '.html'
      }
    },

    watch: {
      ejs: {
        files: ['views/**/*'],
        tasks: ['ejs'],
        options: {
          livereload: true,
          interrupt: false,
          spawn: false
        }
      }
    }

  };

  grunt.initConfig(config);

  // load the tasks
  grunt.loadNpmTasks('grunt-ejs');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // define the tasks
  grunt.registerTask('default', [
    'ejs', 'watch'
  ] );

};

The configuration is self explanatory. Just read the official documentation of grunt-ejs.

Running Grunt

EJS: Grunt: Watch

Now you can build your own static html files using ejs.


What’s Next?

We still have the last grunt example: handlebars.

Consider continue reading [ Template - Grunt - Handlebars ].