What does your gulpfile looks like?

Many of you use Gulp to generate css and js files. What does your gulpfile looks like?

My latest looks like this:

var gulp = require('gulp');

var autoprefixer = require('gulp-autoprefixer');
var cssmin = require('gulp-cssmin');
var notify = require('gulp-notify');
var sass = require('gulp-sass');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');

// css
gulp.task('css', function() {
  gulp.src('site/plugins/my_plugin/assets/scss/style.scss')
    .pipe(sass())
    .pipe(autoprefixer())
    .pipe(gulp.dest('site/plugins/my_plugin/assets/css'))
    .pipe(rename({suffix: '.min'}))
    .pipe(cssmin())
    .pipe(gulp.dest('site/plugins/my_plugin/assets/css'))
    .pipe(notify("CSS generated!"))
  ;
});

// JS
gulp.task('js', function() {
  gulp.src('site/plugins/my_plugin/assets/js/script.js')
    .pipe(uglify())
    .pipe(rename({suffix: '.min'}))
    .pipe(gulp.dest('site/plugins/my_plugin/assets/js/'))
    .pipe(notify("JS generated!"))
  ;
});

// Default
gulp.task('default',function() {
  gulp.watch('site/plugins/my_plugin/assets/scss/**/*.scss',['css']);
  gulp.watch('site/plugins/my_plugin/assets/js/**/*.js',['js']);
});
  • It’s made for a personal plugin.
  • gulpfile.js is placed in the domain root.

It can probably be improved a lot, but it does the job.

I’m not using GulpJS anymore, but I do have a question. Since gulp-sass is capable of compressing it’s output, why are you using gulp-cssmin as well? Does it compress the file better than the built in function?

For the record :slight_smile: :

 .pipe(sass({outputStyle: 'compressed'}))
1 Like

Good question. I tried it now and it does not seems to be a difference in size. Because I output one file that is not minified and one that is, maybe to use sass two times instead of one might theoretically require more power. I mean then it needs to do all the sass stuff as well. In real life I guess it makes no difference.

Thanks for the info! :slight_smile:

1 Like

Just me being curious, what do you now use? :wink:

No problem!

Well, I’ve tried Gulp for a while, but some day, a few things broke with the npm packages and I took a different approach. I ended up using CodeKit, which basically has support for most of the preprocessors (including LibSass) and things I need (concat, minify-ing, uglify-ing) and it’s just a app with a GUI, which I like :slight_smile: . Also: it does live reload. If you’re a Windows user, Prepros does the same thing.

Disclaimer: I’m not in any way related to CodeKit, just a happy user :slight_smile:

1 Like

I’ve been working with CodeKit on a Mac. I did not like it. It felt big and costs money. I feel like Gulp is really fast so I left the UI part. Now I like the more text approach.

I also don’t use gulp anymore.
My projects are usually very simple and I don’t need a ton of things so I’m currently using only NPM.

My package.json looks something like this:

{
  "name"         : "base-setup",
  "version"      : "1.0.0",
  "description"  : "base setup for all my future projects",
  "author"       : "Manuel Moreale <hello@manuelmoreale.com>",
  "homepage"     : "http://",
  "license"      : "UNLICENSED",
  "private"      : true,
  "contributors" : [],
  "repository"   : {
    "type" : "git",
    "url"  : "https://github.com/manuelmoreale/skylab.git"
  },


  "scripts"     : {
    "compile:sass" : "node-sass src/sass/main.sass dist/css/main.css | postcss -c conf/postcss-config.json",
    "watch:sass"   : "nodemon --ext sass --exec 'npm run compile:sass'",

    "compile:js" : "babel src/js -d dist/js",
    "watch:js"   : "nodemon --watch src/js --exec 'npm run compile:js'",

    "refresh" : "browser-sync start --config 'conf/bs-config.js'",
    "init"    : "npm run refresh & npm run watch:sass & npm run watch:js"
  },


  "devDependencies" : {
    "autoprefixer"        : "^6.4.0",
    "babel-cli"           : "^6.11.4",
    "babel-preset-es2015" : "^6.13.2",
    "browser-sync"        : "^2.14.0",
    "concurrently"        : "^2.2.0",
    "cssnano"             : "^3.7.3",
    "node-sass"           : "^3.8.0",
    "nodemon"             : "^1.10.0",
    "postcss-cli"         : "^2.5.2"
  }
}

I also have a few separate configuration files for browsersync and postcss.

2 Likes

