Gulp workflow for Express with SASS, BrowserSync, Uglify and Nodemon - gulp

Problems I'm facing:
The browser doesn't reflect live changes in .scss or .js
I don't understand whether we have to return the stream from the gulp.task() or not, I visited some websites and watched lectures some of which used return and some didn't.
Cannot understand the flow of execution of gulpfile (which statement runs first, then which and so on)
This is my current code of gulpfile.js.
"use strict";
var gulp = require('gulp');
var sass = require('gulp-sass');
var nodemon = require('gulp-nodemon');
var browserSync = require('browser-sync').create();
var uglify = require('gulp-uglify');
gulp.task('default', ['nodemon'], function(){
gulp.watch("src/sass/*.scss", ['sass']);
gulp.watch("src/js/*.js", ['js']);
gulp.watch("views/*.ejs").on('change',browserSync.reload); //Manual Reloading
})
// Process JS files and return the stream.
gulp.task('js', function () {
return gulp.src('src/js/*.js')
.pipe(uglify())
.pipe(gulp.dest('public/javascripts'));
});
// Compile SASS to CSS.
gulp.task('sass', function(){
// gulp.src('src/sass/*.scss') //without return or with return? why?
return gulp.src('src/sass/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('public/stylesheets'))
.pipe(browserSync.stream());
});
// Setup proxy for local server.
gulp.task('browser-sync', ['js','sass'], function() {
browserSync.init(null, {
proxy: "http://localhost:3000",
port: 7000,
});
});
gulp.task('nodemon', ['browser-sync'], function(cb){
var running = false;
return nodemon({script: 'bin/www'}).on('start', function(){
if(!running)
{
running = true;
cb();
}
});
})
You may look at project structure at https://github.com/DivyanshBatham/GulpWorkflow

Try this:
"use strict";
var gulp = require('gulp');
var sass = require('gulp-sass');
var nodemon = require('gulp-nodemon');
var browserSync = require('browser-sync').create();
var uglify = require('gulp-uglify');
// First, run all your tasks
gulp.task('default', ['nodemon', 'sass', 'js'], function(){
// Then watch for changes
gulp.watch("src/sass/*.scss", ['sass']);
gulp.watch("views/*.ejs").on('change',browserSync.reload); //Manual Reloading
// JS changes need to tell browsersync that they're done
gulp.watch("src/js/*.js", ['js-watch']);
})
// create a task that ensures the `js` task is complete before
// reloading browsers
gulp.task('js-watch', ['js'], function (done) {
browserSync.reload();
done();
});
// Process JS files and return the stream.
gulp.task('js', function () {
return gulp.src('src/js/*.js')
.pipe(uglify())
.pipe(gulp.dest('public/javascripts'));
});
// Compile SASS to CSS.
gulp.task('sass', function(){
return gulp.src('src/sass/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('public/stylesheets'))
.pipe(browserSync.stream());
});
// Setup proxy for local server.
gulp.task('browser-sync', ['js','sass'], function() {
browserSync.init(null, {
proxy: "http://localhost:3000",
port: 7000,
});
});
gulp.task('nodemon', ['browser-sync'], function(cb){
var running = false;
return nodemon({script: 'bin/www'}).on('start', function(){
if(!running)
{
running = true;
cb();
}
});
})
Also, you should consider adding the JS file to your index.ejs
Eg: <script src='/javascripts/main.js'></script>
More help: https://browsersync.io/docs/gulp

I'll answer what I can.
You don't always have to return the stream in a gulp task but you should since you have some tasks, like 'browser-sync' that are dependent on other tasks, ['js','sass'], finishing. The purpose of returning the stream is to signal task completion. It is not the only way to signal task completion but one easy way.
You are already doing this in your ['js','sass'] tasks with the return statements.
Your 'js' task needs a .pipe(browserSync.stream()); statement at the end of it like your 'sass' task. Or try .pipe(browserSync.reload({stream:true})); sometimes that variant works better.
You have both browser-sync and nodemon running - that I believe is unusual and may cause problems - they do much the same thing and do not typically see them running together. I would eliminate nodemon from your file.
Flow of execution:
(a) default calls ['nodemon', 'sass', 'js'] : these run in parallel.
(b) nodemon call 'browser-sync'. 'browserSync' must finish setting up before 'nodemon' gets into its function.
(c) 'browser-sync', ['js','sass'], Here browser-sync is dependent upon 'js' and 'sass' which run in parallel and must finish and signal that they have finished by returning the stream for example before browser-sync continues.
(d) After 'js', 'sass', 'browser-sync' and 'nodemon' have completed, your watch statements are set up and begin to watch.

Related

Gulp lint takes too much time

I have a problem with the linting and live reloading in my gulp file. They take to much time to finish.
Here is my gulp file, what do I do wrong :
'use strict';
console.time("Loading plugins"); //start measuring
var gulp = require('gulp');
var connect = require('gulp-connect');
var open = require('gulp-open');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
var concat = require('gulp-concat');
var babelify = require('babelify');
var sass = require('gulp-sass');
var merge = require('merge-stream'); // Merge all styles (css, sass and less) in one big bundle
var lint = require("gulp-eslint");
var config = {
port: 8001,
devBaseUrl: 'http://localhost',
paths: {
html: "./src/*.html",
externals: "./src/assets/externals/*.js",
js: "./src/**/*.js",
images: './src/assets/images/**/*',
fonts: './src/assets/css/fonts/*',
css: [
"./src/assets/css/*",
],
sass: './src/assets/css/*.scss',
dist: "./dist",
mainJS: "./src/main.js"
}
};
gulp.task('connect', ['watch'], function () {
connect.server({
root: ['dist'],
port: config.port,
base: config.devBaseUrl,
livereload: true,
fallback: './dist/index.html'
})
});
gulp.task('open', ['connect'], function () {
gulp.src('dist/index.html')
.pipe(open({uri: config.devBaseUrl + ":" + config.port + "/"}));
});
gulp.task('html', function () {
gulp.src(config.paths.html)
.pipe(gulp.dest(config.paths.dist))
.pipe(connect.reload());
});
gulp.task('externals', function () {
gulp.src(config.paths.externals)
.on('error', console.error.bind(console))
.pipe(concat('external.js'))
.pipe(gulp.dest(config.paths.dist + '/externals'))
.pipe(connect.reload());
});
gulp.task('js', function () {
browserify(config.paths.mainJS)
.transform('babelify', {presets: ['es2015', 'react']})
.bundle()
.on('error', console.error.bind(console))
.pipe(source('bundle.js'))
.pipe(gulp.dest(config.paths.dist + '/scripts'))
.pipe(connect.reload());
});
gulp.task('images', function () {
gulp.src(config.paths.images)
.pipe(gulp.dest(config.paths.dist + '/images'));
});
gulp.task('styles', function () {
gulp.src(config.paths.css)
.pipe(sass())
.pipe(concat('bundle.css'))
.pipe(gulp.dest(config.paths.dist + '/css'))
.pipe(connect.reload());
});
gulp.task('fonts', function () {
gulp.src(config.paths.fonts)
.pipe(gulp.dest(config.paths.dist + '/css/fonts'));
});
gulp.task('lint', function () {
return gulp.src(config.paths.js)
.pipe(lint())
.pipe(lint.format());
});
gulp.task('watch', function () {
gulp.watch(config.paths.js, ['js', 'lint']);
gulp.watch(config.paths.css, ['styles']);
});
console.timeEnd('Loading plugins');
gulp.task('default', ['js', 'styles', 'lint', 'open', 'watch']);
The lint takes almost 20s to finish and liverolading takes 5-6s to refresh the browser after I make some changes.
Any advice?
Gulp ESLint plugin is generally very slow. I compared it to Grunt at some point (a while back) and it was about 5-10 times slower. Don't know why.
Make sure you are running latest version of ESLint and also that you don't have node_modules directory under your src folder. If you do, you can run eslint with --debug flag to make sure that ESLint is not linting files in your node_modules directory. If for some reason it does, add .eslintignore file and specify everything that you don't want to lint there.
In general, if you want instant feedback while coding, I would suggest looking into editor integrations. Pretty much every editor out there has ESLint plugin at this point. They show you errors directly in the window you are writing your code in.
We've recently come across the same issue on my team. The best workaround was to run ESLint only on the modified files, instead of all js files.
We use nodemon to watch for changed files, though gulp-watch has the same idea.
See the change event on gulp-watch.
Then you'd just run a lint function on the changed file.
You may need to resolve the relative file path.
gulp.watch(config.paths.js, ['js'])
.on('change', lintFile);
const lintFile = (file) => {
return gulp.src(file)
.pipe(eslint());
};
Is it necessary to check you code while developing?
We use another approach:
1)Do not check code while developing, because it is long, also it sometimes doesn't allow to create "fast" mock for something while debugging.
2)Check style only before commit. If something is wrong, fix style and check everything works. Also CI system could control your commits.
So, my suggestion is to remove lint from watch task.

