"task runners like Grunt and Gulp are just wrappers for existing CLIs"
I can't say I agree with this. Actually, all the arguments about replacing task runners with npm always failed to convince me.
There are several plugins that simply don't even have a CLI, to begin with. Basically, your suggestion is to write a js file to replace their behaviour and run node on them. You ended up writing 27 lines of code to do something that gulp.watch does in a couple, and better. Without spawning new processes, either.
The argument "npm vs. task runners" works better against Grunt, anyway. We know that Grunt is slow, is verbose, has a config system that quickly becomes unmanageable.
Gulp, on the other hand, does not. Gulp has a declarative approach for its tasks, and a procedural one inside them. It's clear and works beautifully. Moreover, the adoption of vinyl files has great advantages in terms of speed (since all operations happen in memory, and don't write a temp file each time) and it's also great for mocking files. And while it's true that streaming mode doesn't work for all plugins, at least it does for some.
The procedural style allows me to do some computations, if necessary, even if it's a simple `if`. Doing the same with a npm script ranges from being impossible to being awkward.
Setting the configuration for a plugin can usually be done with a POJO that I can indent as I wish; doing the same with the CL is ugly, as I have to do it in a single line (thanks Crockford that didn't allow multiline strings in JSON).
Piping results to another operation is damn simple with Gulp, while I have to append everything in the same line with && using commands. "pre-" and "post-" scripts mitigate the problem only partially (basically it's splitting the command in 3 parts).
Error handling can be better, but at least is there and it's flexible.
I tried the "npm scripts" approach in the past. It started nice, it ended up an unmaintainable mess. Maybe it's because I'm kind of used to Gulp, who knows. But once I had a task that sounded like: "Take the images in that folder, create multiple versions of them according to the spec in that json file, optimize the results and put them in their correct folder." I have no idea how to do this in a command, except for creating a js file for it - something that I did NOT want to do.
I fail to see what's the problem in including Gulp in the build workflow. It's a dev dependency, it won't bloat your final result. It's also relatively small - I'm way more worried about the size of Angular 2, for instance.
Gulp is only suited to problems which can be represented as streams. Certain things, like copying files from a dir to another, firing up mock server, etc, are a pain in the neck with gulp. I moved from gulp to npm scripts and never looked back.
If those are the reasons, I'm even less convinced to switch to npm scripts.
Copying files is as easy as
gulp.src(toBeCopiedGlob)
.pipe(gulp.dest(destDir));
For the rest, Gulp tasks are just JavaScript functions. You're not actually forced to use gulp.src or any other method. You can start shell scripts, you can spawn servers, command livereloading, perform computations and evaluate conditions, etc. and, above all, you have a direct connection with the underling JavaScript application, as you can actually import its modules.
In addition to this, I have a consistent interface in which I can define parameters and help texts, and that's definitely a plus for anyone who's looking at the project's tasks for the first time.
No, it's not that simple if you want to copy certain files from A to B and C, other files from A to D etc
I really don't see why I should be spawning servers or shell scripts etc from within gulp when it works much better just running them directly.
> No, it's not that simple if you want to copy certain files from A to B and C, other files from A to D etc
Well, yes, it's *that* simple. If I have multiple destinations for the same file, I just have to .pipe again to another destination, that's it.
If I have to move other files to other destinations, I just have to do a new gulp.src and so on. On the plus side, I have the syntax of glob at disposal, and directories get created if they don't exist yet.
Are you even arguing that JavaScript doesn't have enough flexibility for that?
> I really don't see why I should be spawning servers or shell scripts etc from within gulp when it works much better just running them directly.
Strange, I'm sure I just perfectly explained why. Maybe I wasn't clear?
And no, they don't work "much better". At best they work as good.
The only times I rely on just npm scripts is for simple projects(?) that sprout and die in a day.
No, you haven't explained perfectly why. And yes, they work much better because there is no extra gulp wrapper around them. If you are happy with gulp good for you, but it's mostly unnecessary.
Thanks for the thoughtful comments! I think I should clarify something, though - I was not arguing for using npm scripts over task runners. I was only discussing a DIY solution for watching file changes if you're already using npm scripts, which are slowly displacing task runners according to surveys.
Since you bring it up, though, I think it's worth noting that 1) You generally shouldn't be actually writing build commands in your package.json (which leads to the && problem), you should just be executing .js or .sh files, and 2) those files can contain as much declarative or procedural logic as you want, including the full power of node, and the freedom to require and chain js plugins just like you would in a gulpfile. I tend to use shell scripts because they're more compact and sometimes faster, which is why I brought up CLIs - but you can always just run a js file with node and require whatever js modules you want.
And to your last point, the reason I (personally) try to avoid dependencies is not because of bloat, it's because dependencies are points of failure. When maintaining a large project over the course of years, you constantly have to watch for new versions of your dependencies. More than once I've been thrown into panic mode at work because a minor patch to a dev dependency caused a build break that started blocking a business-critical bug.
Luckily, Yarn's deterministic installs have solved that surprise bug issue for me, but dependencies still cause me the extra work of keeping up with releases.
The important thing, though, is that we're all productive and enjoying our stacks. Build your code the way you like to!!!
I see your point. Thankfully, as you mentioned, Yarn solved quite a bit of problems with depenencies - that's why I started using it in production right after a short testing period.
Dependencies - even dev ones - still have to be updated, but in my experience Gulp has never been a problem. On the plus side, I have a simple and standardized way to define and run tasks, with hooks for errors and a simplified help page. Teammates have little problem understanding Gulp tasks, rather than inspecting a custom made script: that would be my main concern about the "npm script" approach.
Gulp works well in my general development workflow - which involves watchers for the most part (that start other tasks that finish in a blink), and a couple of less used tasks for which I can afford to wait a couple of seconds more.
But I guess in the end, one should use what's more comfortable for them.
Happy new year!