Static site generator gulp file

Published: 3 weeks ago web dev

I have built a few static sites recently and one of the quickest ways to get them going is to take advantage of gulp, handlebars and npm, and roll your own simple static site generator. Handlebars is powerful enough to support the idea of layouts and makes it easy to build sites in a structured way without code repetition. By using gulp we can also easily take advantage of using sass, imagemin, js minification and more.

Handlebars templating

Handlebars is an easy to learn Javascript-based templating engine to help with building static sites. In Handlebars we will pass {{ variables }} to our view files and we might need to use the odd {{#if}} {{/if}} statement too. The real magic is in the layout/partial logic though. You might think you need to extend Handlebars for this, as I did, but thanks to this fantastic guide you can see it is possible to handle it natively. In summary, the inline partial block does all the heavy lifting.

We can create a defaultLayout.hbs layout (just a regular partial), an index.hbs page (just a regular partial) and a hero.hbs panel (again just a regular partial). Our default layout might look like:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>{{ page-title }}</title>
        <meta name="description" content="{{ meta-description }}">
</head>
<body>
	{{> content }}
</body>
</html>

Our index page:

{{#> defaultLayout 
	page-title="My index page" 
	meta-description="My meta description" 
}}
	{{#*inline "content"}}
		{{> hero }}
	{{/inline}}
{{/defaultLayout}}

And the hero panel partial:

<div class="hero">HERO</div>

As you can see we can define variables in the layout and set them on the actual page partial (title, meta-description). The page partial itself can pull in any number of partials in to any number of defined content blocks. We only have one, content, but we could also have header and footer etc. We could pass variables through to each partial if we wanted, like so:

{{> hero type="full-height" }}

A suggested folder structure for this set up would be /layouts, /pages and /partials respectively. You could use sub folders for larger sites within these. We can compile these templates in gulp - discussed later.

SASS

If we're using a task runner for compiling Handlebars templates, we might as well take advantage of SASS too. In my setup we have a main.scss file that will @import all the SASS partials.

We can include third party files (managed via NPM - see below) in one of two ways. By including the path in the includePaths parameter on the sass object within our gulp file, like so:

includePaths: ['./src/scss','./node_modules/bootstrap-sass/assets/stylesheets']

This includes the path to Bootstrap so in our main.scss file we can just @import 'bootstrap';.

Alternatively, we can specify the relative path in the main.scss file: @import '../../node_modules/animate.css/animate.min';.

You'd want to use the former where the imported file also imports further files and use the later where the imported file is self contained.

I also use autoprefixer and cssnano to optimise the outputted CSS. The final CSS file gets outputted to ./dist/css so you can just link that in the layout file.

JS

It's a similar story with JS although the third party dependencies are loaded a little differently. The gulp.src object is used with an array of all the required JS files. Once all the JS is loaded, the gulp file concatenates it, uglifys (minimises) it and spits it out in ./dist/js.

ImageMin

The gulpfile also uses imagemin to optimise image filesize without reducing quality. Images are by default placed in ./src/images/, get optimised and outputted to ./dist/images. Note that this task doesn't run automatically so you need to run gulp imagemin to start it.

Watching

After running gulp watch, all .src/scss/*.scss files, ./src/js/script.js and all ./src/*/*.hbs files will get automatically compiled when they are modified.

NPM

As mentioned, I use NPM to manage the gulp dependencies and also all the project's CSS and JS third party dependencies. Typically these would all be devDependencies as we don't want to keep gulp related dependencies and everything else we bundled everything up into the final source files. A quick reminder on NPM:

npm install --save-dev bootstrap-sass would install bootstrap-sass into node_modules and write to the devDependencies in package.json. We can then load this via SCSS or gulp.

We can also install specific versions, npm install bootstrap-sass@3.3.7 or opt to choose the latest version but always use only that version, npm install --save-exact bootstrap-sass.

Production mode

The scss and js files get source mapped by default so that you can more easily inspect the original SASS and JS in the browser when building the site. Obviously this isn't required in production and it dramatically increases file size. So gulp --production recompiles all files without any source maps.

The completed gulpfile and the dependencies

To install the gulpfile depdendencies:

npm install --save-dev gulp gulp-autoprefixer gulp-compile-handlebars gulp-concat gulp-cssnano gulp-if gulp-imagemin gulp-rename gulp-sass gulp-sourcemaps gulp-uglify gulp-util

And the complete gulpfile:

Things for the future

Of course, there are loads of extra things that could be added to this in time, such as uncss to remove unused CSS styles. It is also not currently using BrowserSync as I was having some issues with it. To be continued ...