Gulp copies file but it is empty

I'm having a strange problem. I'm using gulp to compile a react app and am having it copy index.html to the appropriate web directory. When I first run gulp, all runs as expected, but when the file changes and the watch task is run, gulp copies an empty version of the file to the web directory. Does anyone know why this might be happening? Here is my gulpfile.js:
var gulp = require('gulp');
var browserify = require('browserify');
var babelify = require('babelify');
var source = require('vinyl-source-stream');
var livereload = require('gulp-livereload');
gulp.task('livereload', function() {
console.log('reloading');
livereload();
});
gulp.task('copyindextodist', function() {
gulp.src('app/index.html')
.pipe(gulp.dest('dist'));
});
gulp.task('compilejs', function() {
browserify({
entries: 'app/index.js',
extensions: ['.js'],
debug: true
})
.transform('babelify', {presets: ['es2015', 'react']})
.bundle()
.pipe(source('app.js'))
.pipe(gulp.dest('dist'));
});
gulp.task('publishapp', function() {
gulp.src('dist/*.*')
.pipe(gulp.dest('../public'));
});
gulp.task('copypaste', function() {
gulp.src('app/index.html')
.pipe(gulp.dest('../public'));
});
gulp.task('watch', function() {
livereload.listen();
gulp.watch('app/index.html', ['copyindextodist']);
gulp.watch('dist/index.html', ['publishapp']);
gulp.watch('app/index.js', ['compilejs']);
gulp.watch('dist/app.js', ['publishapp']);
});
gulp.task('default', ['copyindextodist', 'compilejs', 'publishapp', 'watch']);
I had the same problem until I defined the dependencies correctly. You can define which tasks should be completed, before the current task starts:
gulp.task('compress', ['copy'], function() {
//.... your job
});
This means that the compress task will wait for the copy task to be finished. If you don't do that, you might end up with empty/truncated files and other strange results.
Just take care that your copy tasks return a stream object.
gulp.task('copy', function() {
// "return" is the important part ;-)
return gulp.src(['filepath/**/*'])
.pipe(gulp.dest('lib/newpath'))
});
If you have multiple copy commands running in your task this is tricky, but there is an extension for this:
var gulp = require('gulp');
var merge = require('merge-stream');
gulp.task('copy', function() {
var allStreams = [
gulp.src(['node_modules/bootstrap/dist/**/*'])
.pipe(gulp.dest('lib/bootstrap')),
gulp.src(['node_modules/jquery/dist/**/*'])
.pipe(gulp.dest('lib/jquery')),
];
return merge.apply(this, allStreams);
});
gulp.task('nextTask', ['copy'], function() {
// this task formerly produced empty files, but now
// has a valid dependency on the copy stream and
// thus has all files available when processed.
});

