Upgrading your Gulp for running with Node 10

19 May 2018

Gulp.js is a tool for automating repeated tasks in your development workflow, like building Sass files to CSS, Typescript files to JS, minifying the static files, performing few cleanups, copying etc., This improves your productivity as you can forget these mundane tasks and focus on building the Software.

Gulp version 3.x is the current released npm package that works fine with Node 8 - LTS(Long Term Support stable, which is supported till 2019). When you perform npm install --save-dev gulp, by default it will fetch and install gulp 3.9.x version on your system.

Problem

NodeJs has released a new LTS version - Node 10 in the Month of April 2018. So most of the build server like Visual Studio Team Services(VSTS) online, AppVeyor, Travis CI etc., have started to set this version pre-installed on their build agents. So our gulpfile throws up error with Node version 10.

$ gulp
[21:08:45] Using gulpfile ~/code/gulptest/gulpfile.js
gulp[62193]: ../src/node_contextify.cc:631:static void node::contextify::ContextifyScript::New(const FunctionCallbackInfo<v8::Value> &): Assertion `args[1]->IsString()' failed.
 1: node::Abort() [/Users/roblou/.nvm/versions/node/v10.0.0/bin/node]
 2: node::InternalCallbackScope::~InternalCallbackScope() [/Users/roblou/.nvm/versions/node/v10.0.0/bin/node]
 3: node::contextify::ContextifyScript::New(v8::FunctionCallbackInfo<v8::Value> const&) [/Users/roblou/.nvm/versions/node/v10.0.0/bin/node]
 4: v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo*) [/Users/roblou/.nvm/versions/node/v10.0.0/bin/node]
 5: v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<true>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) [/Users/roblou/.nvm/versions/node/v10.0.0/bin/node]
 6: v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) [/Users/roblou/.nvm/versions/node/v10.0.0/bin/node]
 7: 0x2ee39308427d
[1]    62193 abort      gulp

Solution

  1. One option is that we can specify the Node JS version for this agents before initiating the build. But that would require these agents to perform an additional work to download the required Node version for every build and install it on the agent before actual build, which would increase the overall build time.
    For VSTS, NodeJs installer extension is available in marketplace. For other build system agents, it would need us to specify the Nodejs version so that particular old build image can be loaded. 
  2. The other recommended way, would be to upgrade your Gulp version to 4.x. That way it can seamlessly work well with Node 10 and still use latest build agents available on CI.

The following article will covers on how to upgrade to Gulp v4 and the modifications required to make your gulpfile compatible with the version.

Upgrading to Gulp 4

First, open your command  prompt terminal.

Remove the existing Gulp version that is globally installed on your machine

npm rm -g gulp

Then, globally install the new Gulp CLI package as follows

npm install -g gulp-cli

Proceed on installing Gulp 4 locally to your project folder using following command, which will allow you to install a stable version which is not yet released as the default npm package (@next

npm install --save-dev gulp@next

Above command will update your package.json and package-lock.json, with the new Gulp version and its dependencies. You can verify the global and local installation by running gulp -v command

C:/myprojectfolder> gulp -v
[21:03:13] CLI version 1.3.0
[21:03:13] Local version 4.0.0

This shows that you've successfully upgraded your package version to Gulp 4.

Next step is to fix the errors with gulpfile.js, as Gulp 4 has introduced new features & syntax that throws up error with Gulp 3 code.

Change 1 : AssertionError: Task function must be specified

Gulp 4 has introduced a way to run your multiple tasks either in series or parallel. So you have to specify it explicitly on your code.

So following gulp.js 3 code syntax will throw error 

gulp.task('default', ['sass', 'imagemin']);

In Gulp.js 4, above code should be converted as follows 

// If your tasks are dependent then change above to series as follows
gulp.task('default', gulp.series('sass', 'imagemin'));

// OR ELSE, if the tasks are independent then it can be run in parallel as follows
gulp.task('default', gulp.parallel('sass', 'imagemin'));

 Gulp's official documents in draft can be read in the Github docs.

Change 2 : Code should signal async task completion

Following SASS compilation task written in Gulp.js 3 will throw as error as it doesn't explicitly signal the task completion

gulp.task('sass', function () {
    gulp.src(sassPath)
    .pipe(plumber({ errorHandler: notify.onError("Error: <%=error.message %>") }))
    .pipe(sourcemaps.init())
    .pipe(sass({ outputStyle: 'compressed' }).on('error', sass.logError))
    .pipe(autoprefixer({ browsers: ['> 1%', 'IE 8'], cascade: false }))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest(cssPath));
});

To fix the error : 'The following tasks did not complete: default, sass', following done callback should be triggered to signal the task completion

gulp.task('sass', function (done) {
    gulp.src(sassPath)
    .pipe(plumber({ errorHandler: notify.onError("Error: <%=error.message %>") }))
    .pipe(sourcemaps.init())
    .pipe(sass({ outputStyle: 'compressed' }).on('error', sass.logError))
    .pipe(autoprefixer({ browsers: ['> 1%', 'IE 8'], cascade: false }))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest(cssPath));
    done();
});

 

Change 3: Different Gulp Watcher `change` event params

In Gulp.js 3, the file watcher on file changes will pass event parameter to the change event function as follows

gulp.task('watch', function(){
    gulp.watch('path/to/css/*.scss').on('change', function(event) {
        console.log(event.type + " : " + event.path);
    });
});

In Gulp.js 4, the change event would pass back two params

gulp.task('watch', function(){
    gulp.watch('path/to/css/*.scss')
     .on('change', function(path, stats) {
         console.log('File ' + path + ' was changed');
     }).on('unlink', function(path) {
         console.log('File ' + path + ' was removed');
     });
});

 

Finally,

Though its a major version change from 3.x to 4.x, the upgrade steps & modifications required for Gulp 4 are straight forward and simple. Currently, the situation is bit of a confusion, because the default npm package still installs 3.9.x, which doesn't work with latest Node 10. Missing direction for installing Gulp 4 seems to be a culprit as the developers are thrown up with unexpected error in their build system.

Gulp 4 is expected to be set as the default package, as soon as the the Gulp.js team completes all the updates to their docs as mentioned in below discussion;

Native crash in Node 10

Hope it gets sorted down as soon as possible, to avoid further confusion & surprises among developers.