As part of my development workflow, I use gulp to build the Javascript and CSS files for production. To ensure that the files are removed and replaced, rather than any kind of amendment, I use the del package. This had always worked for me, until nodejs updated on Ubuntu to version 10, when the use of `del` would cause the job to fail with the following error:

[09:31:50] The following tasks did not complete: default, <parallel>, cleanJavascript, cleanCss
[09:31:50] Did you forget to signal async completion?

The jobs to remove the assets are cleanJavascript and cleanCss. They simply delete all .js and .css files in their respective locations. Nothing major, but we do want to make sure old versions are removed when we rebuild. We could just remove these jobs, and hope an overwrite works; but if we remove a module or some other code, we want to ensure it is removed from use in the filesystem too - hence the deletion.

The function for cleanCss started as:

function cleanCss()
{
    return del(css_destination + "*.css");
}

Nothing complicated. It does one job, it does (did) it well. Until the update. When it broke, the short-term fix for development machines was to ignore those jobs, and just overwrite the files. That would still cause issues on our servers upon deployment, which we could prove by updating the job in our CI/CD pipeline.

Initial point of investigation, the documentation for del, specifically usage. The example, at the time of writing, is:

const del = require('del');
 
(async () => {
    const deletedPaths = await del(['temp/*.js', '!temp/unicorn.js']);
 
    console.log('Deleted files and directories:\n', deletedPaths.join('\n'));
})();

That didn't really help. We had the require statement there, but changing the function to async and to use await (see below) didn't work.

/**
 * Changed to match the documentation
 * This doesn't work
 */
async function cleanCss()
{
    await del(css_destination + "*.css");
}

Back to the documentation - this time for gulp's async completion information which says we can return a Promise. Great! but we already are, as part of del. The return type is a Promise.

The only thing left to try was to use the .sync function within del, and if that fails, find (or write) a new component to use. Last chance for del, and our function is now

async function cleanCss()
{
    await del.sync(css_destination + "*.css");
}

Success!

successful run of the full gulp task, following the addition of sync to the del call

It worked. It took more time than it should, but usually these things are built and left because they work. Unless you are creating them and working with them all the time, you tend to ignore them and their inner workings.

Now I can update the pipeline to properly test the deployment tasks, such as gulp.