I'm new to Gulp.js and I'm trying to create a template for static websites using slim/coffee/sass and Browser Sync.
I have an issue with my slim task (compile slim to html): when I edit a slim file gulp run the slim task a lot of times depending on the number of slim files in the project. (so if I have 5 slim files and I edit the title of one of them, gulp will run the slim task 5 times.)
The problem is that in this task I ask Browser Sync to reload the server whenever I edit a slim file. Using again the exemple above, if I edit a title in one file, the server will reload 5 times. And this is realy annoying.
I hope someone got a solution for this issue :)
Here the slim task in my gulpfile:
gulp.task('slim', function () {
return gulp.src(slim_dev + '/**/*.slim')
// prevent server from crashing
.pipe(plugins.plumber({ errorHandler: function(err) {
plugins.notify.onError({
title: "Gulp error in " + err.plugin
})(err);
}}))
// compile slim to html
.pipe(plugins.slim({
pretty: false,
include: true
}))
// minify html
.pipe(plugins.minifyHtml())
// copy result to build folder
.pipe(gulp.dest(slim_build))
// reload server on slim save
.pipe(reload({stream:true}))
// notify when task completed
.pipe(plugins.notify('Slim compilation completed !'));
});
Here the global gulpfile:
// GULP TEMPLATE - Gulfile.js - Victor Allegret
//
// - $ gulp
// - $ gulp build
// - $ gulp clean
//
// --------------------------------------------------------
////////////////////
// VARIABLES
////////////////////////////////////////////////////////////////////////////////
// REQUIRE
// ---------------------------------------------------------
var gulp = require('gulp'),
plugins = require('gulp-load-plugins')({
pattern: '*'
}),
reload = plugins.browserSync.reload
// PATH
// ---------------------------------------------------------
///// PATHS FOR DEV
var slim_dev = './dev/views/',
sass_dev = './dev/assets/stylesheets/',
coffee_dev = './dev/assets/javascripts/',
fonts_dev = './dev/assets/fonts/',
img_dev = './dev/assets/images/',
dev = './dev';
///// PATH FOR PROD
var slim_build = './build/views/',
sass_build = './build/assets/stylesheets/',
coffee_build = './build/assets/javascripts/',
fonts_build = './build/assets/fonts/',
img_build = './build/assets/images/',
build = './build';
////////////////////
// TASKS
////////////////////////////////////////////////////////////////////////////////
// COMPILE SLIM TO HTML
// ---------------------------------------------------------
gulp.task('slim', function () {
return gulp.src(slim_dev + '/**/*.slim')
// prevent server from crashing
.pipe(plugins.plumber({ errorHandler: function(err) {
plugins.notify.onError({
title: "Gulp error in " + err.plugin
})(err);
}}))
// compile slim to html
.pipe(plugins.slim({
pretty: false,
include: true
}))
// minify html
.pipe(plugins.minifyHtml())
// copy result to build folder
.pipe(gulp.dest(slim_build))
// reload server on slim save
.pipe(reload({stream:true}))
// notify when task completed
.pipe(plugins.notify('Slim compilation completed !'));
});
// COMPILE SASS TO CSS
// ---------------------------------------------------------
gulp.task('sass', function () {
return gulp.src(sass_dev + '/**/*.{sass,css,scss}')
// prevent server from crashing
.pipe(plugins.plumber({ errorHandler: function(err) {
plugins.notify.onError({
title: "Gulp error in " + err.plugin,
})(err);
}}))
// compile sass to css
.pipe(plugins.sass())
// add auto-prefixes
.pipe(plugins.autoprefixer({
browsers: ['last 2 versions'],
cascade: false
}))
// concat all files
.pipe(plugins.concat('main.css'))
// rename to .min
.pipe(plugins.rename('main.min.css'))
// minify css
.pipe(plugins.minifyCss())
// copy result to build folder
.pipe(gulp.dest(sass_build))
// reload on sass save
.pipe(reload({stream:true}))
// notify when task completed
.pipe(plugins.notify('Sass compilation completed !'));
});
// COMPILE COFFEE TO JS
// ---------------------------------------------------------
gulp.task('coffee', function() {
return gulp.src(coffee_dev + '/**/*.coffee')
// compile coffee to js
.pipe(plugins.coffee())
// concat all files
.pipe(plugins.concat('all.js'))
// rename to .min
.pipe(plugins.rename('all.min.js'))
// minify js
.pipe(plugins.uglify())
// copy result to build folder
.pipe(gulp.dest(coffee_build))
// notify when task completed
.pipe(plugins.notify('Coffee compilation completed !'));
});
// FONTS
// ---------------------------------------------------------
gulp.task('fonts', function() {
return gulp.src(fonts_dev + '/**/*.{eot,svg,ttf,woff}')
// copy result to build folder
.pipe(gulp.dest(fonts_build))
});
// REMOVE UNUSED CSS
// ---------------------------------------------------------
gulp.task('uncss', function () {
return gulp.src(sass_build + '/app.css')
// remove unused css
.pipe(plugins.uncss({
html: [build + '/**/*.html']
}))
// minify css
.pipe(plugins.minifyCss())
// copy result to build folder
.pipe(gulp.dest(sass_build))
// notify when task completed
.pipe(plugins.notify('Unused CSS removed !'));
});
// MINIFY IMAGES
// ---------------------------------------------------------
gulp.task('img', function () {
return gulp.src(img_dev + '/**/*.{png,jpg,jpeg,gif,svg}')
// minify images
.pipe(plugins.imagemin())
// copy result to build folder
.pipe(gulp.dest(img_build))
// notify when task completed
.pipe(plugins.notify('Images are optimized!'));
});
// REMOVE BUILD FOLDER
// ---------------------------------------------------------
gulp.task('removeBuild', function () {
return gulp.src(build, { read: false})
.pipe(plugins.rimraf())
.pipe(plugins.notify('Prod folder deleted !'));
});
////////////////////
// COMMANDS
////////////////////////////////////////////////////////////////////////////////
// RUN SLIM | SASS | COFFEE ($ gulp dev)
// ---------------------------------------------------------
gulp.task('dev', ['slim', 'sass', 'coffee', 'fonts']);
// RUN SLIM | SASS | COFFEE | UNCSS | IMG ($ gulp build)
// ---------------------------------------------------------
gulp.task('build', ['slim', 'sass', 'coffee', 'fonts', 'uncss', 'img']);
// RUN CLEAN ($ gulp clean)
// ---------------------------------------------------------
gulp.task('clean', ['removeBuild']);
// RUN SERVER ($ gulp)
// ---------------------------------------------------------
///// WATCH
gulp.task('watch', ['dev'], function () {
plugins.browserSync.init({
server: {
baseDir: slim_build,
index: "index.html"
},
scrollProportionally: true,
notify: false
})
gulp.watch(dev + '/**/*.slim', ['slim']);
gulp.watch(dev + '/**/*.sass', ['sass']);
gulp.watch(dev + '/**/*.coffee', ['coffee']);
gulp.watch(build + '/**/*.html').on('change', reload);
});
////// COMMAND
gulp.task('default', ['watch'])
Thanks a lot !
See browserSync stream option : once. So change this:
.pipe(reload({stream:true})) // in 'slim' task
to
stream = plugins.browserSync.stream // for the "slim' task
.pipe(stream({once:true})) // in 'slim' task
That option is supposed to reload browserSync only once per stream.
Related
I am trying to create a gulpfile.js to compile scss to css and JS components to a main JS file. But it's not working properly.
The issues i am facing, when I run the command gulp:
It doesn't compile JS components to a main JS file.
It compiles SCSS but when i save any file, the git-bash terminal executing files infinitely, here is the screenshot:
Here is my gulpfile.js:
"use strict";
const source = 'assets/';
// Load Modules
const { src, dest, watch, series } = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const postcss = require('gulp-postcss');
const cssnano = require('cssnano');
const terser = require('gulp-terser');
const browsersync = require('browser-sync').create();
// Scss Task
function scssTask() {
return src(`${source}/scss/zaincss.scss`)
.pipe(sass())
.pipe(postcss([cssnano()]))
.pipe(dest(`${source}/css`));
}
// Javascript Task
function jsTask() {
return src(`${source}/js/scripts/*.js`)
.pipe(terser())
.pipe(dest(`${source}/js/scripts/`));
}
// BrowserSync Tasks
function browserSyncServe(done) {
browsersync.init({
server: {
baseDir: '.'
},
injectChanges: true
});
done()
}
function browserSyncReload(done) {
browsersync.reload();
done();
}
// Watch Task
function watchTask() {
watch('*.html', browserSyncReload);
watch(['assets/scss/**/*.scss', 'assets/js/**/*.js'], series(scssTask, jsTask, browserSyncReload));
}
// Default Gulp Task
exports.default = series(
scssTask, jsTask, browserSyncServe, watchTask
);
I have googled a lot, but i am stuck. Please help me.
Part of the problem is you are watching the same directory that you are storing your js files in:
// Javascript Task
function jsTask() {
return src(`${source}/js/scripts/*.js`)
.pipe(terser())
.pipe(dest(`${source}/js/scripts/`));
}
So you send the files to ${source}/js/scripts/ but you are watching that location in your watch task: 'assets/js/**/*.js'. So any change in that location starts the process all over again.
Store you minified js files someplace else than the same directory you are watching for changes.
I know that this can be a very stupid question, but I can't find matches with other posts on stackoverflow...
So: Can I modify a file of an external module , just save the file and do something that my app can listen?
At the moment, i'm trying ti change some scss style at the ng2-datepicker module (inside node_modules folder), but if I save and the launch ng serve, changes will not affect my project.
I know it's a simple problem, but i don't know the background architecture of an Angular2 project.
Thanks in advance.
(ps I've seen that i can fork the git and then do something like npm install.
Very interesting, but i also want to know how to have the same result in local)
If you are using gulp file you can tell the changed lib file path to copy to build folder check gulp.task('copy-libs') in code below git repo for angular2-tour-of-heroes using gulp
const gulp = require('gulp');
const del = require('del');
const typescript = require('gulp-typescript');
const tscConfig = require('./tsconfig.json');
const sourcemaps = require('gulp-sourcemaps');
const tslint = require('gulp-tslint');
const browserSync = require('browser-sync');
const reload = browserSync.reload;
const tsconfig = require('tsconfig-glob');
// clean the contents of the distribution directory
gulp.task('clean', function () {
return del('dist/**/*');
});
// copy static assets - i.e. non TypeScript compiled source
gulp.task('copy:assets', ['clean'], function() {
return gulp.src(['app/**/*', 'index.html', 'styles.css', '!app/**/*.ts'], { base : './' })
.pipe(gulp.dest('dist'))
});
// copy dependencies
gulp.task('copy:libs', ['clean'], function() {
return gulp.src([
'node_modules/angular2/bundles/angular2-polyfills.js',
'node_modules/systemjs/dist/system.src.js',
'node_modules/rxjs/bundles/Rx.js',
'node_modules/angular2/bundles/angular2.dev.js',
'node_modules/angular2/bundles/router.dev.js',
'node_modules/node-uuid/uuid.js',
'node_modules/immutable/dist/immutable.js'
'yourpath/changedFileName.js'
])
.pipe(gulp.dest('dist/lib'))
});
// linting
gulp.task('tslint', function() {
return gulp.src('app/**/*.ts')
.pipe(tslint())
.pipe(tslint.report('verbose'));
});
// TypeScript compile
gulp.task('compile', ['clean'], function () {
return gulp
.src(tscConfig.files)
.pipe(sourcemaps.init())
.pipe(typescript(tscConfig.compilerOptions))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('dist/app'));
});
// update the tsconfig files based on the glob pattern
gulp.task('tsconfig-glob', function () {
return tsconfig({
configPath: '.',
indent: 2
});
});
// Run browsersync for development
gulp.task('serve', ['build'], function() {
browserSync({
server: {
baseDir: 'dist'
}
});
gulp.watch(['app/**/*', 'index.html', 'styles.css'], ['buildAndReload']);
});
gulp.task('build', ['tslint', 'compile', 'copy:libs', 'copy:assets']);
gulp.task('buildAndReload', ['build'], reload);
gulp.task('default', ['build']);
I have an issue with gulp.watch.
TLDR:
How to tell gulp.watch to wait until necessary tasks will not be finished before running new cycle?
Reasons:
I have three tasks: clean, build, and watch.
Task clean deletes directory, task build produces files in the same directory (clean is dependency for build).
Task watch runs gulp.watch on directory and then it runs build (that runs clean).
But sometimes watch task runs new build before previous build is finished and an error occurs: build continues write to directory and clean tries to remove directory (of course, ENOTEMPTY error happens).
This issue happens when I run gulp watch command.
My Gulpfile.js:
var gulp = require('gulp');
var ts = require('gulp-typescript');
var tslint = require('gulp-tslint');
var rename = require('gulp-rename');
var del = require('del');
var tsProject = ts.createProject('tsconfig.json');
var tsSources = ['app/**/*.ts', 'app/**/*.tsx'];
gulp.task('clean', function() {
return del(['built']);
});
gulp.task('build', ['clean'], function() {
return gulp.src(tsSources)
.pipe(ts(tsProject)).js
.pipe(rename({extname: '.js'}))
.pipe(gulp.dest('built'));
});
gulp.task('tslint', ['clean'], function() {
return gulp.src(tsSources)
.pipe(tslint())
.pipe(tslint.report('msbuild', {
emitError: false,
summarizeFailureOutput: false
}));
});
gulp.task('watch', ['build', 'tslint'], function() {
return gulp.watch(tsProject.config.filesGlob, ['build', 'tslint']);
});
gulp.task('default', ['build', 'tslint']);
For cleaning the gulp use following code:-
gulp.task('clean', function() {
del.sync([
path.join(__dirname, builtPath, '**/*.js'),
], {
force: true
});
});
I'm attempting to use browser-sync with Gulp 4, but bs is not preserving state, and instead does a full refresh. This is not very useful. It seems bs no longer supports true injection. I filed an issue on GH if you want to contribute.
Here is the pertinent code:
// styles:dev task
gulp.task('styles:dev', function() {
return gulp.src(config.src)
.pipe(sourcemaps.init())
.pipe(postcss(config.postcss.dev))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(config.dest.dev))
.pipe(browserSync.stream());
});
// browserSync task
gulp.task('browserSync', function(cb) {
browserSync.init(config, cb);
});
// Watch task:
gulp.task('watch:styles', function() {
return gulp.watch(config.paths.css,
gulp.series('styles:dev'));
});
gulp.task('watch', gulp.parallel('watch:styles'));
// default task
gulp.task('default',
gulp.series('clean:dev',
gulp.parallel('copy:dev', 'styles:dev'), 'browserSync', 'watch')
);
Thanks in advance.
Fixed. Here's where I went wrong:
The browser-sync constructor takes an options object, which can include a files array. Most of the tutorials I've read, including the gulpfile for Google's very own Web Starter Kit, do not include this. As it turns out, this is required for style injection to preserve state.
Furthermore, do not pass .stream() or .reload() as the final pipe in your styles task. It is not needed, and will short circuit style injection, forcing a full refresh.
Finally, the browserSync process must not be terminated, and watch and browserSync tasks must execute in parallel in order for live style injection to take place.
Hope this helps anybody facing this issue.
I also closed the corresponding github issue, and posted my gulpfile
Almost 3 years later Gulp 4 now looks a little bit different, see https://gulpjs.com/docs/en/getting-started/creating-tasks
To have a complete Gulp 4 kickstart example, see https://gist.github.com/leymannx/8f6a75e8ad5055276a71d2901813726e
// Requires Gulp v4.
// $ npm uninstall --global gulp gulp-cli
// $ rm /usr/local/share/man/man1/gulp.1
// $ npm install --global gulp-cli
// $ npm install
const { src, dest, watch, series, parallel } = require('gulp');
const browsersync = require('browser-sync').create();
const sass = require('gulp-sass');
const autoprefixer = require('gulp-autoprefixer');
const sourcemaps = require('gulp-sourcemaps');
const plumber = require('gulp-plumber');
const sasslint = require('gulp-sass-lint');
const cache = require('gulp-cached');
// Compile CSS from Sass.
function buildStyles() {
return src('scss/ix_experience.scss')
.pipe(plumber()) // Global error listener.
.pipe(sourcemaps.init())
.pipe(sass({ outputStyle: 'compressed' }))
.pipe(autoprefixer(['last 15 versions', '> 1%', 'ie 8', 'ie 7']))
.pipe(sourcemaps.write())
.pipe(dest('css/'))
.pipe(browsersync.reload({ stream: true }));
}
// Watch changes on all *.scss files, lint them and
// trigger buildStyles() at the end.
function watchFiles() {
watch(
['scss/*.scss', 'scss/**/*.scss'],
{ events: 'all', ignoreInitial: false },
series(sassLint, buildStyles)
);
}
// Init BrowserSync.
function browserSync(done) {
browsersync.init({
proxy: 'blog.localhost', // Change this value to match your local URL.
socket: {
domain: 'localhost:3000'
}
});
done();
}
// Init Sass linter.
function sassLint() {
return src(['scss/*.scss', 'scss/**/*.scss'])
.pipe(cache('sasslint'))
.pipe(sasslint({
configFile: '.sass-lint.yml'
}))
.pipe(sasslint.format())
.pipe(sasslint.failOnError());
}
// Export commands.
exports.default = parallel(browserSync, watchFiles); // $ gulp
exports.sass = buildStyles; // $ gulp sass
exports.watch = watchFiles; // $ gulp watch
exports.build = series(buildStyles); // $ gulp build
Goal
I'm updating my old gulpfile.js, which used to be mainly for compiling my Sass into CSS, but now I'm trying to get Gulp to do the following:
Sync browser, whip up localhost server - DONE
Compile Sass => CSS - DONE
Show any JavaScript errors with JSHint - DONE
Compile ES6 => ES6 with Babel (WORKING ON)
Minify all assets (WORKING ON)
Show project file size - DONE
Deploy index.html, style.css and images to S3 (WORKING ON)
Watch files, reload browser when .scss or .html changes - DONE
Problem
Trying to minify my Javascript and also create a scripts.min.js
file, it keeps adding the suffix min to every new minified JavaScript
file.
Folder structure
index.html
gulpfile.js
package.json
.aws.json
.csscomb.json
.gitignore
assets
- css
style.css
style.scss
--partials
---base
---components
---modules
- img
- js
scripts.js
- dist
gulpfile.js
// Include Gulp
var gulp = require('gulp');
var postcss = require("gulp-postcss");
// All of your plugins
var autoprefixer = require('autoprefixer');
var browserSync = require('browser-sync');
var cache = require('gulp-cache');
var concat = require('gulp-concat');
var csswring = require("csswring");
var imagemin = require('gulp-imagemin');
var jshint = require('gulp-jshint');
var lost = require("lost");
var plumber = require('gulp-plumber');
var rename = require('gulp-rename');
var rucksack = require("rucksack-css");
var sass = require('gulp-sass');
var uglify = require('gulp-uglify');
// Sync browser, whip up server
gulp.task('browser-sync', function() {
browserSync({
server: {
baseDir: "./"
}
});
});
// Reload page automagically
gulp.task('bs-reload', function () {
browserSync.reload();
});
// Compile Sass into CSS, apply postprocessors
gulp.task('styles', function(){
var processors = [
autoprefixer({browsers: ['last 2 version']}),
csswring,
lost,
rucksack
];
gulp.src(['assets/css/**/*.scss'])
.pipe(plumber({
errorHandler: function (error) {
console.log(error.message);
this.emit('end');
}}))
.pipe(sass())
.pipe(postcss(processors))
// .pipe(gulp.dest('assets/css/'))
// .pipe(rename({suffix: '.min'}))
.pipe(gulp.dest('assets/css/'))
.pipe(browserSync.reload({stream:true}))
});
// Show any JavaScript errors
gulp.task('scripts', function(){
return gulp.src('assets/js/**/*.js')
.pipe(plumber({
errorHandler: function (error) {
console.log(error.message);
this.emit('end');
}}))
.pipe(jshint())
.pipe(jshint.reporter('default'))
// .pipe(concat('main.js'))
// .pipe(babel())
.pipe(gulp.dest('assets/js/'))
.pipe(uglify())
.pipe(gulp.dest('assets/js/'))
.pipe(rename({suffix: '.min'}))
.pipe(browserSync.reload({stream:true}))
});
// Minify assets, create build folder
gulp.task('images', function(){
gulp.src('assets/img/**/*')
.pipe(cache(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true })))
.pipe(gulp.dest('assets/img'));
});
// Minify HTML
// Default task
gulp.task('default', ['browser-sync'], function(){
gulp.watch("assets/css/**/*.scss", ['styles']);
gulp.watch("assets/js/**/*.js", ['scripts']);
gulp.watch("*.html", ['bs-reload']);
gulp.start("images", "styles", "scripts")
});
// var babel = require('gulp-babel');
// var minifyhtml = require("gulp-minify-html");
// var size = require("gulp-size");
// var upload = require("gulp-s3");
Hi i can't solve all your problems but I had also a similar issue with the babel and ES6 fat arrow functions (using babelify and browserify). To solve the problem try to pass:
stage: 0
to your babel.js gulp plugin. If error will still occurs then try to pass also:
experimental: true
For more information please have a look "experimental" section on babel.js site.