gulpfile.js: rev.manifest() not merging several JS tasks - gulp

The code bellow doesn't merge correctly rev-manifest.json file.
I loop several JS tasks and just one is merged, although hash files are being created and stored correctly.
I already tried a ton of things, I checked gulp-rev and some users seam to have similar problems. Some of them are creating several manifest files and proceed with the actual merge at the end. I would like to discard this solutions since it's slow and ugly.
If I comment the concat(...) line the manifest file registers all the JS tasks.
Is this a BUG or am I missing something here?
gulp 3.9.1
gulp-concat 2.6.0
gulp-rev 7.0.0
var gulp = require('gulp');
var less = require('gulp-less');
var minifycss = require('gulp-minify-css');
var jshint = require('gulp-jshint');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var rev = require('gulp-rev');
var jsFiles = {
task1: [
'./path/file1.js'
],
task2: [
'./path/file2.js',
'./path/file2.js'
]
};
function jsTask(key) {
gulp.task(key, function() {
gulp.src(jsFiles[key])
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(uglify())
// IT WORKS WHEN I COMMENT THIS LINE
.pipe(concat(key + '.min.js'))
.pipe(rev())
.pipe(gulp.dest('./public/js'))
.pipe(rev.manifest({merge:true }))
.pipe(gulp.dest('.'));
});
}
gulp.task('less', function() {
return gulp.src(['./path/less/*.less'])
.pipe(less({errLogToConsole: true}))
.pipe(minifycss())
.pipe(rev())
.pipe(gulp.dest('./path/public/css'))
.pipe(rev.manifest({merge:true }))
.pipe(gulp.dest('.'));
});
for (var key in jsFiles) {
jsTask(key);
}
var defaultTasks = ['less'];
for (var key in jsFiles) {
defaultTasks.push(key);
}
gulp.task('default', defaultTasks);

You can pass the name of the manifest file you want to create(different for each gulp task) to manifest function of the gulp-rev-all module like below
gulp.task('productionizeCss', function () {
return gulp
.src(['dist/prod/**/*.css'])
.pipe(revAll.revision({
fileNameManifest: 'css-manifest.json'
}))
.pipe(gulp.dest('dist/prod/'))
.pipe(revAll.manifestFile())
.pipe(gulp.dest('dist/prod/'));
});
gulp.task('productionizeJS', function () {
return gulp
.src(['dist/prod/**/*.js'])
.pipe(revAll.revision({
fileNameManifest: 'js-manifest.json'
}))
.pipe(gulp.dest('dist/prod/'))
.pipe(revAll.manifestFile())
.pipe(gulp.dest('dist/prod/'));
});
Here, I have two gulp tasks, one to revise all JS and one for CSS.So, I have created two manifest files css-manifest.json, js-manifest.json.
Then I specified both the manifest files in src of the rev-replace module as shown below:
gulp.task('revReplaceIndexHtml', function () {
var manifest = gulp.src(["dist/prod/js-manifest.json", 'dist/prod/css-manifest.json']);
return gulp.src('dist/dev/referralswebui/index.html')
.pipe(revReplace({ manifest: manifest, replaceInExtensions: ['.html']}))
.pipe(gulp.dest('dist/prod/referralswebui/'));
});

I would suggest using gulp-useref instead of gulp-concat.
Given your setup, I think key references a glob path, or at least I hope so. Otherwise you are trying to concatenate a single file, or no files which may crash the concat plug-in. Emphasis on may.
Also, since you are using gulp-rev, I suggest using gulp-rev-replace which will automatically update your index references to the reved files.
Edit
Sometimes rev.manifest behaves in ways that I would describe as buggy. Just to exhaust all possibilities remove the merge option for the manifest and run concat. Or run concat and remove manifest altogether.

Related

Gulp task executed by watch using cached config stream

