HTML Templates for Developers

HTML Templates for Developers

If you asked me, I’d always rather classify myself as developer, and not as web designer. In fact, looking at my background, I really come from systems development, working with C and even assembly. Meanwhile, I mostly write Python stuff, but inevitably, I came to the point where I coded on a web application.

Working on the backend was not that hard a transition – all the things I’m used to and have grown to are there: clean code structure, version management via git, unit tests, continuous integration and automated deployment are my best friends. So far I hardly ever was dealing with frontend stuff – true, I wrote the Django views, but I didn’t bother for the HTML templates.

Of course HTML is not completely unfamiliar to me, but I’m certainly no expert in recent developments, and JavaScript was never a programming language I looked into. Suddenly confronted with the need to build a frontend with my limited skillset, I chose to tackle this task in a way I usually tackle development tasks: Look for a decent framework that does most of the stuff for you (no need to code stuff others have already done for you), and set up a robust build chain, fostering reproducible results and the ability to transfer the development work from one computer to another.

If you’re confronted with the same situation, here’s what I chose & did, and why: As a framework, I chose Bootstrap – not really a surprise, it’s one of the most widespread frameworks, comes with decent documentation and provides a lot of things I needed out of the box. Furthermore, I was dealing with Bootstrap-based templates already earlier, so the structure is somewhat familiar to me. Last but not least, Bootstrap has a very permissive license (MIT) and easily integrates with third-party build tools.

The version management of course is done with git, and for the build toolchain, I opted for gulp and Sass. For people like me, coming from a systems development background: Gulp is a scripting system, helping to automate build steps. It reminds me a lot of good old Makefiles, though its syntax is in JavaScript – but the principles are the same; you create build tasks, define one of them as default, and then you call gulp either with one of the targets, or let it pick the default one.

Sass on the other hand is just a “compiler”, allowing you to use variables and conditionals in your CSS stylesheets, which makes them easier to maintain. Both tools are based on Node.js, but you don’t have to bother for this one – you wouldn’t care what programming language and framework your make binary is written in, either… You just need to have Node.js installed on your computer, which is not that hard to accomplish.

However, using only tools that are based on Node.js allows us to use the Node Package Manager (npm) to maintain the project’s dependencies – just as you would use pip for a Python project to install all required dependencies. This also makes it easy to transfer your development work from one computer to another – just make sure Node.js and git are installed; the rest is automated.

But now enough of waffling, let’s get started. First we need a project repository:

mkdir myfrontend
cd myfrontend
git init
npm init

npm init will ask you quite some questions; you can simply accept the default, as we’re not really building a Node.js application here. The output of this process is a file called package.json, which you can edit to your liking. We only need it to record the dependencies needed for the build chain of this project.

Next, we will install the npm packages required – and make sure they’re stored as dependencies in the package.json file:

npm install bootstrap@4.1.0 --save
npm install jquery@3.3.1 --save
npm install popper.js@1.14.3 --save
npm install font-awesome@4.7.0 --save

These packages are the ones we directly use to create the HTML frontend of our application. You will notice that npm automatically modified package.json, and also created a file called package-lock.json. This second file also needs to be included in the git repository, so don’t exclude it!

Next, we will install the tools required for the build chain:

npm install gulp browser-sync gulp-sass --save-dev
npm install gulp-uglify gulp-clean-css gulp-rename --save-dev

Before we continue, here’s a thought on how to organize the source code inside the repository:

+-- myfrontend/
    +-- dist/
    +-- node_modules/
    +-- src/
    |   |
    |   +-- img/
    |   |
    |   +-- js/
    |   |
    |   +-- scss/
    |   |
    |   +-- index.html
    +-- package-lock.json
    +-- package.json

The idea behind: All source code (HTML, Sass, custom JavaScript, image assets, etc.) will reside inside the src directory. The compiled output will be found in dist, wherewas files related to the build chain, and generic files such as a README or similar would go to the project’s root directory. node_modules is a directory created by npm, containing all the installed dependencies.

Therefore, dist and node_modules should be excluded from our git repository. Add a .gitignore file with these exclusions:

# Dependency directories

# Optional npm cache directory

# Sass

# build output

The only missing part is now what corresponds to a Makefile – and indeed, when using gulp this file is called gulpfile.js. The first part is the header, where dependencies are loaded. Here’s what mine looks like:

var gulp        = require('gulp');
var browserSync = require('browser-sync').create();
var sass        = require('gulp-sass');
var cleanCss    = require("gulp-clean-css");
var uglify      = require("gulp-uglify");
var rename      = require("gulp-rename");

Next, we’re creating a simple gulp task (corresponding to a make target), which does nothing more than moving our image assets from the source directory to dist and avails them to the browserSync tool:

// Move the image assets into our /dist/assets/img folder
gulp.task('img', function() {
    return gulp.src(['src/img/*.png', 'src/img/*.jpg', 'src/img/*.gif'])

As a matter of principle, a gulp task consists of a name ('img' in this case), and a JavaScript callable (a local function in our case). The callable returns a gulp task chain, which is always constructed along the same scheme: First, identify which source files we’re talking about, and then append tasks to the chain by using pipe. To illustrate this principle, here’s a more complex example, which includes compiling the Sass source files into CSS, and then compressing the resulting CSS:

// Compile sass into CSS & auto-inject into browsers
gulp.task('sass', function() {
    return gulp.src(['node_modules/bootstrap/scss/bootstrap.scss', 'node_modules/font-awesome/scss/font-awesome.scss', 'src/scss/*.scss'])
        .pipe(cleanCss({compatibility: 'ie8'}))
            suffix: '.min'

Now you may have noticed that browserSync is called in the various examples. The reason behind: browserSync can open the web browser, serve the compiled files via HTTP and can refresh the browser upon request. This is most convenient: In conjunction with gulp, we can define a task that serves the built files, and monitors our source files for changes. When a change is detected, the build process for that specific file type is launched, and browserSync is notified to update:

// Static Server + watching scss/html files
gulp.task('serve', ['sass'], function() {

        server: "./dist"
    });['node_modules/bootstrap/scss/bootstrap.scss', 'src/scss/*.scss'], ['sass']);['src/img/*.png', 'src/img/*.jpg', 'src/img/*.gif'], ['img']);"src/*.html").on('change', browserSync.reload);

Finally, defining a default task helps running gulp without specifying a target:

gulp.task('default', ['img', 'serve']);

Of course, for this project, some more gulp tasks are needed, but they will look quite the same as the tasks already described. In order to keep this article clean of too much code listing, the full code of the gulpfile can be found here on GitHub.

That’s it – now you can place your HTML code directly in src, your Sass files in src/scss, run gulp thin the project’s root directory and start coding away…

About Jesco Freund

Caffeine-based life form loving X-Plane, crypto, coffee, chili pepper, FreeBSD, C and Python. Likes coding stuff nobody needs and never gets finished either.