How do more complex projects work with NPM scripts? Can your run stuff in series and in parallel?

Before I reply, I should say that I’m definitely not an expert on the subject :slight_smile:

How do more complex projects work with NPM scripts?

As I said, I usually work on fairly simple projects but I know people who are working in big studios on large projects and use NPM without any problem

Can your run stuff in series

If by series you mean one “task” after the other yes, you can. In my setup I do it once on the css file.
As you can see here
node-sass src/sass/main.sass dist/css/main.css | postcss -c conf/postcss-config.json"
I first run node sass to compile my main sass file into a normal css file. Then I take that file and pass it to postcss to do the tasks present in the postcss-config.json file. My config file for postcss is fairly simple as well as you can see below

{
    "use"           : ["autoprefixer" , "cssnano"],
    "input"         : "dist/css/main.css",
    "output"        : "dist/css/main.min.css",
    "local-plugins" : true,
    "autoprefixer"  : {
        "browsers" : "> 5%"
    },
    "cssnano" : {
        "discardComments" : {
            "removeAll" : true
        }
    }
}

I just run autoprefixer first and then minify.

and in parallel

This is a bit tricky. For what I know, and again I’m really not an expert, NPM doesn’t run natively scripts in parallel but there are a few packages to go around this problem.

If you’re interested in the topic, this is an old but good post and there are plenty of posts/tutorial on the web

2 Likes

I’m still using gulpjs.

I also use browsersync (live reload) and use mustache to compile blueprints.

var gulp = require('gulp');
var cleanCSS = require('gulp-clean-css');
var autoprefixer = require('gulp-autoprefixer');
var notify = require("gulp-notify");
var concat = require('gulp-concat');
var minifyjs = require('gulp-minify');
var data = require('gulp-data');
var fs = require('fs');
var path = require('path');
var mustache = require('gulp-mustache');
var replace = require('gulp-replace');
var plumber = require('gulp-plumber');
var autoprefixer = require('gulp-autoprefixer');
var sourcemaps = require('gulp-sourcemaps');
var browserSync = require('browser-sync').create();

gulp.task('css', function () {
   return gulp.src('assets/css/*.css')
      .pipe(plumber())
      .pipe(sourcemaps.init())
      .pipe(autoprefixer({
         browsers: ['last 2 versions'],
         cascade: false
      }))
      .pipe(cleanCSS())
      .pipe(concat('min.css', {newLine: ''}))
      .pipe(sourcemaps.write('../maps'))
      .pipe(gulp.dest("assets/css/output"))
      .pipe(notify('CSS Updated'))
      .pipe(browserSync.stream({match: "**/*.css"}));
});

gulp.task('js', function () {
   return gulp.src('assets/js/*.js')
      .pipe(plumber())
      .pipe(sourcemaps.init())
      .pipe(minifyjs({noSource: true}))
      .pipe(concat('main.js', {newLine: ''}))
      .pipe(sourcemaps.write('../maps'))
      .pipe(gulp.dest("assets/js/output"))
      .pipe(notify('Js Updated'))
      .pipe(browserSync.stream({match: "**/*.js"}));
});

gulp.task('blueprints', function () {
   gulp.src(['site/blueprints/blueprints/*.yml'])
      .pipe(plumber())
      .pipe(data(function (file) {
         return JSON.parse(fs.readFileSync('site/blueprints/data/' + path.basename(file.path, ".yml") + '.json'));
      }))
      .pipe(mustache())
      .pipe(gulp.dest('site/blueprints'))
      .pipe(notify('Blueprints Updated'));
});


gulp.task('browser-sync', function () {
   browserSync.init({
      injectChanges: true,
      proxy: "localhost/bemo/bemo/",
      online: false,
      snippetOptions: {
         ignorePaths: ["panel/**"]
      }
   });
});


gulp.task('default', ['blueprints', 'css', 'js', 'browser-sync'], function () {

   gulp.watch("assets/css/*.css", ['css']);
   gulp.watch("assets/js/*.js", ['js']);
   gulp.watch(["site/blueprints/blueprints/*.yml","site/blueprints/blueprints/partials/*.mustache","site/blueprints/data/*.json"], ['blueprints']);
   gulp.watch("site/**/*.php", browserSync.reload);
});
2 Likes