I'm trying use gulp to bundle and minify my files using gulp-bundle-assets. Running the tasks on their own is fine. My problem is using gulp.watch to watch for any changes in my config file and re-bundle my scripts.
The first time the watch executes everything works correctly. On successive occasions everything runs, but the exact same files are bundled - any changes in the config are ignored.
If I run my "bundle" task while the watch is running, "bundle" will use the current configuration. While successive watches will continue to use the configuration on the first execution.
My guess would be the data for the stream retrieved by gulp.src is cached. So how do I tell it to always get the latest version?
var gulp = require('gulp');
var bundle = require('gulp-bundle-assets');
var del = require('del');
var index = 0;
gulp.task('bundle', function () {
console.log('Bundling files ' + (index++));
return gulp.src('./bundle.config.js')
.pipe(bundle())
.pipe(gulp.dest('./bundles'));
});
gulp.task('watch', function () {
gulp.watch(['./scripts/**/*.{js,css}', './bundle.config.js'], ['clean', 'bundle']);
});
gulp.task('clean', function (cb) {
console.log('Cleaning files');
del(['./bundles/**/*'], cb);
});
An alternative I tried was to use watch(...).on, and calling gulp.run, but that didn't fix the problem, either. I also tried pasting the code from the bundle task in to the on callback, but still got the same result.
The culprit isn't gulp.src(), but bundle(). The gulp-bundle-assets plugin uses require() to load your bundle.config.js. Since Node.js caches return values from require() you always get the same config object after the file is loaded for the first time.
The solution is to invalidate the require cache in your bundle task:
var gulp = require('gulp');
var bundle = require('gulp-bundle-assets');
var del = require('del');
var index = 0;
gulp.task('bundle', ['clean'], function () { // run clean task before bundle task
// invalidate require cache for ./bundle.config.js
delete require.cache[require.resolve('./bundle.config.js')];
console.log('Bundling files ' + (index++));
return gulp.src('./bundle.config.js')
.pipe(bundle())
.pipe(gulp.dest('./bundles'));
});
gulp.task('watch', function () {
gulp.watch(['./scripts/**/*.{js,css}',
'./bundle.config.js'], ['bundle']); // only run bundle task
});
gulp.task('clean', function () {
console.log('Cleaning files');
return del(['./bundles/**/*']); // return promise object
});
Unrelated to your problem, but I also fixed your clean task. The way you had it set up didn't work.

gulp-assemble & gulp-watch not recompiling site when changes are made to data, includes or layouts

