Automating our Craft development workflow or: how I learned to stop worrying and love the Gulpfile

The majority of our projects at Francis Bond are heavily content-driven, requiring a content management systems. In the past, we drifted from platform to platform, searching for the holy grail of balanced functionality, simplicity, and client-friendliness. Eventually, we found that with Craft—see our write-up on why Craft will make your life better. 

Craft's simple and developer-centric templating system gave us a considerable boost in productivity, but we could do better. Standardizing the platform on which we base the majority of our projects presented an opportunity to lock down and automate our workflow.

The way it was

Our existing workflow generally—although this varied project-to-project—looked something like this:

  1. Create a fresh repository
  2. Manually download the latest Craft build
  3. Set-up MAMP virtual hosts on each developer's machine
  4. Create a new hosting environment on our staging server
  5. Deploy to the staging environment over SFTP using Git hooks

Aside from this lackluster process for setting up development and staging environments, we had few development workflows in place. Most projects had little-to-no build automation, synchronizing databases between development and staging environments was manual, and setting up development environments on everyone's machines was tedious.

The way it should be

We soon discovered our current workflow was unworkable. Not only were we wasting time with tedious manual tasks, but were creating a major scalability issue; taking on more projects and more developers meant more manual work, more room for errors, and more inconsistency.

We also knew what we wanted our workflow to be. Our wish-list consisted of the following:

  • Simple set up; we should be able to scaffold a project with as few steps as possible.
  • Consistent development environments on everyone's machine
  • Easy creation of staging environments, simple deployments, and an streamlined way to synchronize databases between environments
  • Automatic asset compilation, minification and optimization

Consistent development environments with Vagrant

We chose Vagrant to standardize our local development environments. Vagrant is a tool for creating and configure lightweight, reproducible, and portable development environments. A machine is defined in a Vagrantfile and creating with a single command: vagrant up.

Vagrant supports automated provisioning, allowing us to install and configure Apache, PHP, and MySQL, all as part of running vagrant up. Vagrant's shared folders creates a bridge between the virtual machine and the local filesystem, meaning any changes made locally are instantly available to the machine.

Build task automation with Gulp

For running build tasks, we initially selected Grunt, but soon switched to Gulp, favoring its simple code-over-configuration methodology. There are several tasks we wished to automate:

  • Javascript concatenation, hinting, and minification
  • Sass compilation, auto-prefixing, and minification
  • Image optimization
  • HTML minification

Gulp has a vast array of plugins available, so everything we desired was easily achievable. Gulp tasks are written in plain Javascript, and are usually as simple as defining a source (for example, our Sass directory), piping it through a few Gulp plugins (rubySass and autoprefixr), and outputting it to a destination directory.

We created two primary tasks in our Gulpfile. gulp build runs smaller tasks for each asset type (styles, javascript, images, etc), performing the build tasks detailed above, and outputting the result to our destination directory. gulp watch keeps track of our source directory, waiting for changes to be made. When they are, it runs the appropriate task, and notifies LiveReload, so changes are instantly reflected in the browser.

Lightning-speed scaffolding with Yeoman

Now that we had our development environments completely automated, we created a Yeoman generator to scaffold out new projects quickly and easily. Our Yeoman generator spits out a copy of our Vagrantfile and Gulpfile, a fresh installation of Craft, and installs a few Bower components that we use ubiquitously.

Seamless deployment with Dokku

After trialling several systems for automating deployments to staging environments, we stumbled upon Dokku. You can think of Dokku as a self-hosted Heroku; you provide a repository and a few lines of configuration, and with a git push, Dokku provisions hosting environment inside a Docker image, and deploys the app for you.

After wrapping Dokku's commands in Gulp tasks, and creating a few tasks to push, pull, and backup databases, deployments couldn't be easier.

The way it is

After iterating our workflow for the past year, testing, adapting and improving it with each project, we've achieved:

  • Consistent development environments on all of our machines
  • Significantly reduced time required to scaffold a project 
  • Simplified and slimmed-down repositories, by relying on NPM and Bower for external resources, and moving assets to AWS S3
  • Effortless deployments to staging environments; a similar process has been adopted for deployment to production environments

If you're in the position to lock-down and automate your development workflow, I highly recommend you do so; careful decisions, and a few days work has lead us to save several hours on every project. With minimal effort, our workflow, along with build scripts, and generators, could be adapted to work with almost any CMS platform.

Fork our Craft Generator on GitHub and start hacking, or take a look at the following resources to get started: