Roots Discourse

Deploy to production server on shared hosting with gulp with FTP

Hi there,

Since most of my clients choose for a cheaper shared hosting solution and therefore I never have SSH access on the production server, I added ftpush to my grunt build command in the previous roots versions: Add ftpush to Grunt Watch?

Now with the new Sage I’m looking for the same setup in Gulp. I installed and configured everything with the suggested Bedrock & Trellis setup before realizing I still need SSH access to actually deploy to remote servers.

I looked at gulp-deploy-ftp: https://www.npmjs.com/package/gulp-deploy-ftp/
and vinyl-ftp: https://github.com/morris/vinyl-ftp

but was wundering if someone already has the same setup for hooking this into the gulp or gulp --production command and if it’s stable enough in practice?

Thanks a lot!

1 Like

Additional question;
What advantages does a Bedrock stacked WP site have if you can’t deploy to a production server with Capistrano due to a lack of SSH access? And if I manually FTP my Bedrock structure over to my production server, which files and folders are actually being used? Are these enough:

.env
config
web

Thanks!

Vinyl-ftp seems to work just fine, with the following additions to my gulpfile.js:

// ## Globals
...
var gutil        = require('gulp-util');
var ftp          = require('vinyl-ftp');

...
// ### Vinyl FTP
gulp.task('deploy', function() {
  var conn = ftp.create( {
    host:     'ftp.mydomain.com',
    user:     'username',
    password: 'password',
    parallel: 10,
    log:      gutil.log
  });
  var globs = [
    '*',
    '*.php',
    'dist/**',
    'lang/**',
    'templates/*.php',
    'lib/*.php',
    '!.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' ) );
});

// ### 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('styles',
              'scripts',
              ['fonts', 'images'],
              'deploy',
              callback);
});

Since the deploy task also runs on the gulp command, I had to manually exclude the static and maps files in the dist folder to prevent them from being uploaded.

1 Like

Hey Twansparant,

Thanks for your sharings on this! If I want to just run gulp for the local files without a deployment, what task would I run?

As I don’t really want to upload all files each time I run gulp… Or once I’ve done the initial upload will it just upload changed files?

Cheers,

J

Good question, which I haven’t figured out yet unfortunately…
In previous versions, you just ran gulp build but in Sage just gulp also runs the build task.

It does yes with the following line:

.pipe( conn.newer( '/public_html/web/app/themes/sage' ) )

However the problem is that the entire dist folder gets rebuild on gulp --production which causes the entire folder to get re-uploaded on every build.

Another thing I just bumped into, is that the previous hashed versions of the minified files don’t get deleted from the ftp server. So I tried to add the following line which should delete the remote dist folder entirely before uploading:

.pipe( conn.rmdir( '/domains/mydomain.com/public_html/web/app/themes/sage/dist' ), cb )

Which does delete the folder, but it gives me a bunch of errors too:

[10:28:57] TypeError: Cannot read property 'on' of undefined
[10:28:57] TypeError: Cannot read property 'on' of undefined
/pathto/site/web/app/themes/sage/node_modules/vinyl-ftp/lib/delete.js:53
                        cb( err );
                        ^
TypeError: undefined is not a function

So I placed a callback function within the task:

gulp.task('upload', function(cb) {
  cb();
  ...
});

But that doesn’t work. I’m not that familiar (yet) with the gulp syntax.
Where should I place the callback and what should go in it?

Could someone give us a hand?
Thanks!

No one appears to have a hand available :frowning:

Solution: Run task only on gulp --production