How to use gulp-watch?

What is the proper way to use gulp-watch plugin?
...
var watch = require('gulp-watch');
function styles() {
return gulp.src('app/styles/*.less')
.pipe(watch('app/styles/*.less'))
.pipe(concat('main.css'))
.pipe(less())
.pipe(gulp.dest('build'));
}
gulp.task('styles', styles);
I don't see any results when run gulp styles.
In your shell (such as Apple's or Linux's Terminal or iTerm) navigate to the folder that your gulpfile.js. For example, if you're using it with a WordPress Theme your gulpfile.js should be in your Theme's root. So navigate there using cd /path/to/your/wordpress/theme.
Then type gulp watch and hit enter.
If your gulpfile.js is configured properly (see example below) than you will see output like this:
[15:45:50] Using gulpfile /path/to/gulpfile.js
[15:45:50] Starting 'watch'...
[15:45:50] Finished 'watch' after 11 ms
Every time you save your file you'll see new output here instantly.
Here is an example of a functional gulpfile.js:
var gulp = require('gulp'),
watch = require('gulp-watch'),
watchLess = require('gulp-watch-less'),
pug = require('gulp-pug'),
less = require('gulp-less'),
minifyCSS = require('gulp-csso'),
concat = require('gulp-concat'),
sourcemaps = require('gulp-sourcemaps');
gulp.task('watch', function () {
gulp.watch('source/less/*.less', ['css']);
});
gulp.task('html', function(){
return gulp.src('source/html/*.pug')
.pipe(pug())
.pipe(gulp.dest('build/html'))
});
gulp.task('css', function(){
return gulp.src('source/less/*.less')
.pipe(less())
.pipe(minifyCSS())
.pipe(gulp.dest('build/css'))
});
gulp.task('js', function(){
return gulp.src('source/js/*.js')
.pipe(sourcemaps.init())
.pipe(concat('app.min.js'))
.pipe(sourcemaps.write())
.pipe(gulp.dest('build/js'))
});
gulp.task('default', [ 'html', 'js', 'css', 'watch']);
Note: Anywhere you see source/whatever/ this is a path you'll either need to create or update to reflect the path you're using for the respective file.
gulp.task('less', function() {
gulp.src('app/styles/*.less')
.pipe(less())
.pipe(gulp.dest('build'));
});
gulp.task('watch', function() {
gulp.watch(['app/styles/*.less'], ['less'])
});
Name your task like I have my 'scripts' task named so you can add it to the series. You can add an array of tasks to the series and they will be started in the order they are listed. For those coming from prior versions note the return on the gulp.src.
This is working code I hope it helps the lurkers.
Then (for version 4+) you need to do something like this:
var concat = require('gulp-concat'); // we can use ES6 const or let her just the same
var uglify = require('gulp-uglify'); // and here as well
gulp.task('scripts', function(done) {
return gulp.src('./src/js/*.js')
.pipe(concat('all.js'))
.pipe(uglify())
.pipe(gulp.dest('./dist/js/'));
});
gulp.task('watch', function() {
gulp.watch('./src/js/*.js',gulp.series(['scripts']))
});
** Note the line gulp.watch('./src/js/*.js',gulp.series(['scripts'],['task2'],['etc']))

