I'm new to Gulp, i did some research but not found solutions .. Here is my Gulpfile.
var gulp = require('gulp');
var watch = require('gulp-watch');
var imagemin = require('gulp-imagemin');
var browserSync = require('browser-sync').create();
var paths = {
src: 'src/',
dist: 'dist/',
html: '**/*.html',
php: '**/*.php',
images: {
src: 'assets/img/**/*.{png,jpg,jpeg,svg,gif}',
dist: 'assets/img'
},
misc: '**/*.{ico,htaccess,txt}'
}
/**
* Files
*/
gulp.task('files', function(){
return gulp.src([
paths.src + paths.php,
paths.src + paths.html,
paths.src + paths.misc
])
.pipe(gulp.dest(paths.dist))
.pipe(browserSync.stream());
});
/**
* Images
*/
gulp.task('images', function(){
return gulp.src(
paths.src + paths.images.src
)
.pipe(imagemin({
progressive: true
}))
.pipe(gulp.dest(paths.dist + paths.images.dist))
.pipe(browserSync.stream());
});
/**
* Serve
*/
gulp.task('serve', ['files', 'images'], function(){
browserSync.init({
server: {
baseDir: 'dist'
}
});
watch([
paths.src + paths.php,
paths.src + paths.html,
paths.src + paths.misc
], function(){ gulp.start('files') });
watch(
paths.src + paths.images.src
, function(){ gulp.start('images') });
});
All is ok but during watching files from my "src" folder (serve task), when i delete a file (image or html,php etc...) in "src", the file is not deleted in the "dist" folder.
When file changed or added, no problem.. I've found some similar topics but not the solution..
Thanks.
The reason files aren't deleted in your dist folder is because gulp.watch() simply reruns a task whenever a watched file changes. That task doesn't know that the reason it is running is because a file was deleted. It simply processes all files matching the glob in its gulp.src() statement.
Since the deleted file doesn't exist anymore, it is not picked up by gulp.src() and your task doesn't process it. It is simply left standing as it is in your dist folder, while the other files there are overwritten.
One way to fix this is to follow the Handling the Delete Event on Watch recipe:
var fileWatcher = watch([
paths.src + paths.php,
paths.src + paths.html,
paths.src + paths.misc
], function(){ gulp.start('files') });
fileWatcher.on('change', function (event) {
if (event.type === 'deleted') {
var filePathFromSrc = path.relative(path.resolve(paths.src), event.path);
var destFilePath = path.resolve(paths.dist, filePathFromSrc);
del.sync(destFilePath);
}
});
The handling for your images would be analogous.
Related
I'm trying to get Browser Sync and Live Reload working in my gulp file but it doesn't want to run correctly.
I want to be able to detect any file change in 'src' and my 'templates' folder which are both contained within the root. The gulp file is detecting the changes in the src folder fine but the template files are not getting reloaded in the browser on save.
Note:
I have the live reload chrome browser extension.
I'm not compiling the templates folder but am compiling everything in src to the web destination folder.
The Gulp File:
// -------------------- Configuration Settings --------------------
var config = {};
//basics
config.siteName = 'Franklin';
config.proxyDomain = 'https://franklin.test';
//source directory
config.src = 'src/';
//twig templates
config.templates = 'templates';
//destinations
config.dest = 'web/';
config.destJS = config.dest + 'assets/js';
config.destCSS = config.dest + 'assets/css';
config.destFonts = config.dest + 'assets/fonts';
config.destPWA = config.dest;
//globs
config.globs = {
templates : config.templates + '/**/*.twig',
scss : config.src + 'scss/**/*.scss',
js : {
individual : config.src + 'js/individual/**/*.js',
combined : [
config.src + 'js/combined/libs/*.js',
config.src + 'js/combined/plugins/*.js',
config.src + 'js/combined/pluginSubs/*.js',
config.src + 'js/combined/site/*.js',
config.src + 'js/combined/site.js'
]
},
fonts : config.src + 'fonts/**/*',
pwa : config.src + 'pwa/**/*',
watched : [
config.templates + '/**/*.twig',
config.destJS + '/**/*.min.js',
config.destCSS + '/**/*.min.css',
config.destFonts + '/**/*',
config.destPWA + '/**/*'
]
};
//browser sync
config.browserSync = {
files: config.globs.watched,
proxy: config.proxyDomain
};
// -------------------- Require Statements --------------------
var gulp = require('gulp'),
autoprefixer = require('gulp-autoprefixer'),
concat = require('gulp-concat'),
livereload = require('gulp-livereload'),
browserSync = require('browser-sync').create(),
newer = require('gulp-newer'),
notify = require('gulp-notify'),
plumber = require('gulp-plumber'),
rename = require('gulp-rename'),
sass = require('gulp-sass'),
size = require('gulp-size'),
uglify = require('gulp-uglify'),
watch = require('gulp-watch'),
path = require('path'),
cssnano = require('gulp-cssnano'),
sourcemaps = require('gulp-sourcemaps'),
lazypipe = require('lazypipe'),
fs = require('fs');
// -------------------- Notification Icon Detection --------------------
/**
* Checks to see if a file exists.
*
* #param filePath
* #returns {*}
*/
function fileExists(filePath)
{
try {
return fs.statSync(filePath).isFile();
} catch (err) {
return false;
}
}
var iconPath = path.join(__dirname, 'gulp.png');
var icon = fileExists( iconPath ) ? iconPath : null;
// -------------------- Plumber Error Handler --------------------
var plumberErrorHandler = function(err) {
console.log( 'plumber error! "' + err.message + '"' );
notify.onError({
title: config.siteName,
message: "Error: <%= err.message %>",
sound: 'Pop'
});
this.emit('end');
};
// -------------------- Processors --------------------
//individual scripts (not combined)
var jsIndividualScripts = lazypipe()
.pipe(plumber, {errorHandler: plumberErrorHandler})
.pipe(newer, { dest: config.destJS, ext: '.min.js' })
.pipe(gulp.dest, config.destJS)
.pipe(size, {showFiles: true})
.pipe(uglify)
.pipe(rename, { suffix: '.min' })
.pipe(gulp.dest, config.destJS)
.pipe(size, {showFiles: true});
//combined scripts
var jsCombinedScripts = lazypipe()
.pipe(plumber, {errorHandler: plumberErrorHandler})
.pipe(newer, config.dest + 'js/scripts.min.js')
.pipe(concat, 'scripts.js')
.pipe(gulp.dest, config.destJS)
.pipe(size, {showFiles: true})
.pipe(uglify)
.pipe(rename, { suffix: '.min' })
.pipe(gulp.dest, config.destJS)
.pipe(size, {showFiles: true});
//scss compiling
var scssProcessing = lazypipe()
.pipe(plumber, {errorHandler: plumberErrorHandler})
.pipe(sass, {outputStyle: ':compact'})
.pipe(autoprefixer, 'last 2 version')
.pipe(gulp.dest, config.destCSS)
.pipe(size, {showFiles: true})
.pipe(rename, { suffix: '.min' })
.pipe(sourcemaps.init)
.pipe(cssnano)
.pipe(sourcemaps.write, '.')
.pipe(gulp.dest, config.destCSS)
.pipe(size, {showFiles: true});
//fonts compiling
var fontsProcessing = lazypipe()
.pipe(plumber, {errorHandler: plumberErrorHandler})
.pipe(gulp.dest, config.destFonts);
//pwa compiling
var pwaProcessing = lazypipe()
.pipe(plumber, { errorHandler: plumberErrorHandler })
.pipe(gulp.dest, config.destPWA);
// -------------------- Tasks --------------------
//styles task
gulp.task('styles', function() {
if ( browserSync.active ) {
return gulp.src(config.globs.scss)
.pipe(scssProcessing())
.pipe(browserSync.reload({stream:true}));
}
return gulp.src(config.globs.scss).pipe(scssProcessing());
});
//template task
gulp.task('templates', function() {
if ( browserSync.active ) {
return gulp.src(config.globs.templates)
.pipe(browserSync.reload({stream:true}));
}
});
//scripts individual task
gulp.task('scripts-individual', function() {
return gulp.src(config.globs.js.individual).pipe(jsIndividualScripts());
});
//scripts combined task
gulp.task('scripts-combined', function() {
return gulp.src(config.globs.js.combined).pipe(jsCombinedScripts());
});
//fonts task
gulp.task('fonts', function() {
return gulp.src(config.globs.fonts).pipe(fontsProcessing());
});
//pwa task
gulp.task('pwa', function () {
return gulp.src(config.globs.pwa).pipe(pwaProcessing());
});
//watch task
gulp.task('live', function() {
//watch all .scss files
gulp.watch(config.globs.scss, ['styles']);
//watch all twig template files
gulp.watch(config.globs.templates, ['templates']);
//watch each individual .js file
watch(config.globs.js.individual).pipe(jsIndividualScripts());
//watch all combined .js files
gulp.watch(config.globs.js.combined, ['scripts-combined']);
});
//default task - one time styles and scripts
gulp.task('default', ['styles', 'templates', 'scripts-individual', 'scripts-combined', 'fonts', 'pwa']);
//start browser-sync server
gulp.task('serve-bs', ['live'], function() {
browserSync.init(config.browserSync)
});
//start livereload
gulp.task('watch', ['live'], function() {
livereload.listen();
//watch for changes on transpired templates, css, and js files
gulp.watch(config.globs.watched, function(event) {
gulp.src(event.path)
.pipe(plumber({errorHandler: plumberErrorHandler}))
.pipe(livereload())
.pipe(notify({
title: config.siteName,
message: event.type + ': ' + event.path.replace(__dirname, '').replace(/\\/g, '/') + ' was reloaded',
sound: 'Pop',
icon: icon
})
);
});
});
I trying to create dynamic gulp task which will loop through all files and folders and concat/compile it in corresponding folders.
Folders structure are for example:
theme/framework/modules/module-1/assets/css/scss/scss-file-1.scss and theme/framework/modules/module-2/assets/css/scss/scss-file-2.scss etc.
And gulp task is
gulp.task('modules-sass', function () {
return gulp.src([
'../../framework/modules/**/assets/css/scss/*.scss'
])
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sassGlob())
.pipe(sass({outputStyle: 'expanded'}).on('error', sass.logError))
.pipe(sourcemaps.write('.', {
includeContent: false,
sourceRoot: function(file) {
return '../css';
}
}))
.pipe(gulp.dest('../../framework/modules'));
});
Results are:
theme/framework/modules/module-1/assets/css/scss/scss-file-1.css
theme/framework/modules/module-1/assets/css/scss/scss-file-1.css.map
theme/framework/modules/module-2/assets/css/scss/scss-file-2.css
theme/framework/modules/module-2/assets/css/scss/scss-file-2.css.map
But I want to put css and map files inside css folder not inside scss!
Also I tried to set absolute path for destination for example
gulp.task('theme-modules-sass', function () {
return gulp.src([
'../../framework/modules/**/assets/css/scss/*.scss'
])
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sassGlob())
.pipe(sass({outputStyle: 'expanded'}).on('error', sass.logError))
.pipe(sourcemaps.write('.', {
includeContent: false,
sourceRoot: function(file) {
return '../css';
}
}))
.pipe(gulp.dest(function(file){
var filePath = file.path;
var module = filePath.substring(filePath.indexOf('\\modules'), filePath.indexOf('\\assets'));
var moduleName = module.replace('\\modules\\', '');
return '../../framework/modules/'+moduleName+'/assets/css/';
}));
});
But then gulp create inside css folder full file hierarchy, example
theme/framework/modules/module-1/assets/css/module-1/assets/css/scss/scss-file-1.css
Thanks for solutions
Best regards,
Nenad
I believe this is what you want. [It looks like your gulpfile.js is in the modules directory.]
// theme / framework / modules / module-1 / assets / css / scss / scss-file-1.scss
// theme / framework / modules / module-2 / assets / css / scss / scss-file-2.scss
var rename = require("gulp-rename");
var path = require("path");
gulp.task('modules-sass', function () {
return gulp.src([
'../../framework/modules/**/assets/css/scss/*.scss'
])
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sassGlob())
.pipe(sass({outputStyle: 'expanded'}).on('error', sass.logError))
.pipe(sourcemaps.write('.', {
includeContent: false,
sourceRoot: function(file) {
return '../css';
}
}))
.pipe(rename(function (file) {
// this removes the last parent directory of the relative file path
file.dirname = path.dirname(file.dirname);
console.log("file.dirname = " + file.dirname);
}))
.pipe(gulp.dest('../../framework/modules'));
});
gulp-rename works nicely here. I initially thought it was just for renaming basenames, like 'myFile.css', but it can ignore basenames and just manipulate the directory path as well. Which is what we do here.
We strip off the last directory name by taking the dirname of the file.dirname.
Im using the gulp smoosher to inject content from a CSS file inline into a copy of my index.html file.
This is working fine upon gulp init, however when running I cant get the task to trigger / generate any updates from updating my CSS file.
I'm currently trying with the following:
var gulp = require('gulp');
var autoprefix = require('gulp-autoprefixer');
var smoosher = require('gulp-smoosher');
var cssDir = 'assets/src/css';
var cssTargetDir = 'assets/build/css';
var htmlSrcDir = 'assets/src';
gulp.task('css', function() {
gulp.src(cssDir + '/**/*.css')
.pipe(autoprefix({
browsers: ['last 40 versions'],
cascade: false
}))
.pipe(gulp.dest(cssTargetDir));
});
gulp.task('smoosher', ['css'], function () {
gulp.src(htmlSrcDir + '/index.html')
.pipe(smoosher({
base: 'assets/build/' //target and inject from build CSS
}))
.pipe(gulp.dest('')); //root
});
gulp.task('watch', function(){
gulp.watch(cssDir + '/*.css', ['css']);
gulp.watch(htmlSrcDir + '/index.html', ['smoosher']);
})
gulp.task('default', [
'css',
'smoosher',
'watch'
]);
you should change the watch for smoosher to watch for css files and not for index.html
Remember to watch for the source of the change and not the end result
gulp.task('watch', function(){
gulp.watch(cssDir + '/*.css', ['css']);
gulp.watch(cssDir + '/*.css', ['smoosher']);
})
I'm trying to rebuild only files that change in my gulpfile.js by using this recipe via the gulp-watch plugin. The problem is when I run my default task gulp, it doesn't watch the files at all after saving any of the files I want it to watch. What am I doing wrong here in my gulpfile.js? Thanks in advance.
/* ----------------------------------------------------- */
/* Gulpfile.js
/* ----------------------------------------------------- */
'use strict';
// Setup modules/Gulp plugins
var gulp = require('gulp'),
del = require('del'),
runSequence = require('run-sequence'),
less = require('gulp-less'),
// minifyCSS = require('gulp-minify-css'),
fileinclude = require('gulp-file-include'),
order = require('gulp-order'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
sourcemaps = require('gulp-sourcemaps'),
imagemin = require('gulp-imagemin'),
pngquant = require('imagemin-pngquant'),
plumber = require('gulp-plumber'),
watch = require('gulp-watch'),
// browserify = require('browserify'),
// sourceStream = require('vinyl-source-stream'),
connect = require('gulp-connect');
// Configure file paths
var path = {
DEST: 'dist/',
SRC: 'src/',
INCLUDES: 'include/',
LESS_SRC: 'src/frontend/less/',
LESS_MANIFEST: 'src/frontend/less/all.less',
CSS_DEST: 'dist/frontend/css/',
JS_SRC: 'src/frontend/js/',
JS_MINIFIED_OUT: 'all.js',
JS_DEST: 'dist/frontend/js',
IMG_SRC: 'src/frontend/img/',
IMG_DEST: 'dist/frontend/img/',
};
// Clean out build folder each time Gulp runs
gulp.task('clean', function (cb) {
del([
path.DEST
], cb);
});
// Compile LESS
gulp.task('less', function(){
return gulp.src(path.LESS_MANIFEST)
.pipe(watch(path.LESS_MANIFEST))
.pipe(plumber({
handleError: function (err) {
console.log(err);
this.emit('end');
}
}))
.pipe(sourcemaps.init())
.pipe(less())
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest(path.CSS_DEST))
.pipe(connect.reload());
});
// Allow HTML files to be included
gulp.task('html', function() {
return gulp.src([path.SRC + '*.html'])
.pipe(watch(path.SRC + '*.html'))
.pipe(plumber({
handleError: function (err) {
console.log(err);
this.emit('end');
}
}))
.pipe(fileinclude({
prefix: '##',
basepath: path.INCLUDES
}))
.pipe(gulp.dest(path.DEST))
.pipe(connect.reload());
});
// Concatenate and minify JavaScript
gulp.task('js', function() {
return gulp.src(path.JS_SRC + '**/*.js')
.pipe(watch(path.JS_SRC + '**/*.js'))
.pipe(order([
path.JS_SRC + 'framework/*.js',
path.JS_SRC + 'vendor/*.js',
path.JS_SRC + 'client/*.js'
], {base: '.'} ))
.pipe(concat(path.JS_MINIFIED_OUT))
.pipe(uglify())
.pipe(gulp.dest(path.JS_DEST))
.pipe(connect.reload());
});
// Minify images
gulp.task('imagemin', function () {
return gulp.src(path.IMG_SRC + '**/*')
.pipe(imagemin({
progressive: true,
use: [pngquant()]
}))
.pipe(gulp.dest(path.IMG_DEST));
});
// Copy folders
gulp.task('copy', function() {
gulp.src(path.SRC + 'extjs/**/*')
.pipe(gulp.dest(path.DEST + 'extjs/'));
// Copy all Bower components to build folder
gulp.src('bower_components/**/*')
.pipe(gulp.dest('dist/bower_components/'));
});
// Connect to a server and livereload pages
gulp.task('connect', function() {
connect.server({
root: path.DEST,
livereload: true
});
});
// Organize build tasks into one task
gulp.task('build', ['less', 'html', 'js', 'imagemin', 'copy']);
// Organize server tasks into one task
gulp.task('server', ['connect']);
// Default task
gulp.task('default', function(cb) {
// Clean out dist/ folder before everything else
runSequence('clean', ['build', 'server'],
cb);
});
Try and remove the watch from your build tasks, and have separate tasks that handle the watching. Something like:
gulp.task("watch-less", function() {
watch(path.LESS_MANIFEST, function () {
gulp.start("less");
));
});
That way, it'll just trigger the task when a file changes. And the task for watching is able to be run separate from your build (which will also make your life easier if you use some form of build automation).
Also, you can specify many watch tasks, like so:
gulp.task("watch", function() {
watch(paths.FOO, function() {
gulp.start("foo");
});
watch(paths.BAR, function() {
gulp.start("bar");
});
});
I have a project in which there are about 30 css themes. It means I have the next css files structure:
src/
themes/
default/
a.scss
b.scss
rockStar/
a.scss
b.scss
oneMoreTheme/
a.scss
b.scss
dist/
themes/
default/
styles.css
rockStar/
styles.css
oneMoreTheme/
styles.css
Here is just example of gulpfile:
var gulp = require('gulp'),
glob = require('glob'),
path = require('path'),
_ = require('underscore'),
$ = require('gulp-load-plugins')(),
options = {};
options.themes = [
'default',
'rockStar',
'oneMoreTheme'
];
gulp.task('styles', function () {
_.each(options.themes, function(themeName, themeKey) {
gulp.src('src/themes/' + themeName + '/**/*.scss')
.pipe($.concat('styles.scss'))
.pipe($.sass())
.pipe(gulp.dest('dist/themes/' + themeName + '/'));
});
});
gulp.task('watch', function () {
gulp.watch('src/**/*.*', ['styles']);
});
In my gulp file I have a task "styles", which compiles scss files from each theme and puts compiled files to dist folder.
And I have task "watch" which run "styles" task when any scss file form any source theme changes. It works, but it takes much time because of lots of themes!
How can my task "watch" detect from which theme files changes and run task "styles" only for this changed theme?
That is indeed a tough one, but here is a solution. Please refer to the comments in the code for an explanation.
version 1
var gulp = require('gulp');
var merge = require('merge2');
var $ = require('gulp-load-plugins')();
var path = require('path');
var options = {};
options.themes = [
'default',
'rockStar',
'oneMoreTheme'
];
// we extract the task itself to a new function
// this allows us to reuse it
var styleTask = function(themeName) {
return gulp.src('src/themes/' + themeName + '/**/*.scss')
.pipe($.concat('styles.scss'))
.pipe($.sass())
.pipe(gulp.dest('dist/themes/' + themeName + '/'));
}
// we adapt the style task to use that function
// please note that I switched _.each for merge
// this allows you to work with streams!
gulp.task('styles', function() {
var tasks = themes.map(styleTask);
return merge(tasks);
});
// here we set up a new watcher. Instead of running 'styles'
// we filter the theme directory from the file that has changed
// and run the styleTask function
gulp.task('default', function() {
var watcher = gulp.watch('src/themes/**/*.scss', function(e) {
var theme = path
.relative(__dirname, e.path)
.substr('src/themes/'.length)
.split('/')[0];
console.log('rebuilding ' + theme);
return styleTask('theme');
});
});
version 2
// same as above except the default task. we save the theme
// we want to build in a file
var singleTheme;
// and call the styleTask function should it be set
gulp.task('single-style', function(done) {
if(singleTheme) {
return styleTask(singleTheme);
} else {
done();
}
});
// here we have a watcher that calls single-style, but before calling
// it gets the right themename.
gulp.task('default', function() {
var watcher = gulp.watch('src/themes/**/*.scss', 'single-style');
watcher.on('change', function(e) {
singleTheme = path
.relative(__dirname, e.path)
.substr('src/themes/'.length)
.split('/')[0];
console.log('rebuilding ' + theme);
})
})
I hope this helped.
Update If you want to run more tasks and have a status call on if they ended, please go for version 2. Than you can add all the tasks you want to run in
gulp.task('default', function() {
var watcher = gulp.watch('src/themes/**/*.scss', ['single-style', 'another-task']);
watcher.on('change', function(e) {
singleTheme = path
.relative(__dirname, e.path)
.substr('src/themes/'.length)
.split('/')[0];
console.log('rebuilding ' + theme);
})
})
Instead of gulp.run you can use gulp.start.