Setting up Jekyll, Gulp, and Automated Git Deployments
I have been using Jekyll for a while for my personal site and long-abandoned blog, but with the latest redesign I decided to play with a more automated workflow for dependency management, development, and deployments. With a little luck that means more frequent postings, since I don’t have to go through the hassle of manually building and deploying my content.
So far I’ve settled on using a mixture of Gulp, Bower, and Jekyll for building the site and Git for deployment to my server. It’s still a work in progress that is being tweaked, but it’s finally settling down to where I felt comfortable writing about it.
Installing Global Dependencies
For my current setup there are a few global dependencies that need to be installed: node, gulp, bower, compass, and jekyll. After installing node (following the instructions from their site), the following commands install bower and gulp.
I already had a ruby install through homebrew, so installing Jekyll and Compass
is just as easy as
gem install jekyll and
gem install compass.
Creating the Folder Structure
Once all of the global dependencies are installed, I created the initial folder
structure using Jekyll’s new command
jekyll new personalsite. This creates
a new folder called
personalsite with the basic folder structure
required by Jekyll. This is where I stopped before, using the normal
jekyll serve commands to build and post my site.
For the new workflow, I made a few changes to the default folder structure. First
I removed the
css folder Jekyll made. Instead I created an
with two sub folders:
fonts. These folders are going to be generated
by gulp and bower, so I also added the whole assets folder to my .gitignore file.
That’s the only real change to the default folder structure.
Setting up Bower
For right now my only two bower requirements for my site are fontawesome and
normalize.scss. I added those dependencies by creating a
bower.json file at
the root of
personalsite with the following contents.
Other than some boilerplate, the main part is the list of dependencies which gives
the name and the version. These dependencies can be installed by running
bower install at the root of the site. This will create a
folder which contains the files for each of the dependencies.
Setting up Node/NPM
To manage the Node dependencies, I created a
package.json file. This mostly has
the dependencies for gulp to manipulate css and integrate with browserSync
This sets up everything so gulp can compile sass files, minify them, and place them
assets folder so Jekyll can pick it up during the build. The dependencies
can be installed with
npm install from the root of the site folder.
Setting up Gulp
The most complicated part of this setup is the
gulp.js file. The full file for
this can be found here.
Below is a breakdown of the parts.
The first part imports the requirements we installed with our
The only one not from the requirements file is
child_process which is used later
for running the Jekyll build commands.
This sets up some paths used in the later tasks, plus a message to indicate
when a Jekyll build is running (for browserSync). The
the build directory for Jekyll. It’s used so instead of having to trigger a
build every time a file changes (like a css file), I can directly place the css
into the output directory and stream the changes through browserSync.
The bower task configures the gulp-bower plugin by passing it the config.bowerDir.
This is the gulp task for moving the fontawesome font files from the bower directory to both the asset directory (so jekyll will pick it up during a build) and to the output directory’s assets folder. I don’t really use the second part, but it matched what I was doing with the css task so I left it in.
The css task compiles the main scss file from which I import all other files, adds the paths for the bower scss files, minifies it, outputs it to the build assets directory and the final assets directory, then triggers a browserSync stream to cause a reload.
These two tasks handle the integration between gulp and Jekyll. The
command has dependencies on the
bower tasks so those are
completed beforehand. The first part sends a notification that there is a build
occurring to browserSync. The second runs the
jekyll build command.
jekyll-rebuild is the actual rebuild command for development, it depends on
jekyll-build and runs a browserSync reload when the build is complete.
The rest of the file defines the entry points into the system. The
runs the other tasks to create an initial build. This is the task I use during the
deployment step on my server.
serve task is what I use during development. In addition to running an initial
build, it starts browserSync against the output directory and sets up watch commands
on the files so browserSync can keep the browser up to date with any changes. Changes
to the scss files triggers the
css task which streams changes to browserSync. Changes
to html files or post files trigger a full
jekyll-rebuild, which will run a new
build and reload the browser.
Because of how Jekyll processes files, the gulp, bower, and npm files will end
up being sent to the output directory
_site. To avoid this, I added the following
Using for Development and Writing
Once all that is setup, developing or writing for my site can be handled by running
gulp serve. This compiles the scss files, builds the jekyll site,
and loads the output in a browser window with browserSync.
If it is a fresh checkout, the
gulp serve command needs to be preceded by
Adding the Site to Git
For my automated deployment, I went with a git work flow. The first thing I did
was put the site code under revision control by running
git init from the root
Before adding and committing the first set of files, I made sure my
file ignores everything that is either auto-generated or doesn’t need to be added
for the build processes.
Then I commited the files with a normal git workflow.
Configuring the Server
So far all this is local to my workstation. On my remote server I initiated a bare git repository to act as the “deploy” base.
To support automated building and deploying, I also installed all of the global dependencies I installed on the local machine.
Finally I added a post-receive git hook by creating the file
~/personalsite.git/hooks/post-receive and setting it as executable
chmod +x ~/personalsite.git/hooks/post-receive This
file will be executed every time there is a push to this repository. In my case,
I use this script to create a temporary checkout, build the site, and then move it
to the directory being served by my web server.
Configuring Git Deployments
Back on my local machine, I added the repo on my server as a remote named
I’m using ssh to add the remote, so there is no need for any additional server
configuration beyond normal remote access (and installing git)
With that done, the only thing required to deploy my site is to push my changes
to the remote server with
git push deploy master