We’re using Gulp quite a bit at work. We used to rely on GUIs, such as Koala or Prepros, but this created problems for working with people outside our front-end team. Projects also didn’t have the necessary tools and configuration included in the project itself, which is a problem for maintenance. So I pushed for Gulp. Not that Gulp is necessarily better than others, but it does the job. You can also go with NPM scripts, but once you introduce some complexity you end up writing separate script files, and you’ve basically reinvented Gulp (or similar tools). :wink:

Going from GUI tools to a command-line process, we lost a few usability nice-to-haves. So I worked on adding better logging and error reporting.

After a while, the configuration grew big and I rewrote it to be modular and to take a config object, so you don’t have to edit the gulpfile.js itself. Our project is here, if you’re interested:

2 Likes

I am a quite heavy gulp user and use it for all kind of stuff. I like to work with a /dist folder, where an optimized version of the website will get created. That version then will get uploaded to the server. I would like to automate this process further but at the moment git-ftp and all the other ftp solutions did not really work out for me.

However here are the highlights that might be different from others.

  • I use gulp-load-plugins so you have an automated loader that makes the modules accessible via $.modulename. If you remove something from your gulpfile you also don’t have to remove the "require ‘xyz;’ which is handy to keep everything free from legacy code.

  • I use libsass for the fast sass compiling (way faster then ruby-sass, which made me crazy)

  • Gulp-rev handles my cache busting. It generates a manifest.json file where the name mapping gets saved. I use that mapping to replace the <link src=""> with the appropriate css name of the cache busted version.

  • With gulp-rewrite I am doing some renaming so the <?php echo js('...') ?> matches the cache busted file.

  • I added a image resize task so when I need test images and just have high resolution photos then I can just resize all of them to max 1920px in one swipe without the need of an external program or tool.

  • The images get optimized (progressive images) and adjusted in quality.

  • Via curl I generate a static index.html from the webpage. The index.html then gets used by critical to create the above the fold css. The saved file then gets inlined with a little snippet that gets called in my header.php.

<?php 
	$filename = kirby()->roots()->assets() . DS . 'css' . DS . 'inline.css';

	if (file_exists($filename)) 
	{
		echo '<style>';
		echo (file_get_contents( $filename ));
		echo '</style>';
	}
?>

The Gulpfile:

'use strict';

var gulp = require('gulp'),
fs = require('fs'),
critical = require('critical');

// load plugins
var $ = require('gulp-load-plugins')({
     pattern: '*',
     rename: {
         'gulp-gm': 'gm',
         'run-sequence': 'runSequence',
         'browserSync': 'browser-sync'
        }
   }
);

// preprocess sass
gulp.task('sass', function () {
  return gulp.src('app/assets/css/*.scss')
    .pipe($.sourcemaps.init())
    .pipe($.sass({outputStyle: 'expanded'}).on('error', $.sass.logError))
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest('app/assets/css/'));
});

// autoprefix styles and add hash for cache busting via gulp rev
gulp.task('styles', ['sass'], function() {
  return gulp.src(['app/assets/css/*.css'])
    .pipe($.csso())
    .pipe($.autoprefixer({
      browsers: ['last 2 versions'],
      cascade: true
      }))
    .pipe($.buffer())
    .pipe($.rev())      // use gulp-rev for cache busting
    .pipe(gulp.dest('dist/assets/css'))
    .pipe($.rev.manifest({
        base: './',
    }))
    .pipe(gulp.dest('dist/'));
});

// minify and concat all scripts
gulp.task('scripts', ['defer'], function(){
    return gulp.src('app/assets/scripts/*.js')
        // .pipe($.jshint())
        .pipe($.concat('vendor.js'))
        .pipe(gulp.dest('./app/assets/scripts/vendor/'))
        .pipe($.uglify())
        .pipe($.rename('vendor.min.js'))
        // .pipe($.jshint.reporter(require('jshint-stylish')))
        .pipe(gulp.dest('./dist/assets/scripts/vendor/'))
        .pipe($.size());
});

// minify and concat the scripts that can be loaded defered
gulp.task('defer', function(){
    return gulp.src(['app/assets/scripts/defer/*.js', '!app/assets/scripts/defer/defer.js'])
        .pipe($.concat('defer.js'))
        .pipe(gulp.dest('./app/assets/scripts/defer/'))
        .pipe($.uglify())
        .pipe($.rename('defer.min.js'))
        .pipe(gulp.dest('./dist/assets/scripts/defer/'))
        .pipe($.size());
});

