Gulp watch, incremental build

1.4k views Asked by At

I'm struggling to make gulp-watch behave as I desire. This small project is tooling to build HTML5 emails templates from Jade+SASS, in a repeatable way. The directory structure is as such:

.
├── Gulpfile.coffee
├── Gulpfile.js
├── build
│   ├── hello-world.html
│   └── styles
│       └── ink.css
├── node_modules
│   ├── ...snip...
├── package.json
└── source
    ├── hello-world.jade
    ├── layouts
    │   └── default.jade
    └── styles
        └── ink.scss

My wish list is thus:

  • Build all templates when styles or templates change. This is what I can't do
  • Don't have a seaerate "cold" start, always use the gulp incremental build. (This seems to work)
  • Live reload would reload the browser, that'd be cool. (This too)

The Gulpfile, in CoffeeScript notation for brevity is included below, it's predominantly based on the documentation Incremental rebuilding, including operating on full file sets.

gulp      = require 'gulp'
inlineCss = require 'gulp-inline-css'
jade      = require 'gulp-jade'
marked    = require 'gulp-marked'
plumber   = require 'gulp-plumber'
rename    = require 'gulp-rename'
sass      = require 'gulp-sass'
cached    = require 'gulp-cached'
util      = require 'gulp-util'
watch     = require 'gulp-watch'
webserver = require 'gulp-webserver'

styleGlob              = "source/styles/*.scss"
templateAndLayouysGlob = "source/**/*.jade"
templateGlob           = "source/*.jade"

styleChangeHandler = (event) ->
  if event.type is "deleted"
    delete cached.caches.scripts[event.path]

templateChangeHandler = (event) ->
  if event.type is "deleted"
    delete cached.caches.templates[event.path]

gulp.task "styleWatcher", ->
  gulp.src(styleGlob)
    .pipe(cached('styles'))
    .pipe(watch(styleGlob))
    .pipe(sass())
    .pipe(gulp.dest("build/styles"))
    .on('error', util.log)

gulp.task "templateWatcher", ->
  gulp.src(templateGlob)
    .pipe(cached('templates'))
    .pipe(watch(templateGlob))
    .pipe(jade(pretty: true))
    .pipe(inlineCss())
    .pipe(gulp.dest("build/"))
    .on('error', util.log)

gulp.task 'webserver', ->
  buildPath = 'build/'
  gulp.src(buildPath)
    .pipe(webserver({
      livereload: true,
      directoryListing: {
        enable: true,
        path: buildPath
      },
      open: true
    }))

gulp.task "watch", ->
  styleWatcher = gulp.watch(styleGlob, ["styleWatcher"])
  styleWatcher.on 'change', styleChangeHandler

  templateWatcher = gulp.watch(templateGlob, ["templateWatcher"])
  templateWatcher.on 'change', templateChangeHandler

  # I would expect this to fire when something in build/styles/*.css
  # is updated by the style watcher?
  templateStyleWatcher = gulp.watch('build/styles/*.css', ["templateWatcher"])
  templateStyleWatcher.on 'change', templateChangeHandler

gulp.task "default", ["styleWatcher", "templateWatcher", "watch", "webserver"]

If it were possible, and I'd written this watcher in GNU Make or similar, I would have had the option to express that build/, and rely on the tooling to rebuild those files if the ones upon which they depend are out of date.

I've seen that there are a number of gulp-<something about inlining> plugins, but none of them make clear whether they support this conditional recompilation by watching paths that were imported for changes (I doubt it).

Given my background in systems programming, I may well be approaching Javascript build tooling in a completely incorrect way.

0

There are 0 answers