I'm having issues using gulp-assemble with gulp-watch. I want gulp to watch the entire assemble source directory (data, includes, layouts and pages) and recompile the site when ever a file changes.
I'm able to get this working correctly for pages, but gulp is not recompiling the site when changes are made to the data, includes or layouts files.
I've added a watch task to the example gulpfile.js in the gulp-assemble repository:
var gulp = require('gulp');
var htmlmin = require('gulp-htmlmin');
var extname = require('gulp-extname');
var assemble = require('assemble');
var middleware = require('./examples/middleware');
var gulpAssemble = require('./');
// setup items on the assemble object
assemble.data({site: {title: 'Blog'}});
assemble.data(['test/fixtures/data/*.{json,yml}']);
assemble.layouts(['test/fixtures/layouts/*.hbs']);
assemble.partials(['test/fixtures/includes/*.hbs']);
// arbitrary middleware that runs when files loaded
assemble.onLoad(/index\.hbs/, middleware(assemble));
// render templates in `test/fixtures`
gulp.task('default', function () {
gulp.src('test/fixtures/pages/*.hbs')
.pipe(gulpAssemble(assemble, { layout: 'default' }))
.pipe(htmlmin({collapseWhitespace: true}))
.pipe(extname())
.pipe(gulp.dest('_gh_pages/'));
});
// ============================================================
// my watch task
// ============================================================
gulp.task('watch', ['default'], function() {
gulp.watch('test/fixtures/**/*.{hbs,yml,json}', ['default']);
});
If I run gulp watch and save a change to any of the .hbs files in the pages directory, I see gulp trigger the default in my terminal output, and I see the .html file in _gh_pages update with the change.
However, if I save a change to any of the .hbs, .json, or .yml files in the data, includes or layouts directories, I see gulp trigger the default in my terminal output, but I see no changes to the _gh_pages .html file(s). I have to run the gulp default task manually in order to get the changes applied to the _gh_pages files.
What do I need to change in order to get the desired behaviour?
gulp-watch will only execute code inside the function for the default task, so to get things like data and layouts to reload, you'll need to move those pieces of code to inside the function (Just before gulp.src).
var gulp = require('gulp');
var htmlmin = require('gulp-htmlmin');
var extname = require('gulp-extname');
var assemble = require('assemble');
var middleware = require('./examples/middleware');
var gulpAssemble = require('./');
// arbitrary middleware that runs when files loaded
assemble.onLoad(/index\.hbs/, middleware(assemble));
// render templates in `test/fixtures`
gulp.task('default', function () {
// setup items on the assemble object
assemble.data({site: {title: 'Blog'}});
assemble.data(['test/fixtures/data/*.{json,yml}']);
assemble.layouts(['test/fixtures/layouts/*.hbs']);
assemble.partials(['test/fixtures/includes/*.hbs']);
gulp.src('test/fixtures/pages/*.hbs')
.pipe(gulpAssemble(assemble, { layout: 'default' }))
.pipe(htmlmin({collapseWhitespace: true}))
.pipe(extname())
.pipe(gulp.dest('_gh_pages/'));
});
// ============================================================
// my watch task
// ============================================================
gulp.task('watch', ['default'], function() {
gulp.watch('test/fixtures/**/*.{hbs,yml,json}', ['default']);
});

How to make gulp remove deleted files while watching on a particular glob pattern?

I have a gulp watch task over a glob, looking for changes and updating an output folder. It is successfully able to updated changed files, add new files but it fails to remove deleted files.
The callback looks like this:
var cb = function (event) {
console.log('Moving assets...');
return gulp.src('app/assets/**/*', {base: 'app'})
.pipe(changed('build/assets'))
.pipe(gulp.dest('build'));
};
The gulp watch task is this:
gulp.watch('app/assets/**/*', cb);
I know that the gulp watch is running fine because the callback receives all the deleted events. But the callback itself is unable to remove the deleted file from the build/assets/ folder.
Do I have to explicitly handle the deleted event or am I missing something out?
The question is old, but I think it's still relevant.
Here is the solution I came up with, based on ondaplana answer in this github issue and the documentation of the gulp modules that are used:
Basically, it uses gulp-watch instead of gulp native watch function, to pipe gulp-filter and del modules.
var filter = require('gulp-filter');
var vinylPaths = require('vinyl-paths');
var del = require('del');
var watch = require('gulp-watch');
var notDeletedFilter = filter(
function(file) {
return file.event !== 'unlink' && file.event !== 'unlinkDir';
},
{restore: true}
);
notDeletedFilter.restore
.pipe(gulp.dest('dist'))
.pipe(vinylPaths(del));
//use gulp-watch instead of gulp native watch function
watch(['app/assets/**/*'], {events: ['add', 'change', 'unlink', 'unlinkDir']})
.pipe(notDeletedFilter)
.pipe(anyModule())
.pipe(gulp.dest('build'));
Documentation :
Gulp recipes

Browserify only if lint passes in Gulp

