Static site generator gulp file
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 ...