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
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.
Head
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.
Sidebar
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 ×</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>
Navbar
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">☰</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
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 ].