// adjust the javascript and css linking so they match their minified version (via regex)
// vendor.js => vendor.min.js
// defer.js => defer.min.js
// main.css => main.min.css
gulp.task('rewrite', function(){
    var data = JSON.parse(fs.readFileSync('dist/rev-manifest.json', 'utf8'));
    return gulp.src(['dist/site/patterns/footer/footer.html.php', 'dist/site/snippets/header.php'], { base: './' }) //must define base so I can overwrite the src file below. Per http://stackoverflow.com/questions/22418799/can-gulp-overwrite-all-src-files
        .pipe($.if('**/footer.html.php', $.replace(/<\?php.*echo.*js\(\'assets\/scripts\/vendor\/vendor\.js\'\).*\?>/g, '<?php echo js(\"assets/scripts/vendor/vendor.min.js\") ?>'))) 
        .pipe($.if('**/footer.html.php', $.replace(/<\?php.*echo.*js\(\'assets\/scripts\/defer\/defer\.js\'.*\).*\?>/g, '<?php echo js(\"assets/scripts/defer/defer.min.js\", true) ?>'))) 
        .pipe($.if('**/header.php', $.replace(/<\?php.*echo.*css\(\'assets\/css\/main.css\'.*\).*\?>/g, '<?php echo css(\"assets/css/' + data["main.css"] + '\") ?>'))) 
        .pipe(gulp.dest('./')); //Write the file back to the same spot. 
});

// requires graphicsmagick http://www.graphicsmagick.org/download.html
// brew install graphicsmagick
gulp.task('imageResize', function() {
  gulp.src(['app/assets/images/**/*.jpg', 'app/assets/images/**/*.png'])
    .pipe($.gm(function (gmfile) {
      return gmfile.resize(1920);
    }))
    .pipe(gulp.dest('dist/assets/images/'))
});

gulp.task('images', function () {
    return gulp.src('app/assets/images/**/*')
        .pipe($.size({title: 'Image size', showFiles: 'true'}))
        .pipe($.cache($.imagemin({
            optimizationLevel: 5,
            progressive: true,
            interlaced: true
        })))
        .pipe(gulp.dest('dist/assets/images'))
        .pipe($.size({title: 'Image size after compression', showFiles: 'true'}));
});

gulp.task('copy', function () {
  return gulp.src([
    'app/**/*',
    '!app/assets/scripts/custom.js',
    '!app/assets/scripts/vendor/*',
    '!app/assets/images/**/*.*',
    '!app/assets/css/**/*',
    ],{
     dot:true
    }).pipe(gulp.dest('dist'))
      .pipe($.size({title: 'Copy'}));
});

// generate index.html via curl for inlining the above the fold css
gulp.task('generate-index', function() {
  return $.run('curl http://localhost/yourproject/dist/ > dist/index.html').exec() 
    .pipe(gulp.dest('output'));
})

// inline the above the fold
gulp.task('critical', ['generate-index'], function (cb) {
    var data = JSON.parse(fs.readFileSync('dist/rev-manifest.json', 'utf8'));
    critical.generate({
        inline: false,
        base: '.',
        css: ['dist/assets/css/' + data['main.css']],
        src: 'dist/index.html',
        dest: 'dist/assets/css/inline.css',
        minify: true,
        width: 375,
        height: 600
    });
});

// Optimize web fonts
gulp.task('fonts', function () {
    return gulp.src('app/assets/fonts/*')
        .pipe($.filter('**/*.{eot,svg,ttf,woff}'))
        .pipe($.flatten())
        .pipe(gulp.dest('dist/assets/fonts'))
        .pipe($.size());
});

// Clean dist Directory
gulp.task('clean', $.del.bind(null, ['dist']));

// Build Production Files, the Default Task
gulp.task('build', ['clean'], function (cb) {
  $.runSequence(['styles', 'fonts', 'images', 'copy', 'scripts'], ['rewrite', 'critical'], cb);
});

gulp.task('default',  function () {
    console.log('Please choose npm run build or npm run serve');
});

gulp.task('open', ['styles', 'scripts'], function () {
    require('opn')('http://localhost:9090');
});

gulp.task('dev', $.shell.task([
  'php -S localhost:9090',
  'echo "completed"'
  ],{
    verbose: true
}));

gulp.task('watch', function() {
    // watch for changes
    gulp.watch([
        'app/assets/css/**/*.css',
        'app/assets/scripts/**/*.js',
        'app/**/*.php'
    ]).on('change', $.browserSync.reload);

    gulp.watch('app/assets/css/**/*.scss', ['sass']);
    gulp.watch('app/assets/images/**/*', ['images']);
    gulp.watch('app/assets/scripts/**/*.js', ['scripts']); 
});

gulp.task('serve', function () {
  $.browserSync({
    proxy: "localhost/wunderwelten/app",
    port: 8080
  });

  // watch for changes
  gulp.watch([
    'app/assets/css/*.css',
    'app/assets/scripts/**/*.js',
    'app/**/*.php'
  ]).on('change', $.browserSync.reload);

  gulp.watch('app/assets/css/**/*.scss', ['sass']);
  gulp.watch('app/assets/images/**/*', ['images']);
  gulp.watch('app/assets/scripts/**/*.js', ['scripts']);
});

6 Likes

This is heartwarming because two months ago I tried to go barebones and setup an only npm config file, but it was quite slow to process—compared to gulp.

Not sure if there are options to overcome this factor, but I prefer speed if it has to be an auto-running process that gets triggered whenever you make a change on your project.

How is your experience so far? I am also mostly working on fairly simple projects, so I am curious to hear how is it going for you—speed related.

Is funny that you ask this now because just a few days ago I said to myself, quoting the great Roger Murtaugh, “I’m too old for this shit” ahah

I was trying to set up a new project and I wanted to use ES6 but after an hour spent between webpack, browserify, rollup e god knows what else I gave up.

I realized that what I need to do is to build sites and not waste hours of my life on these things.

So I went back to the combo MAMP + codekit 3
I can’t stand the idea of spending hours setting up stuff every time I update osx or node or whatever.

Rant aside, npm is pretty fast but it’s tricky to configure well at least in my experience

2 Likes

I usually just use Laravel Elixir. It works well in projects that aren’t based on Laravel.

https://laravel.com/docs/5.3/elixir

Supports sass, less, browserify, webpack, rollup, copying files, and more.

That shouldn’t be so difficult to setup. I wrote a simple yeoman generator for a very basic project setup with ES6 syntax.
You can find it here:

The readme would guide you throught a simple setup process. If you don’t want to use yeoman this task would do the trick:

gulp.task('build', function() {
  return $.browserify('./src/js/app.js')
    .transform("babelify")
    .bundle()
    .pipe($.source('bundle.js'))
    .pipe($.buffer())
    .pipe($.sourcemaps.init({loadMaps: true})) // loads map from browserify file
    .pipe($.sourcemaps.write('./')) // writes .map file
    .pipe(gulp.dest('./src/js/'));
});

This would be all you need for writing javascript with the es6 specification. Maybe that helps you out.

Problem is I got rid of GULP and I was trying to use only NPM.
But I appreciate your help :wink:

Well okay without gulp… I don’t know :D. You could use npm run scripts to avoid a globally installed gulp (if this is what bothers you on gulp :smiley: ) or you could run browserify / babel from command line

I was already running everything from the command line.
And I got rid of gulp just because you can do the same simple things using NPM directly and I hate to use 2 tools when I can just use 1.

But to be honest with you I was just tired of the endless chain of tools I now need to simply code a site.
I really don’t care about gulp, npm, grunt, browserify, broccoli or any other tool. I want something that works and doesn’t make me waste an afternoon every time I need to start a new project.

That’s why I went back to Codekit and now I’m happy again.

And I got rid of gulp just because you can do the same simple things using NPM directly and I hate to use 2 tools when I can just use 1.

npm is an package manager ecosystem and gulp is a task runner. Sure you can use npm to somehow hack your way through to do some script execution but I think its not where it’s strength lies.

Your client and your paycheck doesn’t care what tools you use that’s right. You have to decide yourself to what kind of the endless stream of tools you want to use and which one you reject because at the end of the day the best tools are those that workout for you. If you write javascript in Es15 or Es16 syntax, really is not a big deal and most of the time the hassle setting it up is not worth it.

However sometimes it might make sense to break out of the comfort zone and rethink the way of your very own workflow to discover and learn something new.

While setting up npm and stuff can be daunting, if you do it right you can reuse most of it on further projects. You could even write your own yeoman generator that scaffolds your very own kirby project with all your settings and dependencies ready and installed. Then everything you would need to do to start a new project would be to fire up that generator and you will have everything setup and ready in seconds.

I don’t want to persuade you to use npm but if you do it right and invest some time it can really enhance your workflow. Also this is just my perspective. Maybe you can achieve the same with codekit or something else, I on the other hand, don’t know those tools because they are often paid software and I don’t want to spend money on them.