Pulling font-face CSS files automatically into your workflow with Gulp

I wanted to share something cool with everyone - I’ve built a little timesaver by adding a couple of tasks to the gulpfile.js. It was inspired by this discussion: Cannot get @font-face to work with Sage/Sass

Sage does a nice job of grabbing the font files and flattening them into the dist/fonts folder on compile, but I always had to do the other CSS part manually.

Because I often work with fonts from various places like Fontsquirrel (which often are generated with lots of junk files plus a file called stylesheet.scss), I often end up with a bunch of seperate font folders which means I have to move everything into assets/fonts, clean up the contents, and then manually copy and paste the contents of all the loose stylesheets into a single file, and then finally update the file references for /dist/ - and after doing this repeatedly you start feeling the frustration. I thought it would be great to use Gulp to automate the process so I can add and remove fonts as I like and not have to worry about updating @font-face references by hand. So here is my stab at doing that…

This assumes you have a directory in /assets/ with font folders arranged like:

/fonts/
  /name-of-font-1/
     (font files, .woff, .eot, .ttf etc)
     stylesheet.css
  /name-of-font-2/
     (font files, .woff, .eot, .ttf etc)
     stylesheet.css
  /name-of-font-3/
     (font files, .woff, .eot, .ttf etc)
     stylesheet.css

Look out for my comments next to the lines I added or modified, in each of the code blocks below. If your folder structure differs to the one I have, you may need to amend the glob patterns in the fontcss task.


First off in my terminal I add a couple of gulp plugins:
gulp install --save-dev gulp-concat-util gulp-replace

Then in gulpfile.js I modify the variable list to call the new plugins:

// ## Globals
var argv         = require('minimist')(process.argv.slice(2));
var autoprefixer = require('gulp-autoprefixer');
var browserSync  = require('browser-sync').create();
var changed      = require('gulp-changed');
var concat       = require('gulp-concat-util'); //Updated concat to concat-util
var flatten      = require('gulp-flatten');
var gulp         = require('gulp');
var gulpif       = require('gulp-if');
var imagemin     = require('gulp-imagemin');
var jshint       = require('gulp-jshint');
var lazypipe     = require('lazypipe');
var less         = require('gulp-less');
var merge        = require('merge-stream');
var minifyCss    = require('gulp-minify-css');
var plumber      = require('gulp-plumber');
var rev          = require('gulp-rev');
var runSequence  = require('run-sequence');
var sass         = require('gulp-sass');
var sourcemaps   = require('gulp-sourcemaps');
var uglify       = require('gulp-uglify');
var replace      = require('gulp-replace'); //Added variable for gulp-replace

After this I wrote two new tasks after the JSHint code block:

// ### Custom tasks
// Take all the fontcss stylesheets and concat them into a single SCSS file
gulp.task ('font-css', function() {
  return gulp.src([path.source + 'fonts/**/stylesheet.css']) //Gather up all the 'stylesheet.css' files
     .pipe(concat('_fonts.scss')) //Concat them all into a single file
     .pipe(concat.header('/* !!! WARNING !!! \nThis file is auto-generated. \nDo not edit it or else you will lose changes next time you compile! */\n\n'))
     .pipe(replace("url('", "url('../fonts/"))
     .pipe(gulp.dest(path.source + ['styles/components'])); // Put them in the assets/styles/components folder
});

// Remove the font-face SCSS file if a cleanup is run
gulp.task('clean-font-css', require('del').bind(null, [path.source + 'styles/components/_fonts.scss']));

and then add the new fontcss task to watch, build and clean tasks:

// ### Watch
// `gulp watch` - Use BrowserSync to proxy your dev server and synchronize code
// changes across devices. Specify the hostname of your dev server at
// `manifest.config.devUrl`. When a modification is made to an asset, run the
// build step for that asset and inject the changes into the page.
// See: http://www.browsersync.io
gulp.task('watch', function() {
  browserSync.init({
    files: ['{lib,templates}/**/*.php', '*.php'],
    proxy: config.devUrl,
    snippetOptions: {
      whitelist: ['/wp-admin/admin-ajax.php'],
      blacklist: ['/wp-admin/**']
    }
  });
  gulp.watch([path.source + 'fonts/**/stylesheet.css'], ['font-css']); //New fontcss task
  gulp.watch([path.source + 'styles/**/*'], ['styles']);
  gulp.watch([path.source + 'scripts/**/*'], ['jshint', 'scripts']);
  gulp.watch([path.source + 'fonts/**/*'], ['fonts']);
  gulp.watch([path.source + 'images/**/*'], ['images']);
  gulp.watch(['bower.json', 'assets/manifest.json'], ['build']);
});
// ### Build
// `gulp build` - Run all the build tasks but don't clean up beforehand.
// Generally you should be running `gulp` instead of `gulp build`.
gulp.task('build', function(callback) {
  runSequence(
              'font-css', //New fontcss task
              'styles', 
              'scripts',
              ['fonts', 'images'],
              callback);
});
// ### Gulp
// `gulp` - Run a complete build. To compile for production run `gulp --production`.
gulp.task('default', ['clean', 'clean-font-css' /*New fontcss cleanup task*/], function() {
  gulp.start('build');
});

Finally, I open /styles/main.scss and add:

@import "components/_fonts"; // Import custom @font-face fonts

After all that you should be able to run gulp to re-compile everything, and you should see all your fonts referenced nicely in dist/styles/main.css. It also works with gulp watch so you can move stuff in an out of the fonts folder and have it all regenerate nicely :thumbsup:

