cmegown
cmegown

Reputation: 401

Execute gulp.js task after command via child_process.exec is complete

I have a Jekyll project running with Browsersync, but I'm running into a minor issue with getting my gulp tasks to run as expected/desired. Here's a reduced version of my gulpfile:

const gulp = require('gulp');
const browserSync = require('browser-sync').create();

gulp.task('jekyll', () => {
  return require('child_process').exec('bundle exec jekyll serve');
});

gulp.task('serve', ['jekyll'], () => {
  browserSync.init({
    proxy: 'localhost: 4000'
  });

  gulp.watch('_site/**/*.html').on('change', browserSync.reload);
});

gulp.task('default', ['serve']);

What is desired/expected: The jekyll task is run and the command is executed, which results in an actively running server. Then the serve task is run, which opens up a new tab pointing at the already-running jekyll server. Everything is right in the world.

What actually happens: The jekyll task is run and the command is executed. The serve task is run immediately after the jekyll task is run, and a new browser tab is opened. The tab will spin forever because at the time it was opened the server (via jekyll) is not running yet. After a few seconds a manual refresh will get things working as expected because at that point the server is running.

My main question is this: how can I prevent the jekyll task from being "completed" until after the bundle exec jekyll serve command is actually complete with the server running? It's a very trivial inconvenience to have to manually refresh the page that first time, but this is a chance to learn something new.

Upvotes: 2

Views: 2365

Answers (2)

cmegown
cmegown

Reputation: 401

I'll post the solution that I have found to work best for me since I originally asked this question.

The problem was that I was attempted to spin up a Jekyll server first, then run additional gulp tasks afterwards. Maybe there's a way to do that, maybe not. I found that spinning up the Jekyll server in one command prompt, and then executing the remaining gulp tasks in another was the answer.

Ultimately all the was really required to change in the code was to simply remove the jekyll task:

const gulp = require('gulp');
const browserSync = require('browser-sync').create();

gulp.task('jekyll', () => {
    return require('child_process').exec('bundle exec jekyll serve');
});

gulp.task('serve', () => {
    browserSync.init({
        proxy: 'localhost: 4000'
    });

    gulp.watch('_site/**/*.html').on('change', browserSync.reload);
});

gulp.task('default', ['serve']);

If anyone out there has a more elegant solution I would love to hear it!

Upvotes: 1

Roberto Navarro
Roberto Navarro

Reputation: 765

Give the following a try, I'm using it myself with great success:

const child = require("child_process");
const gutil = require("gulp-util");

gulp.task("jekyll", (done) => {
  let jekyll = child.spawn("jekyll", ["serve", "--incremental", "--drafts"])
              .on("close", () => {
                  done(); // let gulp know the task has completed
              });
  let jekyllLogger = function (buffer) {
      buffer.toString()
      .split(/\n/)
      .forEach(function (message) {
          if (message) {
              gutil.log("Jekyll: " + message);
          }
      });
  };

  jekyll.stdout.on("data", jekyllLogger);
  jekyll.stderr.on("data", jekyllLogger)
}

Upvotes: 2

Related Questions