Yeoman: How to install dependencies sequentially - generator

In my generator I want to run npm i and jspm i sequentially so that the log output won't mixed together. How do I do that?
Currently, if I put them together:
install: function() {
this.npmInstall();
this.spawnCommand('jspm', ['install']);
}
or
install: {
npm: function() { this.npmInstall(); },
jspm: function() { this.spawnCommand('jspm', ['install']); }
}
the will be run at the same time.
I'm aware that I can put jspm i in the end queue, but I want to use it for post-install code and it has the same problem (i.e. all codes in end queue are run in parallel).

Yeoman is only Node.js and JavaScript. You'll handle this in the same way you'd handle any asynchronous action.
In Yeoman, you use this.async() to define an asynchronous task:
install: {
npm: function() {
this.npmInstall();
},
jspm: function() {
this.spawnCommand('jspm', ['install']).on('close', this.async());
}
}
Note you can also use this.spawnCommandSync

Related

Gulp Fix "gulp.run() has been deprecated" for Server Livereload

I'm new to Gulp and I found a Gulpfile.js example I wanted to use to livereload my express app's server whenever a change takes place in either my app.js file or ./public directory. Here is the Gulpfile.js code:
var gulp = require('gulp'),
spawn = require('child_process').spawn,
node;
/**
* $ gulp server
* description: Launch the server. If there's a server already running, kill it.
*/
gulp.task('server', function() {
if (node) node.kill()
node = spawn('node', ['app.js'], {stdio: 'inherit'})
node.on('close', function (code) {
if (code === 8) {
gulp.log('Error detected, waiting for changes...');
}
});
})
/**
* $ gulp default
* description: Start the development environment
*/
gulp.task('default', function() {
gulp.run('server')
gulp.watch(['./app.js', './public/'], function() {
gulp.run('server')
})
})
// clean up if an error goes unhandled.
process.on('exit', function() {
if (node) node.kill()
})
In my terminal window I keep getting the following warning:
gulp.run() has been deprecated. Use task dependencies or gulp.watch task triggering instead.
Gulp is working and it is livereloading the web application like I want it to but I'd like to fix this issue to future proof my development process, as well as get rid of this annoying warning message.
Thanks for the help!
One option would be to simply replace all occurrences of gulp.run() with gulp.start():
gulp.task('default', function() {
gulp.start('server');
gulp.watch(['./app.js', './public/'], function() {
gulp.start('server');
});
});
However calling a task explicitly using gulp.start() is not the idiomatic way of doing things in gulp (although sometimes it's necessary).
The warning message you receive already hints at the idiomatic way of solving this:
Use task dependencies or gulp.watch task triggering
Task dependencies allow you to run a task before another task. That means you can get rid of the first gulp.run().
Task triggering in gulp.watch() allows you to run a task when a file changes. That means you can get rid of the second gulp.run().
Therefore your default task ends up looking like this:
gulp.task('default', ['server'], function() {
gulp.watch(['./app.js', './public/'], ['server']);
});

Gulp.js. Same task on watch, with different parallel tasks

I use gulp 4.0. And I have, this 'watch' task:
gulp.task("watch", function() {
gulp.watch("scss/*.scss", gulp.series("sass")).on("unlink", function(filepath) {
remember.forget("sass", path.resolve(filepath));
delete cached.caches.sass[path.resolve(filepath)];
});
gulp.watch("templates/**/*.jade", gulp.series("jade")).on("unlink", function(filepath) {
remember.forget("jade", path.resolve(filepath));
delete cached.caches.jade[path.resolve(filepath)];
});
});
So, I have same two lines:
remember.forget("jade", path.resolve(filepath));
delete cached.caches.jade[path.resolve(filepath)];
If it was a pipelines, it would be easy to create new task, and then run them. But here, I have a argument (parameter) - filepath.
So, the question is: How i can replace it with one task? With no repeat of these two lines.
So, the question is: How i can replace it with one task?
You can't. Tasks cannot take arguments. Your only option is to create a function:
function runTask(taskName) {
return function(evt, filepath) {
if (evt === "unlink") {
remember.forget(taskName, path.resolve(filepath));
delete cached.caches[taskName][path.resolve(filepath)];
}
gulp.series(taskName)();
};
}
gulp.task("watch", function() {
gulp.watch("scss/*.scss").on("all", runTask("sass"));
gulp.watch("templates/**/*.jade").on("all", runTask("jade"));
});
Note that the above code presumes that you want to clear the sass and jade caches before running the sass and jade tasks. If it's the other way around you'll have to adjust it accordingly.

Infinite watch loop with gulp on auto-updated / auto-generated files

I am attempting to use some gulp plugins ( jscs, csscomb ) to style my code on the fly during dev time.
I'm having a problem with the gulp process running an infinite loop with the format task.
What's I believe to be happening:
start a serve task of some kind
an initial run is performed with all tasks to prep files for the staging server
a local staging server is started in parallel with a watch task
myfile.scss is updated by a developer
the gulp watcher starts the csscomb task
csscomb plugin changes the file and replaces it
the watcher task sees the change from the file replacement & starts the format task again...
the csscomb plugin runs again and so on ...
Here is a snippet that causes this loop. (Note: this uses v4 of gulp)
'use strict'
import { task, parallel, series, src, dest, watch, plugins } from './gulp';
import { startStagingServer } from './servers';
import { solution } from './solution.map';
const path = require('path');
task('serve', parallel(startStagingServer, watchStyles);
function watchStyles() {
watch([ solution.src.styles ], series(formatStyles, compileStyles))
}
function formatStyles(done) {
return src([ solution.src.styles ])
.pipe(plugins.csscomb())
.pipe(dest(solution.src.mount)) // the root of the solution
}
function compileStyles() {
return src([ solution.src.styles ])
.pipe(plugins.sass().on('error', plug.sass.logError))
.pipe(dest(path.join(solution.dest.stage, 'serve')));
}
Does anyone know a way to avoid this?
The way to avoid this is not to put the fix in the watcher. Use 2 separate functions: one that fixes and the other that doesn't. Only watch the one that doesn't. Example:
function taskJscsFix() {
return gulp.src(path.JS)
.pipe(jscs({
configPath: './gulp/.jscsrc',
fix: true
}))
.pipe(gulp.dest(path.SRC.JS));
}
function taskScripts() {
return gulp.src(path.JS)
.pipe(jscs({
configPath: './gulp/.jscsrc'
}))
.pipe(jscs.reporter())
.pipe(gulp.dest(path.DEST.JS));
}

how do I run a gulp task from two or more other tasks and pass the pipe through

This must be obvious but I can't find it. I want to preprocess my stylus/coffee files with a watcher in the dev environment and in production with a build task (isn't that common to all of us?) and also run a few more minification and uglification steps in production but I want to share the pipe steps common to both dev and production for DRY
The problem is that when I run the task which watches the files, the task which preprocesses does that to all the files since it has its own gulp.src statement which includes all stylus files.
How do I avoid compiling all files on watching while still keeping the compile task separate. Thanks
paths = {
jade: ['www/**/*.jade']
};
gulp.task('jade', function() {
return gulp.src(paths.jade).pipe(jade({
pretty: true
})).pipe(gulp.dest('www/')).pipe(browserSync.stream());
});
gulp.task('serve', ['jade', 'coffee'], function() {
browserSync.init({
server: './www'
});
watch(paths.jade, function() {
return gulp.start(['jade']);
});
return gulp.watch('www/**/*.coffee', ['coffee']);
});
One important thing in Gulp is not to duplicate pipelines. If you want to process your stylus files, it has to be the one and only stylus pipe. If you want to execute different steps in your pipe however, you have multiple choices. One that I would suggest would be a noop() function in conjunction with a selection function:
var through = require('through2'); // Gulp's stream engine
/** creates an empty pipeline step **/
function noop() {
return through.obj();
}
/** the isProd variable denotes if we are in
production mode. If so, we execute the task.
If not, we pass it through an empty step
**/
function prod(task) {
if(isProd) {
return task;
} else {
return noop();
}
}
gulp.task('stylus', function() {
return gulp.src(path.styles)
.pipe(stylus())
.pipe(prod(minifyCss())) // We just minify in production mode
.pipe(gulp.dest(path.whatever))
})
As for the incremental builds (building just the changed files with every iteration), the best way would be to get on the gulp-cached plugin:
var cached = require('gulp-cached');
gulp.task('stylus', function() {
return gulp.src(path.styles)
.pipe(cached('styles')) // we just pass through the files that have changed
.pipe(stylus())
.pipe(prod(minifyCss()))
.pipe(gulp.dest(path.whatever))
})
This plugin will check if the contents have changed with each iteration you have done.
I spend a whole chapter on Gulp for different environments in my book, and I found those to be the most suitable ones. For more information on incremental builds, you can also check on my article on that (includes Gulp4): http://fettblog.eu/gulp-4-incremental-builds/

I cant configure my grunt file for haml

dose any one know how I can configure my grunt file for haml?
I have this now:
haml: {
dist: {
files: {
'index.html': 'index.haml'
}
}
}
I've also tried `
haml: {
dist: {
files: {
['index.html']: 'index.haml'
}
}
}
both along with
grunt.loadNpmTasks('grunt-contrib-haml');
I've been able to get compass running but not haml. I tried the config.rb file as well.
I'd imagine you did, but are you registering the task at the end of your Gruntfile.js file? Also, what error messages (if any) are you getting when you run 'grunt haml -v' from the command line?
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
haml: {
dist: {
files: {
'index.html':'index.haml'
}
}
});
grunt.loadNpmTasks('grunt-contrib-haml');
grunt.registerTask('default','['haml']);
^^^^ this last bit here, is it in your Gruntfile? You should have something similar for Compass to run.
This package always gives me some grief when I install it, for whatever reason.