Roots Discourse

Run task only on gulp --production

Hi there,

Following up on this thread, is it possible to run a gulp task only on gulp --production?
Since I don’t have SSH access to my remote server, I have to upload my changed files with a gulp task using vinyl-ftp:

// ### Vinyl FTP
gulp.task( 'upload', ['rmdirs'], function ( cb ) {
  var conn = ftp.create( ftppass );
  var globs = [
    '*',
    '*.php',
    'dist/**',
    'lang/**',
    'templates/*.php',
    'lib/*.php',
    '!.ftppass.json',
    '!.git',
    '!*.json',
    '!*.md',
    '!*.xml',
    '!assets',
    '!bower_components',
    '!gulpfile.js',
    '!node_modules',
    '!node_modules/**',
  ];
  // using base = '.' will transfer everything to /public_html correctly
  // turn off buffering in gulp.src for best performance
  return gulp.src( globs, { base: '.', buffer: false } )
    .pipe( conn.newer( '/public_html/web/app/themes/sage/' ) ) // only upload newer files
    .pipe( conn.dest( '/public_html/web/app/themes/sage/' ) );
});

// Remove directories
gulp.task( 'rmdirs', ['rmdirScripts', 'rmdirStyles'] );

// Remove dist/scripts directory
gulp.task( 'rmdirScripts', function ( cb ) {
  var conn = ftp.create( ftppass );
  conn.rmdir( '/public_html/web/app/themes/sage/dist/scripts', cb );
});

// Remove dist/styles directory
gulp.task( 'rmdirStyles', function ( cb ) {
  var conn = ftp.create( ftppass );
  conn.rmdir( '/public_html/web/app/themes/sage/dist/styles', cb );
});

Since it doesn’t automatically delete older minified production scripts and styles, I have to run a gulp sequence which will delete the dist/scripts and dist/styles directories first remotely before uploading the new ones.

This works perfect, however when running gulp, the upload task also runs which causes non-production files to get uploaded and deleting the production files in dist/scripts and dist/styles.

So to completely solve my problem, I have to run the upload task only with the --production flag.
How do I achieve this?

Thanks!

In your glob array you definitely want to be whitelisting files instead of blacklisting.

Ok thanks, but how does that help me with this issue?
I’m trying to comprehend what tasks I need to add in order to run only on gulp --production?
Cheers!

I can’t grasp my head around how this works in Gulp…
Right now, I added the following in my gulpfile.js:

// ## Globals    
var vinylftp     = require('vinyl-ftp');
var ftppass      = require('./.ftppass.json');
        
// Set production flag
var isProduction = false;
if (argv.production === true) {
  isProduction = true;
}
        
// ### FTP tasks
var ftpTasks = function() {
  return lazypipe()
    .pipe(function(cb) {
      var conn = vinylftp.create(ftppass);
      conn.rmdir( '/public_html/web/app/themes/sage/dist/scripts', function(err) {
        if (err) { console.log(err); }
      });
    })
    .pipe(function(cb) {
      var conn = vinylftp.create(ftppass);
      conn.rmdir( '/public_html/web/app/themes/sage/dist/styles', function(err) {
        if (err) { console.log(err); }
      });
    })
    .pipe(function() {
      var conn = vinylftp.create(ftppass);
      var globs = [
        '*',
        '*.php',
        'dist/**',
        'lang/**',
        'templates/*.php',
        'lib/*.php',
        '!.ftppass.json',
        '!.git',
        '!*.json',
        '!*.md',
        '!*.xml',
        '!assets',
        '!bower_components',
        '!dist/scripts/jquery.js',
        '!dist/scripts/jquery.js.map',
        '!dist/scripts/main.js',
        '!dist/scripts/main.js.map',
        '!dist/scripts/modernizr.js',
        '!dist/scripts/modernizr.js.map',
        '!dist/styles/editor-style.css',
        '!dist/styles/editor-style.css.map',
        '!dist/styles/main.css',
        '!dist/styles/main.css.map',
        '!gulpfile.js',
        '!node_modules',
        '!node_modules/**',
      ];
      // using base = '.' will transfer everything to /public_html correctly
      // turn off buffering in gulp.src for best performance
      return gulp.src( globs, { base: '.', buffer: false } )
        .pipe( conn.newer( '/public_html/web/app/themes/sage' ) ) // only upload newer files
        .pipe( conn.dest( '/public_html/web/app/themes/sage' ) ),
        function() {
          console.log(chalk.green('✔ All done!'));
        };
    })();
};
        
// ### Upload
gulp.task('upload', function() {
  console.log(isProduction);
  // gulp.src('.') // same error
  return gulp.src('.')
    .pipe( gulpif(isProduction, ftpTasks() ) );
});
        
// ### Build
gulp.task('build', function(callback) {
  runSequence('styles',
              'scripts',
              ['fonts', 'images', 'svg'],
              'upload',
              callback);
});

When I run gulp or gulp --production I’m getting these errors:

[11:55:38] Starting 'upload'...
true
[11:55:38] 'upload' errored after 11 ms
[11:55:38] TypeError: undefined is not a function
    at proxyStream (/pathto/site/web/app/themes/sage/node_modules/lazypipe/node_modules/stream-combiner/node_modules/duplexer/index.js:65:16)
    at Array.forEach (native)
    at forEach (/pathto/site/web/app/themes/sage/node_modules/lazypipe/node_modules/stream-combiner/node_modules/duplexer/index.js:11:20)
    at duplex (/pathto/site/web/app/themes/sage/node_modules/lazypipe/node_modules/stream-combiner/node_modules/duplexer/index.js:27:5)
    at module.exports (/pathto/site/web/app/themes/sage/node_modules/lazypipe/node_modules/stream-combiner/index.js:20:17)
    at build (/pathto/site/web/app/themes/sage/node_modules/lazypipe/index.js:26:20)
    at ftpTasks (/pathto/site/web/app/themes/sage/gulpfile.js:233:7)
    at Gulp.<anonymous> (/pathto/site/web/app/themes/sage/gulpfile.js:367:33)
    at module.exports (/pathto/site/web/app/themes/sage/node_modules/gulp/node_modules/orchestrator/lib/runTask.js:34:7)
    at Gulp.Orchestrator._runTask (/pathto/site/web/app/themes/sage/node_modules/gulp/node_modules/orchestrator/index.js:273:3)

