Starter kit Part 2 - Gulp

This is second article from series about Starter kit. I use it for setting new up projects quickly and painlessly. This time, let's discuss use of Gulp. If you are interested about folder structure, check out previous article.

Lets review the requirements:

  1. Folders and files should be ready - In my case that means folder structure as I am used to - source folder with subfolders for different kinds of assets, and distribution folder for generated ones. In source folder I would already have some code, because the foundation is pretty much always the same. I don’t wanna start with a blank slate, I think no one does.

  2. Gulp with common tasks I often need - I am keen user of Gulp and I use it for myriad of things. Since project I work on are very similar, it is pointless to start from scratch everytime. Like this I can have one place, where I keep the most recent version of the tasks.

  3. It should allow for easy adjustment - Fitting kit to our needs must be easy. If it is problematic to adjust, it would defeat whole point of it, which is shaving off some work, time and cursing.

  4. It should be well-arranged so others can use it without problems - Last, but not the least, there will be other developers who will have to use it or manage it. Clear structure, documentation and help should be in place.

Gulp

I suppose you are familiar with it at least a little bit. If you are not, check this article on CSS-Tricks for a great introduction, then come back.

I was using Gulp on many projects and I love it. The modularity and tasks are amazing! It’s simply unvaluable. However, with time my gulpfiles grew larger and larger (~300 lines), thus becoming obfuscated and complicated to understand. Customizations were needlessly difficult and error-prone. I decided to make a major refactoring, in order to preserve all the benefits while mitigating the weak spots. And fulfill my requirement #3 and #4.

Order

The major change was separation of gulpfile into several smaller files. In the first look it might look like a overkill. But some fiddling in the beginning certainly pays off. I am very happy with the result, you can see everything relevant without the rest (which plays nicely with my singletasking philosophy). Thanks to this it is easier to spot superfluous code and get rid off it, keeping everything nice and tidy.

My gulpfile is separated like so:

gulpfile.js
package.json
└─┬ gulp
  ├─┬ docs
  │ └── docs.js
  ├─┬ tasks
  │ ├── clean.js
  │ ├── images.js
  │ ├── markup.js
  │ ├── scripts.js
  │ ├── serve.js
  │ ├── styles.js
  │ ├── svg.js
  │ └── watch.js
  └── config.js

Gulpfile.js

The tasks are like usual, just within its own files. I import these into the gulpfile.js like so…

// -------------------------------------
// Load tasks
// -------------------------------------
//
require('./gulp/tasks/styles');
require('./gulp/tasks/scripts');
require('./gulp/tasks/images');
...

… and make them available. Then you are free to make task sequences. I have one for developing - default, one for production prod. More on the in the next article.

In the end of this file I also included documentation, which we’ll discuss in a while.

// -------------------------------------
//   Documentation
// -------------------------------------
// - type `gulp --tasks` in Terminal
//
require('./gulp/docs/docs');

Tasks

The most important part of any gulpfile are tasks, of course. I divided them based on their output, so we have styles, scripts, images, svg, markup and utility tasks serve, watch and clean. Each of them has a own file. In the beggining there are declared npm packages used. Then there are settings or tasks. There can be more variants of a given task, which deal with same thing, but in slightly different manner.

Everyone has different needs and approach, so to keep this post succint, I won’t go into much detail here. The tasks are documented in the code. Hovewer, I wrote dedicated article about my tasks, maybe you’ll get inspired a bit, too.

Config

Now, when the tasks are separated by output, it is much easier to make changes. To take customization one step further, I extracted paths from individual tasks to the config file.

  1. It allows you keep gulpfile in the root, while putting the frontend folder whenever you like.
  2. Reorganize your assets as you please, and change paths on 1 place.
  3. You can also check/set the names of the generated files with ease, without having to touch task files.
// -------------------------------------
//   Config
// -------------------------------------
//  1 - Source root
//  2 - Distribution root
//  3 - set paths of assets
//  4 - set names for generated assets

var src  = './frontend-src/';  // 1
var dist = './frontend-dist/'; // 2

module.exports = {
  paths : { // 3
    styles : {
      src        : src + 'scss/**/*.scss',
      dest       : dist + 'css'
    },

    ...

    markup : {
      templates  : src + 'twig/[^_]*.twig',
      src        : src + 'twig/**/*.twig',
      dest       : dist
    },
    dist         : dist // used by clean task
  },
  names : { // 4
    css          : 'generatedByGulp.css',
    js : {
      app        : 'generatedByGulp.js',
      vendor     : 'vendor.js'
    },
    svgSprite    : 'svgSprite.svg'
  }
};

Documentation

Documentation is often neglected part of a workflow. I firmly believe it shouldn’t be, especially on gulpfile, which is going to be used with colleagues. So I documented tasks and gulpfile with comments, used white-space and alignment to make it more readable and included also docs/docs.js. There I describe what tasks are meant to do. When you type gulp --tasks in terminal, you get task tree with descriptions.

Tasks for /work/_tools/starter/gulpfile.js
├── clean                 Deletes 'frontend-dist' folder
├─┬ default               Watches for changes and quickly generates styles, scripts, images, svgs and markup. BrowserSynced.
│ └─┬ <series>
│   ├─┬ <parallel>
│   │ ├── styles:dev
│   │ ├── scripts:dev
│   │ ├── scripts-vendor:dev
│   │ ├── images
│   │ ├── svg
│   │ └── markup
│   └─┬ <parallel>
│     ├─┬ watch
│     │ └─┬ <parallel>
│     │   ├── watch:styles
│     │   ├── watch:scripts
│     │   ├── watch:scripts-vendor
│     │   ├── watch:images
│     │   ├── watch:svg
│     │   └── watch:markup
│     └── serve
├── images                Optimize images
├── images2webp           Generates WebP format

Individual tasks have a description, compound tasks reveal what, when and how they run a sequence.

Wrap up

So, that’s it. When I need to get up and running with a new project, I clone starter kit. If needed, I adjust tasks/folders and in few minutes I am ready to start building what matters. I highly recommend to building something similar. It saves time, work and help with achieving better results. What do you think? Do you use something similar? I’ll be very happy to hear suggestions, thoughts or critique. :)