Change stream file names on the go in gulp-watch task - gulp

Even though it is not that necessary I want to have my dev-environment as clean as possible and therefore automatically remove deleted files from my build directory.
Since I'm using TypeScript I want to have the compiled and static files in one directory on the fly. I'm achieving this with watching static files and copying them to a build folder (I probably should rename that in the future).
Deleted files should then also be removed from the build directory. I tried this and almost succeeded. The only thing I'm trying to find out is how to change a stream file name from app/tmp.html to build/app/tmp.html.
This is my watch-task so far:
let gulp = require( 'gulp' );
let watch = require( 'gulp-watch' );
let filter = require( 'gulp-filter' );
let clean = require( 'gulp-clean' );
gulp.task( 'watch', function() {
let deletedFilter = filter( file => {
return file.event !== 'unlink' && file.event !== 'deleted';
}, { restore: true } );
let newFilter = filter( file => {
return file.event !== 'add';
} );
watch( './app/**/*.{html,css,js,map,svg,png,jpg}' )
.pipe( deletedFilter )
.pipe( gulp.dest( './build/app/' ) )
.pipe( newFilter )
.pipe( deletedFilter.restore ) // this line here
.pipe( clean() ); // and that line there still make
// some trouble
} );
Thank you so much for any help!

Okay, I was taking a little break and dug into a little deeper. Looking at gulp-debug I came up with a solution, using the following, additional node modules to gulp and gulp-watch:
gulp-filter to filter out deleted files in the first place
through2 to go through all filtered (deleted) files
path to get the relative path
gulp-clean to actually remove the files from the build directory
All together it looks something like this (as of writing this answer, I'm using NodeJS 5.10.1):
'use strict';
let staticFilePattern = `./app/**/*.{html,css,js,map,svg,png,jpg}`;
let buildDirectory = 'build';
let gulp = require( 'gulp' );
let watch = require( 'gulp-watch' );
let filter = require( 'gulp-filter' );
let clean = require( 'gulp-clean' );
let through = require( 'through2' );
let path = require( 'path' );
let changeToBuildDirectory = function() {
return through.obj( function( file, enc, cb ) {
file.path = process.cwd() + `/${buildDirectory}/` + path.relative( process.cwd(), file.path );
cb( null, file );
});
};
gulp.task( 'watch', function() {
let deletedFilter = filter( file => {
return file.event !== 'unlink' && file.event !== 'deleted';
}, { restore: true } );
let newFilter = filter( file => {
return file.event !== 'add';
} );
watch( staticFilePattern )
.pipe( deletedFilter )
.pipe( gulp.dest( `./${buildDirectory}/app/` ) )
.pipe( newFilter )
.pipe( debug( { title: 'Foo' } ) )
.pipe( deletedFilter.restore )
.pipe( changeToBuildDirectory() )
.pipe( clean() );
} );
I don't find it very clean, since I'm just modifying the path on the file object, but it works, so I'm pleased. If you got a more clean solution, you are welcome to post another answer or leave it in the comments
I hope it is useful to some extend.
Cheers!

Related

How to create directory with name given by a prompt question with gulp

I would like to run a gulpfile.js task which asks in prompt the directory name to create it inside the build folder.
Structure
gulfile.js
build/
foo/ <-- directory name given by a question
gulpfile task
gulp.task( 'questions', function( callback ) {
return gulp.src('build')
.pipe( prompt.prompt({
type: 'input',
name: 'dir_name',
message: 'What is directory name ?'
}, function( res ){
//console.log(res.dir_name);
//make directory called res.dir_name in build/
}))
.pipe(gulp.dest('build'));
});
How can I do this ?
I found a solution thanks gulp-prompt package.
This example copy content base folder in build folder.
const prompt = require('gulp-prompt');
var my_dirname, project_build_path ;
gulp.task( 'questions', function( callback ) {
return gulp.src('./base/**/*')
.pipe( prompt.prompt({
type: 'input',
name: 'dir_name',
message: 'What is directory name ?'
}, function( res ){
my_dirname = res.dir_name;
project_build_path = 'build/' + my_dirname;
gulp.src( './base/**/*' ).pipe( gulp.dest( project_build_path ) );
}));
});

gulp add folder in zip archive

gulp.task( 'zip', function () {
return gulp.src( './dist/**' )
.pipe(zip( 'dist.zip' ))
.pipe(gulp.dest( './' ));
});
I have next structure
dist.zip
all-files
How do I make the following structure in the archive?
dist.zip
dist
all-files
Your code is fine except for the gulp.dest which takes a string (or a function):
gulp.task( 'zip', function () {
return gulp.src( './dist/**' )
.pipe(zip( 'dist.zip' ))
// .pipe(gulp.dest( ./ )); your code, note the apostrophes below
.pipe(gulp.dest( './' ));
});

Gulp deleting CSS in html file

I have a HTML file with all the scripts and stylesheets that I use in my Web App. When I add a new, custom CSS, and I run gulp, it automatically deletes that new line from the HTML file. My web application is an angular app.
<!-- MATERILIZE CORE CSS-->
<link href="../../common/vendors/Materialize/dist/css/materialize.css" rel="stylesheet"/>
<!-- MAIN STYLE -->
<link href="views/modules/main/min/custom-min.css" rel="stylesheet"/>
<!-- END MAIN STYLE -->
UPDATE 1
this is my gulpfile
( function () {
'use strict';
var //Required
args = require( 'yargs' ).argv,
spawn = require( 'child_process' ).spawn,
cssmin = require( 'gulp-cssnano' ),
concat = require( 'gulp-concat' ),
del = require( 'del' ),
echo = require( 'cli-color' ),
gulp = require( 'gulp' ),
gulpif = require( 'gulp-if' ),
linker = require( 'gulp-linker' ),
ngAnnotate = require( 'gulp-ng-annotate' ),
rename = require( 'gulp-rename' ),
runSequence = require( 'run-sequence' ).use( gulp ),
sass = require( 'gulp-ruby-sass' ),
sourcemaps = require( 'gulp-sourcemaps' ),
uglify = require( 'gulp-uglify' ),
shell = require( 'gulp-shell' ),
node,
// Client FOLDERS
client = {
ROOT: 'web/client/',
SRC_SCSS: 'web/client/source/sass',
EXPORT_CSS: 'web/client/public/css',
SRC_JS: 'web/client/source/js',
EXPORT_JS: 'web/client/public/js'
},
// Dashboard FOLDERS
dashboard = {
ROOT: 'web/dashboard/',
SRC_SCSS: 'web/dashboard/source/sass',
EXPORT_CSS: 'web/dashboard/static/css',
SRC_JS: 'web/dashboard/source/js',
EXPORT_JS: 'web/dashboard/static/js'
},
// Exported FILES
out = {
MINIFIEDCSS: 'app.min.css',
MINIFIEDJS: 'app.min.js'
};
/**
* $ gulp minifyJS --GLOBAL FUNCTION
* description: Concat and minified JS files into *.min.js
*/
gulp.task( 'minifyJS', function () {
return gulp.src( [ args.SRC_JS + '/**/module.js', args.SRC_JS + '/**/*.js' ] )
.pipe( sourcemaps.init() )
.pipe( concat( out.MINIFIEDJS ) )
.pipe( ngAnnotate() )
.pipe( uglify() )
.pipe( sourcemaps.write() )
.pipe( gulp.dest( args.EXPORT_JS ) );
} );
/**
* $ gulp linkJS --GLOBAL FUNCTION
* description: lin all js files to index.html client
*/
gulp.task( 'linkJS', function () {
return gulp.src( args.ROOT + args.FOLDER + 'index.html' )
.pipe( linker( {
scripts: [ ( args.EXPORT_JS + '/' + out.MINIFIEDJS ) ],
startTag: '<!-- APP -->',
endTag: '<!-- END APP -->',
fileTmpl: '<script src="%s"></script>',
appRoot: args.ROOT + args.FOLDER
} ) )
.pipe( gulp.dest( args.ROOT + args.FOLDER ) );
} );
/**
* $ gulp compileSASS --GLOBAL FUNCTION
* description: compile sass file into a CSS file
*/
gulp.task( 'compileSASS', function () {
return sass( args.SRC_SCSS + '/app.scss', {
sourcemap: true
} )
.on( 'error', function ( err ) {
console.error( 'Error!', err.message );
} )
.pipe( gulpif( args.production, sourcemaps.init() ) )
.pipe( gulpif( args.production, cssmin() ) )
.pipe( sourcemaps.write( {
includeContent: false,
sourceRoot: '/' + args.SRC_SCSS
} ) )
.pipe( gulpif( args.production, rename( {
suffix: '.min'
} ) ) )
.pipe( gulp.dest( args.EXPORT_CSS ) );
} );
/**
* $ gulp linkCSS --GLOBAL FUNCTION
* description: link to index.html client all sass files
*/
gulp.task( 'linkCSS', function () {
var isProduction = args.production;
return gulp.src( args.ROOT + args.FOLDER + '/index.html' )
.pipe( linker( {
scripts: isProduction ? [ ( args.EXPORT_CSS + '/' + out.MINIFIEDCSS ) ] : [ ( args.EXPORT_CSS + '/app.css' ) ], //jshint ignore: line
startTag: '<!-- MAIN STYLE -->',
endTag: '<!-- END MAIN STYLE -->',
fileTmpl: '<link href="%s" rel="stylesheet"/>',
appRoot: args.ROOT + args.FOLDER
} ) )
.pipe( gulp.dest( args.ROOT + '/' + args.FOLDER ) );
} );
/**
* $ gulp docs-api --GLOBAL FUNCTION
* description: genereate apidocs
*/
gulp.task( 'docs-api', shell.task( [ 'apidoc -i ./server/handlers -o docs/api/' ] ) );
/**
* $ gulp clean --GLOBAL FUNCTION
* description: clean client side css and js folder
*/
gulp.task( 'clean', function () {
var cleanALL = function () {
del.sync( [ './docs/**' ] );
del.sync( [ args.EXPORT_JS, args.EXPORT_CSS ] );
},
cleanONE = function ( folder ) {
del.sync( [ folder ] );
};
if ( !args.js && !args.css ) {
return cleanALL();
} else {
return args.js ? cleanONE( args.EXPORT_JS ) : cleanONE( args.EXPORT_CSS );
}
} );
/**
* $ 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', [ 'server/server.js' ], {
stdio: 'inherit'
} );
node.on( 'close', function ( code ) {
if ( code === 8 ) {
console.log( echo.redBright.bold( 'Error detected, waiting for changes...' ) );
}
} );
} );
/**
* $ gulp clientJS
* description: Compile all JS files for the Web Client component.
*/
gulp.task( 'clientJS', function ( callback ) {
args = {
js: 'js',
ROOT: client.ROOT,
SRC_JS: client.SRC_JS,
EXPORT_JS: client.EXPORT_JS,
FOLDER: 'public/'
};
runSequence(
'clean',
'minifyJS',
'linkJS',
callback
);
} );
/**
* $ gulp dashJS
* description: Compile all JS files for the Dashboard component.
*/
gulp.task( 'dashJS', function ( callback ) {
args = {
js: 'js',
ROOT: dashboard.ROOT,
SRC_JS: dashboard.SRC_JS,
EXPORT_JS: dashboard.EXPORT_JS,
FOLDER: 'static/'
};
runSequence(
'clean',
'minifyJS',
'linkJS',
callback
);
} );
/**
* $ gulp clientSCSS
* description: Compile all SCSS files for the Web Client component.
*/
gulp.task( 'clientSCSS', function ( callback ) {
args = {
css: 'css',
ROOT: client.ROOT,
SRC_SCSS: client.SRC_SCSS,
EXPORT_CSS: client.EXPORT_CSS,
FOLDER: 'public/'
};
runSequence(
'clean',
'compileSASS',
'linkCSS',
callback
);
} );
/**
* $ gulp dashSCSS
* description: Compile all SCSS files for the Dashboard component.
*/
gulp.task( 'dashSCSS', function ( callback ) {
args = {
css: 'css',
ROOT: dashboard.ROOT,
SRC_SCSS: dashboard.SRC_SCSS,
EXPORT_CSS: dashboard.EXPORT_CSS,
FOLDER: 'static/'
};
runSequence(
'clean',
'compileSASS',
'linkCSS',
callback
);
} );
/**
* $ gulp start
* description: Execute all sub-tasks and start the server,
* including the wathes (to listen for any changes)
*/
gulp.task( 'start', function () {
runSequence(
'clientJS',
'dashJS',
'clientSCSS',
'dashSCSS',
'server',
'watch'
);
} );
/**
* $ gulp watch
* description: watch for any changes and restart server if required
*/
gulp.task( 'watch', function () {
gulp.watch( [ 'server/index.js', './server/**/*.js', './server/**/*.json' ], function () {
runSequence(
'server'
);
} );
// Need to watch for sass changes too? Just add another watch call!
// no more messing around with grunt-concurrent or the like. Gulp is
// async by default.
gulp.watch( client.SRC_SCSS + '/**/*.scss', [ 'clientSCSS' ] );
gulp.watch( client.SRC_JS + '/**/*.js', [ 'clientJS' ] );
gulp.watch( dashboard.SRC_SCSS + '/**/*.scss', [ 'dashSCSS' ] );
gulp.watch( dashboard.SRC_JS + '/**/*.js', [ 'dashJS' ] );
} );
// Clean up if an error goes unhandled.
process.on( 'exit', function () {
if ( node ) {
node.kill();
}
} );
} )();
can you share your gulp code. Probably you might have written some gulp task which will dynamically create your index.html file. Whereever you have written task to add css files make your you have added correct path. May be which ever css files are missing are not in specified path.
gulp.task('inject:css', () => {
return gulp.src(paths.client.mainView)
.pipe(plugins.inject(
gulp.src(`${clientPath}/{app,components}/**/*.css`, {read: true})
.pipe(plugins.sort()),
{
starttag: '<!-- injector:css -->',
endtag: '<!-- endinjector -->',
transform: (filepath) => '<link rel="stylesheet" href="' + filepath.replace(`/${clientPath}/`, '').replace('/.tmp/', '') + '">'
}))
.pipe(gulp.dest(clientPath));
});
above task will include all css files from app,component
gulp.src(`${clientPath}/{app,components}/**/*.css`, {read: true})
If I add some css files outside those two folders. and add it to index manually. If i run gulp it will be removed
Hoping this will resolve your problem

Gulp 'watch' not saving files rendered with gulp-swig

I've used Gulp a number of times but this problem has me totally stumped. I have a render task to save an HTML template piped through gulp-swig. It works perfectly fine when invoked manually via gulp render but will not save when the task is triggered by gulp.watch. So, to clarify, the watcher does trigger the task but the rendered file doesn't actually get saved to its destination.
I've boiled the problem down to the following, removing all other tasks from my gulpfile, axed plumber, context data, etc. Any help appreciated!
var gulp = require( 'gulp' ),
browserSync = require( 'browser-sync' ).create(),
rename = require( 'gulp-rename' ),
swig = require( 'gulp-swig' ),
reload = browserSync.reload;
gulp.task( 'render', function() {
return gulp.src( './dev/template.html' )
.pipe( swig() )
.pipe( rename( 'index.html' ) )
.pipe( gulp.dest( './preview' ) )
.on( 'end', reload );
});
gulp.task( 'serve', function() {
browserSync.init( { server: './preview' } );
gulp.watch( './dev/*.html', [ 'render' ] );
});
gulp.task( 'default', [ 'serve' ] );
Duh, got it working. It appears that swig caches the template by default (?) so it was in fact saving the file but it was identical. I noticed a 'cache' option in another (unrelated) post about swig which did the trick. So, I needed to pass in an options object, like so:
.pipe( swig({
defaults: { cache: false }
}) )

Using Browserify with a revision manifest in Gulp, getting "Error: write after end"

I'm trying to compile a React app, append a hash to the output filename and produce a revision manifest, so that I can tell the browser to cache it forever. The problem is that the dozen or so tools involved don't all work together perfectly, at least as far as I can figure out by trying to assimilate all of their readmes and juggle .pipe calls.
Gulpfile: gist
Gulp task:
gulp.task( 'compile:js', function() {
var browserifyTransform = transform( function( filename ) {
return browserify( filename )
.transform( reactify )
.bundle();
});
return gulp.src( 'src/index.js' )
.pipe( browserifyTransform )
.pipe( sourcemaps.init({ loadMaps: true }))
.pipe( uglify() )
.pipe( rev() )
.pipe( gulp.dest( 'static/dist' ));
});
update Simplified version, same error:
gulp.task( 'compile:js', function() {
var browserifyTransform = transform( function( filename ) {
return browserify( filename )
.transform( reactify )
.bundle();
});
return gulp.src( 'src/index.js' )
.pipe( browserifyTransform )
.pipe( gulp.dest( 'static/dist' ));
});
Error stack:
[15:55:04] Using gulpfile ~/Projects/pixsplodr/gulpfile.js
[15:55:04] Starting 'compile:js'...
Error: write after end
at writeAfterEnd (/home/dan/Projects/pixsplodr/node_modules/browserify/node_modules/readable-stream/lib/_stream_writable.js:161:12)
at Labeled.Writable.write (/home/dan/Projects/pixsplodr/node_modules/browserify/node_modules/readable-stream/lib/_stream_writable.js:208:5)
at write (_stream_readable.js:601:24)
at flow (_stream_readable.js:610:7)
at _stream_readable.js:578:7
at process._tickCallback (node.js:419:13)
There are a few open bugs that result in this error (example: github.com/hughsk/vinyl-transform/issues/1). The problem with them is that when the original src stream ends, it ends the writable stream, which is still being used. Hence the error.
Try this instead.
gulp.task( 'compile:js', function() {
var browserifyTransform = transform( function( filename ) {
return browserify( filename )
.transform( reactify )
.bundle();
});
gulp.src( 'src/index.js' )
.pipe( browserifyTransform )
.pipe( sourcemaps.init({ loadMaps: true }))
.pipe( uglify() )
.pipe( rev() )
.pipe( gulp.dest( 'static/dist' ));
return gulp.src( '');
});
By returning a seperate gulp.src, gulp is forced to wait until the initial command is finished in order to return the new src.
I resolve this issue using gulp-streamify package.
I had to rewrite my task as follow:
gulp = require('gulp');
rev = require('gulp-rev'); // add hash to filename
rimraf = require('gulp-rimraf'); // delete folder
gulpsync = require('gulp-sync')(gulp); // sync gulp task
babel = require('gulp-babel'); // es6 transpiler
browserify = require('browserify');
source = require('vinyl-source-stream');
streamify = require('gulp-streamify');
gulp.task('compile-es6', function(){
var stream = browserify('app/assets/javascript/application.js')
.transform("babelify", {presets: ["es2015"]})
.bundle();
return stream.pipe(source('bundle.js'))
.pipe(streamify(rev()))
.pipe(gulp.dest('public/javascripts'))
.pipe(rev.manifest('./rev-manifest.json',{merge:true}))
.pipe(gulp.dest(''));
});
Well, I have solution that satisfies my requirements, but it isn't perfect.
Let Browserify start the stream from a file name, instead of using gulp.src
Use vinyl-source-stream to transform Browserify's Node stream to a Gulp stream, before passing the data on to other gulp plugins
I am also using gulp-rev to append a hash to generated filenames, and to create a manifest that maps them to their original filename.
I was having trouble with source maps earlier too, but I have found that using Browserify transforms and settings seems to work better than using Gulp plugins on Browserify's output. That might be entirely due to user error, but I have been seeing so many conflicting Browserify / Gulp examples and minimal examples that I was unable to extend in an intuitive way, that I am just glad to have a working build with all of the features that I wanted.
var gulp = require( 'gulp' );
var gutil = require( 'gulp-util' );
var watchify = require( 'watchify' );
var browserify = require( 'browserify' );
var source = require( 'vinyl-source-stream' );
var buffer = require( 'vinyl-buffer' );
var sass = require( 'gulp-sass' );
var _ = require( 'lodash' );
var rev = require( 'gulp-rev' );
// Dev build
gulp.task( 'watch', [ 'sass' ], function() {
gulp.watch( 'node_modules/quiz/style/**/*.scss', [ 'sass' ]);
builder( './src/app/index.js', true ).bundle( './dist/static', 'quiz-app.min.js' );
});
// Production build
gulp.task( 'build', [ 'sass' ], function() {
builder( './src/app/index.js', false ).bundle( './dist/static', 'quiz-app.min.js' );
});
// snip //
function builder( entry, isDev ) {
var bundler;
if( isDev ) {
bundler = watchify( browserify(
'./src/app/index.js',
_.extend( watchify.args, { debug: true })
));
} else {
bundler = browserify(
'./src/app/index.js'
);
}
bundler.transform( 'reactify' );
bundler.transform( 'es6ify' );
bundler.transform({ global: true }, 'uglifyify' );
bundler.on( 'log', gutil.log ); // Help bundler log to the terminal
function bundle( dest, filename ) {
return bundler.bundle()
.on( 'error', gutil.log.bind( gutil, 'Browserify error' )) // Log errors during build
.pipe( source( filename ))
.pipe( buffer() )
.pipe( rev() )
.pipe( gulp.dest( dest ))
.pipe( rev.manifest() )
.pipe( gulp.dest( dest ));
}
return { bundle: bundle };
}
I also tried just using the tools from NPM scripts, but I was unable to find a good way to do incremental builds while watching a set of files.