BrowserSync: Reload HTML on Change

I'm using Gulp + BrowserSync and I'm trying to reload my development website when changes are made to my HTML files, but I can't seem to get it working.
I'm getting no errors in the command line, my page seems to reload but the changes I've made don't appear in the browser, unless I quit the gulp task and run it again.
This is my current setup:
var gulp = require('gulp');
var browserify = require('browserify');
var swig = require('gulp-swig');
var browserSync = require('browser-sync');
var reload = browserSync.reload;
gulp.task('serve', function () {
browserSync({
server: {
baseDir: './Build'
}
});
});
gulp.task('templates', function() {
return gulp.src('./src/*.html')
.pipe(swig())
.pipe(gulp.dest('./Build'))
.pipe(reload({stream: true}))
});
// Default task
gulp.task('default', ['serve', 'templates', 'sass', 'js'], function() {
gulp.watch('./src/*.html', ['templates']);
gulp.watch(['./src/scss/*.scss', './src/scss/**/*.scss'], ['sass']);
gulp.watch('./src/js/*.js', ['js']);
});
Any help with this is appreciated. Thanks in advance!
The problem in this setup seems to be swig. When you check the files in ./Build, they haven't changed, so the browser is loading the files correctly. But swig does not get the changes. Disabling swig's caching feature should resolve this:
gulp.task('templates', function() {
return gulp.src('./src/*.html')
.pipe(swig({
defaults: { cache: false }
}))
.pipe(gulp.dest('./Build'))
.pipe(reload({stream: true}));
});