You’ll know it’s all working when you see extra tasks in the gulp output:

$ gulp 

[06:55:45] Using gulpfile /var/www/clients/project/www/wp-content/themes/cheriemcom-theme/gulpfile.js
[06:55:45] Starting 'clean'...
[06:55:45] Starting 'clean-font-css'...
[06:55:45] Finished 'clean-font-css' after 8.96 ms
[06:55:46] Finished 'clean' after 78 ms
[06:55:46] Starting 'default'...
[06:55:46] Starting 'build'...
[06:55:46] Starting 'font-css'...
[06:55:46] Finished 'default' after 24 ms
[06:55:46] Finished 'font-css' after 193 ms
[06:55:46] Starting 'wiredep'...
[06:55:47] Finished 'wiredep' after 1.15 s
[06:55:47] Starting 'styles'...
[06:55:51] Finished 'styles' after 4.01 s
[06:55:51] Starting 'jshint'...
[06:55:51] Finished 'jshint' after 380 ms
[06:55:51] Starting 'scripts'...
[06:55:56] Finished 'scripts' after 4.57 s
[06:55:56] Starting 'fonts'...
[06:55:56] Starting 'images'...
[06:55:56] gulp-imagemin: Minified 0 images
[06:55:56] Finished 'images' after 14 ms
[06:55:56] Finished 'fonts' after 604 ms
[06:55:56] Finished 'build' after 11 s

/!\ A WORD OF CAUTION
This process generates a file here: assets/styles/components/_fonts.scss which will be automatically generated every time something changes in your fonts folder, so don’t do any manual editing in this file or you are prone to lose it all!

This is my first proper exploration into Gulp and it really is a thing of beauty. Hopefully it saves someone some time in their workflow :slight_smile: It’s not fully tested but I haven’t seen any explosions so far. If there’s something here that could be improved I am all ears too.

7 Likes

This seems like a great feature, possibly something that I would like to see in the core. I would like to know what @austin at thinks about your gulp file. Also would be great to see a branch with this feature incorporated so some of us could test it out and give feedback. this is something I would definitely use in some of my projects that aren’t using google fonts or type kit.

Thanks for the feedback :slight_smile: I’ll make a fork of the Sage project and add my commits into it, and if it meets the standards for Sage I’m happy for people to take it and extend further. I’ve found it to be a massive timesaver myself, as I’m often swapping fonts in and out to test out the appearance of things :slight_smile:

I’ve thrown up a quick repo here:
https://github.com/drawcard/sage-css-font

Instructions:
https://github.com/drawcard/sage-css-font/wiki

Some thoughts on improvements I’ve had since putting this together:

  1. Some fonts will come accompanied with lots of junk, eg documentation, etc. While this is good to keep in the /assets/ folder, it should be stripped out when everything is compiled to /dist/. I haven’t currently fixed that, but it should be before integrating this. It might take a modification of the fonts task.

  2. There is probably a better way of handling the concat + import method than making a _fonts.scss file, so if anyone has ideas on improving that, that would be awesome.

  3. Though I thought it was initially updating things when gulp watch was running, it looks like it’s best to run gulp to do a full recompile, when moving things in and out of the /fonts/ folder. It’s probably something going on in my setup, but I’d like to know if anyone has the same issue.

Please take this idea and run with it - I am not a professional with Gulp so I’m sure there’s better ways of doing this, but so far it works great for me :thumbsup:

At the moment, the compile chain breaks if the font-css task is run without any fonts in the folder (or if no matched CSS files are detected). This is because there’s no .css files to work on, so the task doesn’t generate _fonts.scss and the main.css file compile ends with this error:

assets/styles/main.scss
  8:9  file to import not found or unreadable: components/_fonts
Current dir: 
assets/styles/main.scss
  8:9  file to import not found or unreadable: components/_fonts
Current dir: /var/www/clients/website.com.au/www/wp-content/themes/website-theme/assets/styles/

This makes me wonder if it’s better to take this task out of the main gulp or gulp watch chain, and just execute it on it’s own, eg by running gulp font-css.

The other option is to just have a assets/styles/components/_fonts.scss file created off the bat, so there’s always a file present when compiling.

I’ll experiment and update my fork if necessary.

Thank you for this!

I’m going to take a look here in a bit.

As far as priorities this needs to get merged: https://github.com/roots/sage/pull/1485 before any more gulpfile craziness can happen. The faster this gets tested and merged the faster we can start doing more cool stuff with the gulpfile.

No worries, glad it is useful to everyone :smile:

I’ve made a minor update to the repo, by adding in a blank _fonts.scss file to /assets/styles/components/ - it seems to be the easiest solution to fixing the above problem I came across, for simplicity’s sake.

Awesome solution! Thanks.
I use IcoMoon a lot to generate custom icon fonts, so I changed your task a little because their default stylesheet file is called style.css.
The only thing bothering me about this is that this stylesheet (and other unnecessary files from the font folder) are also copied over to the dist/fonts folder, but I guess that’s done with the original fonts task.

Yeah that’s probably the only setback. Though you could get crafty and use another gulp plugin to remove that errant file as another task in the pipeline… something like https://www.npmjs.com/package/gulp-rm

I also have a different issue when running gulp watch at the same time as running gulp --production.

Because the _font.scss changes during the font-css task and the clean task has already run, the dist folder also contains the non-production files because they get recompiled with the watch task.

It’s not a biggie, but because I also have a FTP task running, the non-production files are uploaded as well.