Any idea what I’m doing wrong here?
Thanks!

Hi Austin, appreciate the response… But could you please elaborate on this a bit?

Is there really no one who could help us with an example on how to add a gulp task with gulp-if condition for the –production flag?
Can’t find any examples out there that work n this workflow…
Any help is appreciated! Thanks

@jakus I finally worked it out!

First create a .ftppass.json file in your theme root with your FTP credentials:

{
  "host":       "ftp.mydomain.com",
  "user":       "username",
  "password":   "password"
}

Then add these 2 globals at he top of your gulpfile.js:

var vinylftp     = require('vinyl-ftp');
var ftppass      = require('./.ftppass.json');

Then in your upload task, check if the --production flag is set and if so, run a sequence of tasks:

// ### Upload
gulp.task('upload', function(callback) {
  if (argv.production === true) {
    runSequence('rmdirdist', ['ftpupload'], callback);
  }  
});

First remove the remote dist folder with the rmdirdist task:

// ### Remove remote dist directory
gulp.task( 'rmdirdist', function (cb) {
  var conn = vinylftp.create( ftppass );
  conn.rmdir( '/public_html/web/app/themes/sage/dist', cb );
});

After that, upload only new files (including the freshly created dist directory) with the ftpupload task:

// ### Upload Vinyl FTP
gulp.task('ftpupload', function (callback) {
  var conn = vinylftp.create({
    host:       ftppass.host,
    user:       ftppass.user,
    password:   ftppass.password,
    log:        gutil.log
  });
  var globs = [
    '*',
    '*.php',
    'dist/**',
    'lang/**',
    'templates/*.php',
    'lib/*.php',
    '!*.json',
    '!*.md',
    '!*.xml',
    '!assets',
    '!bower_components',
    '!node_modules',
  ];
  // using base = '.' will transfer everything to /public_html correctly
  // turn off buffering in gulp.src for best performance
  return gulp.src( globs, { base: '.', buffer: false } )
    .pipe( conn.newer( '/public_html/web/app/themes/sage' ) ) // only upload newer files
    .pipe( conn.dest( '/public_html/web/app/themes/sage' ) );
});

Finally, add the upload task to the build sequence task:

// ### Build
gulp.task('build', function(callback) {
  runSequence('styles',
              'scripts',
              ['fonts', 'images', 'svg'],
              'upload',
              callback);
}); 

This should work now!
Happy :smile:

2 Likes

Amazing man! Thank you very much…

I’ll give it a shot now.

Sorry just have a stupid noobish question - just to confirm do I run gulp upload?

Or can I just run gulp --production and this will run the upload/rmdist tasks automatically?

Thanks again mate.

A little late to the party, but a couple comments:

flag usage

I define flags here that tell the rest of the gulpfile what should be enabled/disabled. Here is an example of me using one of the flags. I suppose you could also do something like if (enabled.rev) { /*whatever*/ }. The way you are doing it is fine though, just wanted to elaborate on how I am parsing the flags.

do not blacklist things

I cannot really think of a situation where you would want to create a blacklist for your globs. You should generally always be whitelisting stuff unless you have a good reason to blacklist.

  var globs = [
    '*.php',
    'dist/**',
    'lang/**',
    'templates/*.php',
    'lib/*.php'
  ];

This way no secret stuff makes it’s way to the public web.

How to conditionally run the upload task

The way you are doing it works I’m sure, but it has some limitations. You cannot run gulp uploads on it’s own without specifying --production. Here is how I would do it:

// ### Build
gulp.task('build', function(callback) {
  var tasks = [
    'styles',
    'scripts', ['fonts', 'images', 'svg']
  ];

  if (argv.production) {
    // only add upload to task list if `--production`
    tasks = tasks.concat(['upload']);
  }

  runSequence.apply(
    this,
    tasks.concat([callback])
  );
});

And then remove the if (argv.production) inside your uploads task. This way you can run the uploads task on it’s own with gulp uploads without specifying --production

// ### Upload
gulp.task('upload', function(callback) {
    runSequence('rmdirdist', 'ftpupload', callback);
});
2 Likes

Thanks Austin, this is awesome feedback and helps greatly…

Thanks for your reply Austin!

Yeah, that’s the first thing I tried, adding this to the enabled array:

// FTP Upload when `--production`
upload: argv.production

But then I get an error:

  upload: argv.production
  ^^^^^^^^
SyntaxError: Unexpected identifier

I don’t understand exactly what the difference is between functions declared like this:

var upload = function() {}

and tasks or how you call such a function within a task?
How exactly would that work in this case?

Thanks, I tried that too actually, but all my bower_components and node_modules got uploaded too because this line was still in my globs : '*'
I removed it, and it works now!

Great, much better indeed!
Thanks for your help, glad I got this workflow working now!

This is a syntax error. Check your commas and stuff.

FYI: Austin’s steps/code are working fine for me… The tasks are not uploading any of the node_modules or bower_components and I can run the gulp upload task on its own…

Maybe follow Austin’s code Twansparant :smile:

it is working fine for me too @jakus, just not when defining the flag in the CLI options.
Doesn’t matter anyway, because my problem is solved!