HTML Reloading using BrowserSync in Gulp

I've tried several different things in my gulpfile.js to get HTML automatic reloading to work with BrowserSync (not LiveReload) in Gulp, but none have worked. I thought this last try would do the trick but it isn't working, either. What am I missing?
Here's my entire gulpfile.js:
// -------------------------------------------------------------------------
// GET THINGS SET UP
// -------------------------------------------------------------------------
// Include Gulp
var gulp = require('gulp');
// CSS plugins
var sass = require('gulp-sass');
var combineMediaQueries = require('gulp-combine-media-queries');
var autoprefixer = require('gulp-autoprefixer');
var cssmin = require('gulp-cssmin');
// JS plugins
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
// Image plugins
var imagemin = require('gulp-imagemin');
var svgmin = require('gulp-svgmin');
// General plugins
var browserSync = require('browser-sync');
var reload = browserSync.reload;
var notify = require('gulp-notify');
// -------------------------------------------------------------------------
// TASKS
// -------------------------------------------------------------------------
// CSS tasks
gulp.task('css', function() {
return gulp.src('src/scss/**/*')
// Compile Sass
.pipe(sass({ style: 'compressed', noCache: true }))
// Combine media queries
.pipe(combineMediaQueries())
// parse CSS and add vendor-prefixed CSS properties
.pipe(autoprefixer())
// Minify CSS
.pipe(cssmin())
// Where to store the finalized CSS
.pipe(gulp.dest('build/css'))
// Notify us that the task was completed
.pipe(notify({ message: 'CSS task complete' }));
});
// JS tasks
gulp.task('js', function() {
return gulp.src('src/js/**/*')
// Concatenate all JS files into one
.pipe(concat('production.js'))
// Minify JS
.pipe(uglify())
// Where to store the finalized JS
.pipe(gulp.dest('build/js'))
// Notify us that the task was completed
.pipe(notify({ message: 'Javascript task complete' }));
});
// Image tasks
gulp.task('images', function() {
return gulp.src('src/images/raster/*')
// Minify the images
.pipe(imagemin())
// Where to store the finalized images
.pipe(gulp.dest('build/images'))
// Notify us that the task was completed
.pipe(notify({ message: 'Image task complete' }));
});
// SVG tasks
gulp.task('svgs', function() {
return gulp.src('src/images/vector/*')
// Minify the SVG's
.pipe(svgmin())
// Where to store the finalized SVG's
.pipe(gulp.dest('build/images'))
// Notify us that the task was completed
.pipe(notify({ message: 'SVG task complete' }));
});
// Watch files for changes
gulp.task('watch', ['browser-sync'], function() {
// Watch HTML files
gulp.watch('build/*.html', reload);
// Watch Sass files
gulp.watch('src/scss/**/*', ['css']);
// Watch JS files
gulp.watch('src/js/**/*', ['js']);
// Watch image files
gulp.watch('src/images/raster/*', ['images']);
// Watch SVG files
gulp.watch('src/images/vector/*', ['svgs']);
});
gulp.task('browser-sync', function() {
browserSync.init(['build/css/*', 'build/js/*'], {
server: {
baseDir: "build"
}
});
});
// Default task
gulp.task('default', ['css', 'js', 'images', 'svgs', 'watch', 'browser-sync']);
I had the exact same problem.
The problem was that my jade (html) task did not finish before my browsersync task.
So I made the browsersync task wait for all tasks that had to finish first
Apparently thats why Browser-Sync was not aware of the file, this fixed it:
gulp.task('browsersync', ['jade', 'stylus', 'browserify'], function() {
browserSync.init(['./public/**/**.**'], {
port: 8080,
server: {
baseDir: "./public"
}
});
});
gulp.task('browser-sync', function() {
browserSync.init(['./build/css/**.*', './build/js/**.*'], {
server: {
baseDir: "./build"
}
});
});
These minor changes in the code above, should fix your problem...