I'm trying to achieve this Gulp stream:
It seems like a fairly straight-forward process, but from what I can tell, it is not possible to implement as a Gulp stream.
I'm currently doing this:
gulp.task('js', function () {
return browserify('foo/main.js')
.bundle()
.pipe(source('bundle.js'))
.pipe(streamify(jshint()))
.pipe(jshint.reporter('default'))
// source map, minify, …
});
The problem is that JSHint should run first, only on the changed file, and the process should be aborted if the lint fails. In my setup, Browserify always runs, and only then JSHint runs on the entire bundle. I can deal with the performance penalty, but the JSHint's line numbers correspond to the generated bundle, and not my JS source files, which is a pain.
This is a cool idea. I've implemented this into my pipeline using watchify, which will lint files using the default reporter, and use the fail reporter if the file changed didn't pass the lint test. Even though this is recommended in the question, personally I would avoid doing this as what you really want is just for your reporter to emit lint checks, whilst keeping the development watcher still spawned in the background. Otherwise you have to keep restarting the task, which would generally tend to bug me. Anyway, here's the code:
'use strict';
var assign = require('object-assign'),
gulp = require('gulp'),
gutil = require('gulp-util'),
merge = require('merge-stream'),
jshint = require('gulp-jshint'),
source = require('vinyl-source-stream'),
watchify = require('watchify'),
browserify = require('browserify');
var resources = {
mainJS : 'main.js',
bundleJS : 'bundle.js',
root : 'www'
};
function res(r) {
return './' + resources[r];
}
gulp.task('watch', function() {
var bundler = watchify(browserify(res('mainJS'), assign(watchify.args, {
fullPaths: false
})));
var scripts = function(changedFiles) {
var compileStream = bundler
.bundle()
.on('error', gutil.log.bind(gutil, gutil.colors.red('Browserify Error\n')))
.pipe(source(res('bundleJS')))
.pipe(gulp.dest(res('root')));
if (changedFiles) {
var lintStream = gulp.src(changedFiles)
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(jshint.reporter('fail'));
return merge(lintStream, compileStream);
}
return compileStream;
};
bundler.on('update', scripts);
return scripts();
});
Note that this is based heavily off the official recipe for fast browserify builds with watchify (https://github.com/gulpjs/gulp/blob/master/docs/recipes/fast-browserify-builds-with-watchify.md), and is an 'all-in-one' type task; that is to say that I will generally spawn a single task somewhere off in the background, with minimal logging (I run gulp with the --silent flag), which is personally easier to deal with :-)

How do I replace the filenames listed in index.html with the output of gulp-rev?

I'm using gulp-rev to build static files that I can set to never expire. I'd like to replace all references to the generated files in index.html to these renamed files, but I can't seem to find anything that does that like Grunt with usemin.
As far as I can tell right now, I have some options.
Use gulp-usemin2, which depends on gulp-rev. When I go to search Gulp plugins, it says that gulp-usemin2 does too much so I should use gulp-useref instead, but I can't configure gulp-ref to use gulp-rev's output.
Write my own plugin the replace the blocks (scripts & styles) in index.html (and in the CSS) with the generated files.
Any ideas? I don't see why this little use case should be the only thing in my way to replacing Grunt.
Rather than trying to solve this problem multiple gulp steps (which gulp-rev seems to want you to do), I've forked gulp-rev to gulp-rev-all to solve this usecase in one gulp plugin.
For my personal usecase I wanted to rev absolutely everything but as someone else raised an feature request, there should be the ability to exclude certain files like index.html. This will be implemented soon.
I've just written a gulp plugin to do this, it works especially well with gulp-rev and gulp-useref.
The usage will depend on how you've set things up, but it should look something like:
gulp.task("index", function() {
var jsFilter = filter("**/*.js");
var cssFilter = filter("**/*.css");
return gulp.src("src/index.html")
.pipe(useref.assets())
.pipe(jsFilter)
.pipe(uglify()) // Process your javascripts
.pipe(jsFilter.restore())
.pipe(cssFilter)
.pipe(csso()) // Process your CSS
.pipe(cssFilter.restore())
.pipe(rev()) // Rename *only* the concatenated files
.pipe(useref.restore())
.pipe(useref())
.pipe(revReplace()) // Substitute in new filenames
.pipe(gulp.dest('public'));
});
I have confronted the same problem, I tried gulp-rev-all, but it has some path problem, not very free to use.
So I figure out an solution, use gulp-rev and gulp-replace:
At first I have a replace symbol in my html(js, css) files
<link rel="stylesheet" href="{{{css/common.css}}}" />
<script src="{{{js/lib/jquery.js}}}"></script>
in css files
background: url({{{img/logo.png}}})
Second after some compile task, use gulp-replace to replace all the static files reference:
take stylus compile in development as example:
gulp.task('dev-stylus', function() {
return gulp.src(['./fe/css/**/*.styl', '!./fe/css/**/_*.styl'])
.pipe(stylus({
use: nib()
}))
.pipe(replace(/\{\{\{(\S*)\}\}\}/g, '/static/build/$1'))
.pipe(gulp.dest('./static/build/css'))
.pipe(refresh());
});
In production environment, use gulp-rev to generate rev-manifest.json
gulp.task('release-build', ['release-stylus', 'release-js', 'release-img'], function() {
return gulp.src(['./static/build/**/*.css',
'./static/build/**/*.js',
'./static/build/**/*.png',
'./static/build/**/*.gif',
'./static/build/**/*.jpg'],
{base: './static/build'})
.pipe(gulp.dest('./static/tmp'))
.pipe(rev())
.pipe(gulp.dest('./static/tmp'))
.pipe(rev.manifest())
.pipe(gulp.dest('./static'));
});
Then use gulp-replace to replace the refs in static files with rev-manifest.json:
gulp.task('css-js-replace', ['img-replace'], function() {
return gulp.src(['./static/tmp/**/*.css', './static/tmp/**/*.js'])
.pipe(replace(/\{\{\{(\S*)\}\}\}/g, function(match, p1) {
var manifest = require('./static/rev-manifest.json');
return '/static/dist/'+manifest[p1]
}))
.pipe(gulp.dest('./static/dist'));
});
This helped me gulp-html-replace.
<!-- build:js -->
<script src="js/player.js"></script>
<script src="js/monster.js"></script>
<script src="js/world.js"></script>
<!-- endbuild -->
var gulp = require('gulp');
var htmlreplace = require('gulp-html-replace');
gulp.task('default', function() {
gulp.src('index.html')
.pipe(htmlreplace({
'css': 'styles.min.css',
'js': 'js/bundle.min.js'
}))
.pipe(gulp.dest('build/'));
});
You could do it with gulp-useref like this.
var gulp = require('gulp'),
useref = require('gulp-useref'),
filter = require('gulp-filter'),
uglify = require('gulp-uglify'),
minifyCss = require('gulp-minify-css'),
rev = require('gulp-rev');
gulp.task('html', function () {
var jsFilter = filter('**/*.js');
var cssFilter = filter('**/*.css');
return gulp.src('app/*.html')
.pipe(useref.assets())
.pipe(jsFilter)
.pipe(uglify())
.pipe(rev())
.pipe(jsFilter.restore())
.pipe(cssFilter)
.pipe(minifyCss())
.pipe(rev())
.pipe(cssFilter.restore())
.pipe(useref.restore())
.pipe(useref())
.pipe(gulp.dest('dist'));
});
or you could even do it this way:
gulp.task('html', function () {
var jsFilter = filter('**/*.js');
var cssFilter = filter('**/*.css');
return gulp.src('app/*.html')
.pipe(useref.assets())
.pipe(rev())
.pipe(jsFilter)
.pipe(uglify())
.pipe(jsFilter.restore())
.pipe(cssFilter)
.pipe(minifyCss())
.pipe(cssFilter.restore())
.pipe(useref.restore())
.pipe(useref())
.pipe(gulp.dest('dist'));
});
The problem is updating the asset paths in the html with the new rev file paths. gulp-useref doesn't do that.