Caching image optimization tasks in gulp - node.js

I'm trying to write gulpfile.js, which will follow modern best practices for optimization and one of them is using picture element. That's why I'm optimizing, resizing and adding webp images, but all these reprocessing tasks take quite a lot of time, that's why I want to cache all of them.
'use strict';
var gulp = require('gulp'),
plumber = require('gulp-plumber'),
gutil = require('gulp-util'),
notify = require('gulp-notify'),
size = require('gulp-size'),
rename = require('gulp-rename'),
sass = require('gulp-sass'),
autoprefixer = require('gulp-autoprefixer'),
cmq = require('gulp-combine-media-queries'),
minifyCSS = require('gulp-minify-css'),
jshint = require('gulp-jshint'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify'),
psi = require('psi'),
ngrok = require('ngrok'),
cp = require('child_process'),
browserSync = require('browser-sync'),
imageMin = require('gulp-imagemin'),
cwebp = require('gulp-cwebp'),
imageResize = require('gulp-image-resize'),
cache = require('gulp-cache'),
cached = require('gulp-cached'),
changed = require('gulp-changed'),
newer = require('gulp-newer'),
parallel = require('concurrent-transform'),
os = require('os-utils'),
minifyHTML = require('gulp-minify-html'),
clean = require('gulp-clean'),
url = 'http://1ec934f4.ngrok.com/',
reload = browserSync.reload;
var onError = function(err) {
gutil.beep();
gutil.log(gutil.colors.green(err + '\n'));
};
var messages = {
jekyllBuild: '<span style="color: grey">Running:</span> $ jekyll build'
};
/*========== Paths ==========*/
var paths = {
styles: {
src: 'assets/sass/main.scss',
dest: 'build/css',
destProd: 'html/build/css',
watch: 'assets/sass/**/*.scss',
style: 'build/css/main.css',
styleProd: 'html/build/css/main.css',
styleMin: 'build/css/main.min.css',
styleMinProd: 'html/build/css/main.min.css'
},
scripts: {
src: 'assets/js/**/*.js',
dest: 'build/js',
destProd: 'html/build/js',
destVen: 'assets/js/vendor',
script: 'build/js/main.js',
scriptProd: 'html/build/js/main.js',
scriptMin: 'build/js/main.min.js',
scriptMinProd: 'html/build/js/main.min.js',
bundleMain: 'build/js/main.bundle.js',
bundleMainMin: 'build/js/main.bundle.min.js',
watch: ['assets/js/**/*.js', '!/assets/js/vendor/**/*.js']
},
jshint: {
src: [
'assets/js/**/*.js',
'!assets/js/vendor/**/*.js'
]
},
bundles: {
main: [
'assets/js/main.js',
'assets/js/vendor/**/*.js',
'!assets/js/vendor/bootstrap-sprockets.js',
'!assets/js/vendor/bootstrap.js',
]
},
images: {
src: 'assets/img/**/*.{jpg, png, svg, gif, webp}',
dest: 'build/img',
destOpt: 'build/img/opt',
destProd: 'html/build/img',
watch: 'assets/img/**/*.{jpg, png, svg, gif, webp}',
watchOpt: 'build/img/opt/*.{jpg, png, svg, gif, webp}',
watchDest: 'build/img/*.{jpg, png, svg, gif, webp}',
watchProd: 'html/build/img/**/*.{jpg, png, svg, gif, webp}'
},
html: {
dest: 'html',
watch: ['index.html', '_layouts/*.html', '_includes/**/*', '_posts/**/*'],
watchProd: 'html/**/*.html'
},
copy: {
styles: 'bower_components/bootstrap-sass-official/assets/stylesheets/**/*.scss',
scripts: 'bower_components/bootstrap-sass-official/assets/javascripts/**/*.js'
},
clean: {
img: 'build/img',
imgProd: 'html/build/img',
styles: 'build/css',
stylesProd: 'html/build/css',
scripts: 'build/js',
scriptsProd: 'html/build/js',
build: 'build',
buildProd: 'html/build',
prod: 'html'
}
};
/*==================================
= Gulp Tasks =
==================================*/
gulp.task('browser-sync', function() {
browserSync({server: {baseDir: paths.html.dest}});
});
gulp.task('sass', function () {
return gulp.src(paths.styles.watch)
.pipe(plumber({errorHandler: onError}))
.pipe(sass({outputStyles: 'nested'}))
.pipe(autoprefixer(['last 15 versions', '> 1%', 'ie 8', 'ie 7'], {cascade: true}))
.pipe(gulp.dest(paths.styles.dest))
.pipe(gulp.dest(paths.styles.destProd))
.pipe(size({showFiles: true}))
.pipe(notify('sass is done.\n'));
});
gulp.task('sass-min', ['sass'], function () {
return gulp.src(paths.styles.style)
.pipe(plumber({errorHandler: onError}))
.pipe(cmq({log: true}))
.pipe(minifyCSS())
// .pipe(zopfli())
// .pipe(zip('main.css.zip'))
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest(paths.styles.dest))
.pipe(gulp.dest(paths.styles.destProd))
.pipe(size({showFiles: true}))
.pipe(notify('Sass-min is done.\n'));
});
gulp.task('sass-reload', ['sass-min'], function () {
return gulp.src(paths.styles.styleMin)
.pipe(reload({stream: true}));
});
gulp.task('jshint-gulp', function () {
return gulp.src('gulpfile.js')
.pipe(cache(jshint('.jshintrc')))
.pipe(jshint.reporter('jshint-stylish'))
.pipe(notify('jshint-gulp is done.\n'));
});
gulp.task('jshint', ['jshint-gulp'], function () {
return gulp.src(paths.scripts.script)
.pipe(cache(jshint('.jshintrc')))
.pipe(jshint.reporter('jshint-stylish'))
.pipe(notify('jshint-gulp is done.\n'));
});
gulp.task('concat', ['jshint'], function () {
return gulp.src(paths.bundles.main)
.pipe(concat('main.bundle.js'))
.pipe(gulp.dest(paths.scripts.dest))
.pipe(gulp.dest(paths.scripts.destProd))
.pipe(size({showFiles: true}));
});
gulp.task('js', ['concat'], function () {
return gulp.src(paths.scripts.bundleMain)
.pipe(uglify())
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest(paths.scripts.dest))
.pipe(gulp.dest(paths.scripts.destProd))
.pipe(notify('js is done.\n'));
});
gulp.task('js-reload', ['js'], function () {
return gulp.src(paths.scripts.bundleMainMin)
.pipe(plumber({errorHandler: onError}))
.pipe(reload({stream:true}));
});
gulp.task('image-min', function () {
return gulp.src(paths.images.src)
.pipe(plumber({errorHandler: onError}))
.pipe(cached(imageMin({optimizationLevel: 3, progressive: true, interlaced: true})))
.pipe(gulp.dest(paths.images.destOpt))
.pipe(size({showFiles: true}))
.pipe(notify('image-min is done.\n'));
});
gulp.task('image-resize-sm', ['image-min'], function () {
return gulp.src(paths.images.watchOpt)
.pipe(plumber({errorHandler: onError}))
.pipe(changed(paths.images.dest))
.pipe(parallel(imageResize({
width : 400,
height : 300,
crop : true,
upscale : false
}), os.cpuUsage(function(v) { console.log( 'CPU Usage (%): ' + v ); })))
.pipe(rename({suffix: '-sm'}))
.pipe(gulp.dest(paths.images.dest))
.pipe(size({showFiles: true}))
.pipe(gulp.dest(paths.images.destProd));
});
gulp.task('image-resize-md', ['image-resize-sm'], function () {
return gulp.src(paths.images.watchOpt)
.pipe(plumber({errorHandler: onError}))
.pipe(changed(paths.images.dest))
.pipe(parallel(imageResize({
width : 800,
height : 600,
crop : true,
upscale : false
}), os.cpuUsage(function(v) { console.log( 'CPU Usage (%): ' + v ); })))
.pipe(rename({suffix: '-md'}))
.pipe(gulp.dest(paths.images.dest))
.pipe(size({showFiles: true}))
.pipe(gulp.dest(paths.images.destProd));
});
gulp.task('image-resize-lg', ['image-resize-md'], function () {
return gulp.src(paths.images.watchOpt)
.pipe(plumber({errorHandler: onError}))
.pipe(changed(paths.images.dest))
.pipe(parallel(imageResize({
width : 1200,
height : 900,
crop : true,
upscale : false
}), os.cpuUsage(function(v) { console.log( 'CPU Usage (%): ' + v ); })))
.pipe(rename({suffix: '-lg'}))
.pipe(size({showFiles: true}))
.pipe(gulp.dest(paths.images.dest))
.pipe(gulp.dest(paths.images.destProd));
});
gulp.task('cwebp', ['image-resize-lg'], function () {
return gulp.src(paths.images.watchProd)
.pipe(plumber({errorHandler: onError}))
// .pipe(changed(paths.images.watchDest))
// .pipe(cwebp())
.pipe(changed(paths.images.watchDest))
.pipe(parallel(cwebp()), os.cpuUsage(function(v) { console.log( 'CPU Usage (%): ' + v ); }))
.pipe(gulp.dest(paths.images.dest))
.pipe(gulp.dest(paths.images.destProd))
.pipe(notify('cwebp is done.\n'));
});
gulp.task('img-reload', ['cwebp'], function () {
return gulp.src(paths.images.destProd)
.pipe(plumber({errorHandler: onError}))
.pipe(reload({stream:true}))
.pipe(notify('img-reload is done.\n'));
});
gulp.task('jekyll-build', function (done) {
browserSync.notify(messages.jekyllBuild);
return cp.spawn('jekyll', ['build'], {stdio: 'inherit'})
.on('close', done);
});
gulp.task('jekyll', ['jekyll-build'], function() {
return gulp.src(paths.html.watchProd)
.pipe(minifyHTML())
.pipe(gulp.dest(paths.html.dest));
});
gulp.task('jekyll-rebuild', ['jekyll'], function () {
reload();
});
gulp.task('copy-css', function() {
return gulp.src(paths.copy.styles)
.pipe(gulp.dest('assets/scss/vendor'));
});
gulp.task('copy-js', function() {
return gulp.src(paths.copy.scripts)
.pipe(gulp.dest(paths.scripts.destVen));
});
gulp.task('clear-cache', function(done) {
return cache(cache.caches = {});
});
gulp.task('clean', ['clear-cache'], function() {
return gulp.src(paths.html.dest, {read: false})
.pipe(clean());
});
gulp.task('ngrok', function () {
ngrok.connect({
authtoken: 'aGJcNEqh838HDfvyheIe', //2BUMGp1fJDzPal7FvxN2
//httpauth: 'login:password',
port: 3000
}, function(err, url) {
if (err !== null) {
console.log( err );
}
});
});
gulp.task('pagespeed', ['ngrok'], function () {
return psi({
nokey: 'true', // or use key: ‘YOUR_API_KEY’
url: url,
strategy: 'mobile'
});
});
gulp.task('watch', ['sass-min', 'js', 'browser-sync'], function () {
gulp.watch(paths.styles.watch, ['sass-reload']);
gulp.watch(paths.scripts.watch, ['js-reload']);
gulp.watch(paths.images.watch, ['img-reload']);
gulp.watch(paths.html.watch, ['jekyll-rebuild']);
});
Questions
How to properly use os-utils to output CPU and memory usage in % used over the single task?
Does my onError function works properly? I'm not quite clear with how to use beep and gutil?
How to properly cache (or change, remember, cached or whatever other caching plugin) images for gulp-resize and gulp-cwebp tasks ?
Check Github repo
I made some tests and the processing time tells that gulp-cached and parallel do work properly, but gulp-changed is not working. I also tried to use gulp-cache and gulp-cached plugins instead of gulp-changed, but it didn't work out too.
I was running gulp-reload task for these test with all image assests from this repo.
gulp-reload task includes gulp-imagemin, gulp-image-resize and gulp-cwebp plugins.
If you would like to run these tests on your local machine I suggest to use gulp clear-cache task for clearing cache for gulp image-min task.
Test 1
image-min [cached]
image-resize []
cwebp []
TIME +/- 64sec
Test 2
image-min [cached]
image-resize [changed]
cwebp []
TIME +/- 63sec
Test 3
image-min [cached]
image-resize [changed]
cwebp [changed]
TIME +/- 64sec
Test 4
image-min [cached]
image-resize [changed, parallel]
cwebp [changed]
Time +/- 22sec
Test 5
image-min []
image-resize [changed, parallel]
cwebp [changed]
Time +/- 32sec
Any code suggestions are also welcome!

Related

Adding additional spec files to an angular project, not loading/defining correctly?

Caveat: I am not the author of this project. Whoever originally wrote this is no longer with the organization and I am seemingly the most knowledgeable on this topic at this point.
I know a little about javascript and unit tests, so I successfully added one .spec.js file. I tried adding a second one for another module, reusing a lot of the spec setup, and it immediately broke.
Project resources:
Nodejs 12.16.1
jasmine-node-karma: "^1.6.1"
karma: "^6.3.12"
Contents of ./karma.conf.js:
module.exports = function(config) {
config.set({
basePath: './public',
frameworks: ['jasmine', 'jquery-3.2.1'],
files: [
"../node_modules/angular/angular.js",
"../node_modules/angular-mocks/angular-mocks.js",
"../node_modules/bootstrap/dist/js/bootstrap.js",
"../public/**/*.js",
],
exclude: [
],
preprocessors: {
},
client: {
captureConsole: true
},
browserConsoleLogOptions: {
terminal: true,
level: ""
},
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['FirefoxHeadless', 'ChromeHeadlessNoSandbox', 'PhantomJS'],
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
},
FirefoxHeadless: {
base: 'Firefox',
flags: ['-headless'],
}
},
singleRun: false,
concurrency: Infinity
})
}
Originally I added ./public/controllers.spec.js to match the existing ./public/controllers.js. These unit tests pass and continue to do so.
Yesterday I added ./public/backups/backupcontrollers.spec.js to match ./public/backups/backupcontrollers.js.
Contents of ./public/backups/backupcontrollers.js:
/**
* Angular controller.
*/
'use strict'
const backupApp = angular.module('backup', [])
const backupTypePath = 'elasticsearch'
backupApp.controller('BackupFormController', ['$scope', '$filter', '$http', function ($scope, $filter, $http) {
console.log('Started BackupFormController')
$scope.itemInstances = []
$scope.fetchStatus = 'Ready!'
$scope.processSelection = function (item, backupType = backupTypePath) {
$scope.currentItem = item.metadata.name
$scope.getBackup(backupType)
console.log('currentItem after selecting from dropdown: ' + $scope.currentItem)
}
$scope.init = function (backupType = backupTypePath) {
$scope.refreshItemInstances(backupType)
console.log('currentItem after loading page for first time: ' + $scope.currentItem)
}
$scope.getBackup = function (backupType = backupTypePath) {
const path = `/v1/backup/${backupType}`
$scope.fetchStatus = `Fetching Backups for Item ${$scope.currentItem}...`
console.log(`Fetching backups for item from ${path}`)
$http.get('/api', { headers: { path: path, item: $scope.currentItem } })
.success(function (data, status, headers, config) {
console.log(`Got data from GET on path ${path}, HTTP status ${status}: ${JSON.stringify(data)}`)
if (typeof data === 'string' || data instanceof String) {
$scope.backups = data.split(/\r?\n/)
} else {
$scope.backups = data
}
$scope.fetchStatus = 'Ready!'
console.log('Done fetching backup list for item:' + $scope.currentItem + '!')
})
.error(function (data, status, header, config) {
console.log(data)
$scope.fetchStatus = 'Ready!'
})
}
// Refresh the list of displayed Item instances
$scope.refreshItemInstances = function (backupType = backupTypePath) {
console.log('Fetching list of all items in the system ...')
$scope.fetchStatus = 'Fetching Items ... '
$http.get('/env')
.success(function (data, status, headers, config) {
console.log(data)
for (let i = 0; i < data.length; i++) {
$scope.itemInstances.push(data[i])
}
$scope.currentItem = $scope.itemInstances[0].metadata.name
console.log('Done fetching list of all items!')
console.log('currentItem after fetching list of all items: ' + $scope.currentItem)
$scope.fetchStatus = 'Ready!'
$scope.getBackup(backupType)
})
.error(function (data, status, header, config) {
console.log(data)
$scope.fetchStatus = 'Ready!'
})
}
}])
Contents of ./public/backups/backupcontrollers.spec.js:
describe('BackupFormController', function () {
let $controller, $rootScope, $httpBackend
beforeEach(module('backup'))
const mockBackupString = 'string of backup data'
const mockBackupData = {
body: mockBackupString
}
const mockItemsUnsorted = [
{
metadata: {
name: 'prod-mock-1',
spec: 'asdf',
status: 'ok'
},
notes: []
},
{
metadata: {
name: 'dev-mock-1',
spec: 'asdf',
status: 'ok'
},
notes: []
},
{
metadata: {
name: 'integ-mock-1',
spec: 'asdf',
status: 'ok'
},
notes: []
}
]
beforeEach(inject(function ($injector) {
$rootScope = $injector.get('$rootScope')
const $controller = $injector.get('$controller')
$httpBackend = $injector.get('$httpBackend')
const mockEnv = $httpBackend.when('GET', '/env')
.respond(mockItemsUnsorted)
const mockAPI = $httpBackend.when('GET', '/api')
.respond(mockBackupString)
const createController = function () {
return $controller('BackupFormController', { '$scope': $rootScope })
}
}))
describe('$scope.getBackup', function () {
beforeEach(function () {
spyOn(console, 'log')
})
it('should GET /api and set $scope.backups', function () {
controller = createController()
console.log('Dumping fetchStatus: ', $rootScope.fetchStatus)
$rootScope.init()
$httpBackend.flush()
expect($rootScope.backups).toEqual(mockBackupString)
expect(console.log).toHaveBeenCalled()
})
})
})
It seems like this new spec isn't working correctly at all; when I run npm test I see the normal successful tests from ./public/controllers.spec.js but also:
Chrome Headless 105.0.5195.125 (Mac OS 10.15.7) BackupFormController $scope.getBackup should GET /api and set $scope.backups FAILED
ReferenceError: createController is not defined
at UserContext.<anonymous> (backup/backupcontrollers.spec.js:51:7)
at <Jasmine>
This is the only output concerning ./public/backups/backupcontrollers.spec.js.
Has anybody run into this before? I found some posts regarding including angular-mocks, but as you can see in karma.conf.js, it's being included.

After upgrade to Gulp 4 default task is not detecting default changes for JS & Scss

I upgraded the gulp to 4.0.2 from Gulp version 3. it will not detect changes when the tracked JSa and SCSS file is changed.
Gulp version I am using :-
CLI version: 2.3.0
Local version: 4.0.2
gulpfile.js
'use strict';
var gulp = require('gulp'),
sass = require('gulp-sass'),
del = require('del'),
jshint = require('gulp-jshint'),
concat = require('gulp-concat'),
rename = require('gulp-rename'),
uglify = require('gulp-uglify'),
strip = require('gulp-strip-comments'),
livereload = require('gulp-livereload'),
http = require('http'),
st = require('st'),
sourcemaps = require('gulp-sourcemaps'),
ngAnnotate = require('gulp-ng-annotate'),
babel = require('gulp-babel'),
uglifycss = require('gulp-uglifycss'),
browserSync = require('browser-sync').create();
//Rerun the task when a file changes
var watch_hintJs = ['./global/util/*.js', './global/util/**/*.js', './modules/**/*Service.js', './modules/**/*Directive.js', './modules/**/*Controller.js', './modules/**/*Constant.js'];
var watch_hintscss = ['./global/scss/*.scss', './modules/**/*.scss'];
// This method is used to delete the files
gulp.task('clean', ()=> {
return del(['./assets/css']);
});
var globalCSS = ['./assets/libs/css/**','./assets/libs/css/*.css'];
gulp.task('css', ()=> {
return gulp.src(globalCSS)
.pipe(concat('myapp-main-libs.css'))
.pipe(uglifycss({
"uglyComments": true
}))
.pipe(gulp.dest('./assets/css/'));
});
/* SASS TO CSS CONVERSION*/
gulp.task('sass', ()=> {
return gulp.src(['./global/scss/*.scss', './global/scss/lib/*.scss', './modules/**/*.scss'])
.pipe(sass().on('error', sass.logError))
.pipe(sass())
.pipe(concat('myapp-main.css'))
//.pipe(strip())
.pipe(uglifycss({
"uglyComments": true
}))
.pipe(gulp.dest('./assets/css/'));
});
//This method is converting all JS files to Single file//
var jsFiles = ['./global/util/*.js', './global/util/lib/*.js', './global/util/components/*.js',
'./modules/**/*Service.js', './modules/**/*Directive.js', './modules/**/*Controller.js', './modules/**/*Constant.js'],
jsDest = './assets/js/',
jsLibs = [
'assets/libs/js/tether.min.js',
'assets/libs/js/jquery.min.js',
'assets/libs/js/jquery-ui-min.js',
'assets/libs/js/bootstrap.min.js',
'assets/libs/js/angular.min.js',
'assets/libs/js/angular-ui-router.min.js',
'assets/libs/js/ui-grid-min.js',
'assets/libs/js/html2canvas.js',
'assets/libs/js/ui-bootstrap-tpls-2.5.0.min.js',
'assets/libs/js/accordian.js',
'assets/libs/js/angularResizable.js',
'assets/libs/js/angular-animate.min.js',
'assets/libs/js/ngToast.js',
'assets/libs/js/angular-sanitize.js',
'assets/libs/js/pubsub.js',
'assets/libs/js/angular-environment.js',
'assets/libs/js/deferred-with-update.js',
'assets/libs/js/multiselect.js',
'assets/libs/js/angular-chart.min.js',
'assets/libs/js/common.js',
'assets/libs/js/bootstrap-colorpicker-module.min.js',
'assets/libs/js/dom-to-image.js',
'assets/libs/js/alasql.min.js',
'assets/libs/js/xlsx.core.min.js',
'node_modules/babel-polyfill/dist/polyfill.min.js',
'assets/libs/js/jquery.csv.js',
'assets/libs/js/z-worker.js',
'assets/libs/js/zip.js'
];
gulp.task('libs', ()=> {
return gulp.src(jsLibs)
.pipe(strip())
.pipe(concat('myapp-lib-scripts.js'))
.pipe(gulp.dest(jsDest));
});
var minify = require('gulp-minify');
gulp.task('scripts', ()=> {
return gulp.src(jsFiles)
.pipe(jshint())
.pipe(sourcemaps.init())
.pipe(babel({
presets: ['es2015', 'stage-3'],
"plugins": ["transform-async-to-generator"]
}))
.pipe(concat('myapp-scripts.js'))
.pipe(uglify({
mangle: false
}))
.pipe(sourcemaps.write('./maps'))
.pipe(gulp.dest(jsDest))
.pipe(livereload());
});
/*jshint, watch, browserify*/
// configure the jshint task
gulp.task('jshint', ()=> {
return gulp.src(watch_hintJs)
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'));
});
gulp.task('browser-sync', gulp.series('sass', ()=> {
browserSync.init({
server: {
injectChanges: true,
baseDir: "./"
},
browser: ["chrome.exe"]
});
}));
gulp.task('js-watch', gulp.series('scripts', () =>{
console.log('you changed the JS');
return browserSync.reload();
}));
gulp.task('css-watch', gulp.series('sass', ()=> {
console.log('you changed the css');
return browserSync.reload();
}));
gulp.task('watch', gulp.series('browser-sync', ()=> {
console.log('you reach watch');
gulp.watch(watch_hintJs, ['js-watch']);
gulp.watch(watch_hintscss, ['css-watch']);
gulp.watch(watch_hintJs, browserSync.reload());
return livereload.listen();
}));
gulp.task('server', (done)=> {
return http.createServer(
st({
path: __dirname + '/',
index: 'index.html',
cache: false
})
).listen(8080, done);
});
var revts = require('gulp-rev-timestamp');
gulp.task('rev-timestamp', ()=> {
return gulp.src("./index.html")
.pipe(revts())
.pipe(gulp.dest('.'));
});
gulp.task('default', gulp.series('clean', 'css', 'sass', 'libs', 'scripts', 'rev-timestamp', 'watch'));
gulp.task('prod', gulp.series('clean', 'css', 'sass', 'libs', 'scripts', 'jshint', 'rev-timestamp'));
Note: Style task is working correctly and moving all .scss files from source to destination.
I really appreciate any help since I am running out of ideas
Finally, I found the solution as below:-
gulp.task('watch', ()=> {
console.log('you reach watch');
gulp.watch(watch_hintJs).on('change',gulp.parallel('js-watch'));
gulp.watch(watch_hintscss).on('change',gulp.parallel('css-watch'));
return livereload.listen();
});

Getting error event.js:174 throw er; everytime I save any scss file

Here's a Screen Shot of the error event.js:174
I did a lot of research and googled a lot. I tried uninstalling and re-installing everything. Made new files again but still no luck. I tried on my laptop and it works smoothly without any errors. I am using Windows 7 64 bit desktop.
Am I doing anything wrong in Gulp? Here's the gulp code:
const gulp = require('gulp');
const sass = require('gulp-sass');
const autoprefixer = require('gulp-autoprefixer');
const cleanCSS = require('gulp-clean-css');
const browserSync = require('browser-sync').create();
const concat = require('gulp-concat');
const minify = require('gulp-minify');
const rename = require('gulp-rename');
const imagemin = require('gulp-imagemin');
const sourcemaps = require('gulp-sourcemaps');
const postcss = require('gulp-postcss');
//const webp = require('gulp-webp');
const log = require('fancy-log');
const g = require("gulp-load-plugins")();
const purgecss = require('gulp-purgecss');
const critical = require('critical').stream;
gulp.task('purgecss', () => {
return gulp.src('./dist/css/*.css')
.pipe(purgecss({
content: ["./dist/*.html"]
}))
.pipe(gulp.dest('./dist/css/purged'))
})
// Extract Media Queries & Make Seperate CSS Files
gulp.task("extractmedia", function() {
gulp.src("./dist/css/*.css")
.pipe(g.extractMediaQueries())
.pipe(gulp.dest("./dist/css/"));
});
// CSS Tasks
gulp.task('css-compile', function() {
gulp.src('scss/**/*.scss')
.pipe(sass({outputStyle: 'nested'}).on('error', sass.logError))
.pipe(autoprefixer({
browsers: ['last 10 versions'],
cascade: false
}))
.pipe(gulp.dest('./dist/css/'));
});
gulp.task('minify-css', function() {
gulp.src(['./dist/css/*.css', '!dist/css/*.min.css'])
.pipe(cleanCSS())
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest('./dist/css'))
});
// JavaScript Tasks
gulp.task('js-build', function() {
const plugins = getJSModules();
return gulp.src(plugins.modules)
.pipe(concat('modules.js'))
.pipe(gulp.dest('./dist/js/'));
});
gulp.task('js-minify', function() {
gulp.src(['./dist/js/*.js', '!dist/js/*.min.js'])
.pipe(minify({
ext:{
src:'.js',
min:'.min.js'
},
noSource: true,
}))
.pipe(gulp.dest('./dist/js'));
});
// Image Compression
gulp.task('img-compression', function() {
gulp.src('./img/*')
.pipe(imagemin([
imagemin.gifsicle({interlaced: true}),
imagemin.jpegtran({progressive: true}),
imagemin.optipng({optimizationLevel: 5}),
imagemin.svgo({
plugins: [
{removeViewBox: true},
{cleanupIDs: false}
]
})
]))
//.pipe(webp())
.pipe(gulp.dest('./dist/img'));
});
// Generate & Inline Critical-path CSS
gulp.task('critical', function () {
return gulp.src('./dist/*.html')
.pipe(critical({base: './dist/', inline: true, css: ['./dist/css/app.min.css']}))
.on('error', function(err) { log.error(err.message); })
.pipe(gulp.dest('./dist/'));
});
// Compile sass into CSS & auto-inject into browsers
gulp.task('sass', function() {
return gulp.src("dist/scss/*.scss")
.pipe(sass())
.pipe(gulp.dest("dist/css"))
.pipe(browserSync.stream({match: '**/*.css'}))
.pipe(sourcemaps.init())
.pipe(sass().on('error', sass.logError))
.pipe(postcss([ autoprefixer({ browsers: [
'Chrome >= 35',
'Firefox >= 38',
'Edge >= 12',
'Explorer >= 10',
'iOS >= 8',
'Safari >= 8',
'Android 2.3',
'Android >= 4',
'Opera >= 12']})]))
.pipe(sourcemaps.write())
.pipe(gulp.dest('css/'))
.pipe(cleanCSS())
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest('css/'))
});
// Static Server + watching scss/html files
gulp.task('serve', ['sass'], function() {
browserSync.init({
injectChanges: true,
server: "./dist"
});
gulp.watch("dist/scss/*.scss", ['sass']);
gulp.watch("dist/*.html").on('change', browserSync.reload);
});
gulp.task('default', ['serve'], function() {
gulp.watch("scss/**/*.scss", ['css-compile']);
gulp.watch(["dist/css/*.css", "!dist/css/*.min.css"], ['minify-css']);
gulp.watch("js/**/*.js", ['js-build']);
gulp.watch(["dist/js/*.js", "!dist/js/*.min.js"], ['js-minify']);
gulp.watch("**/*", {cwd: './img/'}, ['img-compression']);
});
function getJSModules() {
delete require.cache[require.resolve('./js/modules.js')];
return require('./js/modules');
}
Please Help I am Stuck. As every time I save scss file I get this error all of a sudden which sucks hell lot of time for me to develop further. Sometimes it works fine but after 3-4 save file it crashes.
Found the Solution: It was all about the Folder Permissions. Hope this helps someone.

Gulp 4 error: "Did you forget to signal async completion?"

I am working on a small project that needs .sass files compiled into .css files. I have used Gulp a while ago and loved it, but my old gulpfile.js does not work anymore, because Gulp has changed since version 4.
I have made a new gulpfile.js:
var gulp = require('gulp'),
sass = require('gulp-sass'),
rename = require('gulp-rename');
var paths = {
styles: {
src: 'src/scss/*.scss',
dest: 'build/css'
}
};
function styles() {
return gulp
.src(paths.styles.src, {
sourcemaps: true
})
.pipe(sass())
.pipe(rename({
basename: 'main',
suffix: '.min'
}))
.pipe(gulp.dest(paths.styles.dest));
}
function watch() {
gulp
.watch(paths.styles.src, styles);
}
var syncConfig = {
server: {
baseDir : './',
index : 'index.html'
},
port : 3000,
open : false
};
// browser-sync
function server() {
init(syncConfig);
}
var build = gulp.parallel(styles, watch, server);
gulp
.task(build);
gulp
.task('default', build);
I have a "Did you forget to signal async completion?" error returned by the console.
Where is my mistake?
There ware two things missing: the browsersync variable browsersync = require('browser-sync').create() and the callback for the server function:
function server(done) {
if (browsersync) browsersync.init(syncConfig);
done();
}
It compiles SASS to CSS, still there is this problem: the page does not reload automatically when changes are made in the main.scss.
Here is the entire code:
var gulp = require('gulp'),
browsersync = require('browser-sync').create(),
sass = require('gulp-sass'),
rename = require('gulp-rename');
var paths = {
styles: {
src: 'src/scss/*.scss',
dest: 'build/css'
}
};
function styles() {
return gulp
.src(paths.styles.src, {
sourcemaps: true
})
.pipe(sass())
.pipe(rename({
basename: 'main',
suffix: '.min'
}))
.pipe(gulp.dest(paths.styles.dest));
}
function watch() {
gulp
.watch(paths.styles.src, styles);
}
var syncConfig = {
server: {
baseDir : './',
index : 'index.html'
},
port : 3000,
open : false
};
// browser-sync
function server(done) {
if (browsersync) browsersync.init(syncConfig);
done();
}
var build = gulp.parallel(styles, watch, server);
gulp
.task(build);
gulp
.task('default', build);

Cannot set property '__UglifyJsPlugin' of undefined

I am using the following plugin to paralelized the uglify step in webpack
https://github.com/tradingview/webpack-uglify-parallel
unfortunately, I get the following error:
Fatal error: Cannot set property '__UglifyJsPlugin' of undefined
Here's my webpack config:
/*jslint node: true */
var webpack = require("webpack"),
_ = require("lodash"),
path = require("path"),
fs = require("fs"),
os = require('os'),
UglifyJsParallelPlugin = require('webpack-uglify-parallel'),
webpackConfig,
commonsPlugin = new webpack.optimize.CommonsChunkPlugin('m-common-[chunkhash:8].js'),
dedupePlugin = new webpack.optimize.DedupePlugin(),
uglifyPlugin = new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
parallelUglify = new UglifyJsParallelPlugin({
workers: os.cpus().length
}),
sourceMapPlugin = new webpack.SourceMapDevToolPlugin('[file].map', null,
'[absolute-resource-path]',
'[absolute-resource-path]'),
fnCaseSensitivityPlugin = function () {
this.plugin('normal-module-factory', function(nmf) {
nmf.plugin('after-resolve', function(data, done) {
var parentDir = path.dirname(data.resource);
var resourceName = path.basename(data.resource);
fs.readdir(parentDir, function(err, files) {
if (err) {
done(err);
}
if (files.indexOf(resourceName) === -1) {
var realName = _.find(files, function(filename) {
return filename.toLowerCase() === resourceName.toLowerCase();
});
done(new Error('CaseSensitivityPlugin: `' + resourceName + '` does not match the corresponding file on disk `' + realName + '`'));
return;
}
done(null, data);
});
});
});
},
fnDonePlugin = function () {
this.plugin("done", function(stats) {
var statsByChunk = JSON.parse(JSON.stringify(stats.toJson())).assetsByChunkName;
webpackConfig.statsByChunk = statsByChunk;
for (var chunkName in statsByChunk) {
if (statsByChunk.hasOwnProperty(chunkName)) {
var nameIn = statsByChunk[chunkName][0],
gzName = nameIn.substring(0, nameIn.length - 2) + "gz.js";
webpackConfig.filesToCompress['./marvel-web/dist/' + gzName] = './marvel-web/dist/' + nameIn;
// The mrvlBuildOut object contains a set of name/value
// pairs to be used during HTML template processing.
// There are certain filenames we need to add to the
// mrvlBuildOut object as properties so that they can be
// injected into HTML templates that make use of them.
// The code below takes the nameIn string which will have
// one of 2 forms:
//
// Debug Builds:
// m-core-fixed.js
//
// Produciton Builds:
// m-core-<chunkid>.js
//
// It strips off everything after the last dash including the
// .js extension so we are left with the base filename. We then
// use that filename base to look up the name of the property
// we should set to that filename on the mrvlBuildOut object.
var map = webpackConfig.mrvlBuildOutFilePropMap,
propName = map[nameIn.replace(/-[^-]+\.js$/ , '')];
if (propName) {
webpackConfig.mrvlBuildOut[propName] = nameIn;
}
}
}
webpackConfig.webpackDoneListeners.forEach(function (fnCall) {
fnCall(statsByChunk);
});
});
};
webpackConfig = {
mrvlBuildOut: {
//gets filled in with m-common-[chunkhash] and m-web-[chunkhash]
},
mrvlBuildOutFilePropMap: {
"m-common": "marvelcommon",
"m-web": "marvelweb",
"m-blog": "marvelblog",
"m-gallery": "marvelgallery",
"m-landing": "marvellanding",
"m-unsupported": "marvelunsupported",
"m-login": "marvellogin",
"m-voice-chrome": "voicechrome",
"m-apps-chrome": "appschrome",
"m-viewpage-chrome": "viewpagechrome"
},
webpackDoneListeners: [],
filesToCompress: {
},
marvel: {
addVendor: function (name, path, noparse) {
this.resolve.alias[name] = path;
if (noparse) {
this.module.noParse.push(new RegExp(path));
}
this.entry.vendors.push(name);
},
addBuildOutFilePropMapEntry: function( filenameBase, propName ) {
if ( filenameBase && propName ) {
webpackConfig.mrvlBuildOutFilePropMap[filenameBase] = propName;
}
},
stats: {
colors: true,
modules: true,
reasons: false
},
entry: {
'm-web': './marvel-web/js/app.js',
'm-blog': './marvel-web/js/app-blog.js',
'm-gallery': './marvel-web/js/app-gallery.js',
'm-landing': './marvel-web/js/app-landing.js',
'm-unsupported': './marvel-web/js/app-unsupported.js',
'm-login': './marvel-web/js/app-login.js',
'm-voice-chrome': './marvel-web/js/app-voice-chrome.js',
'm-apps-chrome': './marvel-web/js/app-apps-chrome.js',
'm-viewpage-chrome': './marvel-web/js/app-viewpage-chrome.js',
vendors: []
},
resolve: {
modulesDirectories: [
'node_modules',
'marvel-web',
'marvel-web/js'
],
alias: {
// If you find yourself wanting to add an alias here, think
// about if it would be better for your component to live in
// marvel-core instead of in marvel-web. See the README.md in
// marvel-core for more info.
'marvel-apps': __dirname + '/marvel-web/js/apps.js',
'uuid': 'node-uuid'
}
},
output: {
path: 'marvel-web/dist',
filename: '[name]-[chunkhash:8].js',
chunkFilename: '[name]-[chunkhash:8].js'
},
module: {
noParse: [
/[\/\\].html$/
]
},
plugins: [
commonsPlugin,
dedupePlugin,
parallelUglify,
fnCaseSensitivityPlugin,
sourceMapPlugin,
fnDonePlugin
]
}
};
var libs_dir = __dirname + '/marvel-core/src/js/lib/';
webpackConfig.marvel.addVendor("jquery", libs_dir + "jQuery/jquery.min.js", true);
webpackConfig.marvel.addVendor("lodash", libs_dir + "lodash/lodash.min.js", true);
webpackConfig.marvel.addVendor("underscore", libs_dir + "lodash/lodash.min.js", true);
webpackConfig.marvel.addVendor("q", libs_dir + "q/q.js", true);
webpackConfig.marvel.addVendor("backbone", libs_dir + "backbone/backbone-min.js", false);//if we don't parse backbone then require is not found??
webpackConfig.marvel.addVendor("cookie", libs_dir + "cookie/cookie.js", true);
webpackConfig.marvel.addVendor("canvas-to-blob", libs_dir + "canvas-to-blob/canvas-to-blob.js", true);
webpackConfig.marvelDebug = {
watch: true,
keepAlive: true,
stats: webpackConfig.marvel.stats,
entry: webpackConfig.marvel.entry,
resolve: webpackConfig.marvel.resolve,
output: {
path: 'marvel-web/dist',
filename: '[name]-fixed.js',
chunkFilename: '[name]-fixed.js'
},
module: webpackConfig.marvel.module,
//devtool: "eval-source-map",
devtool: "source-map",
//devtool: "eval",
addBuildOutFilePropMapEntry: webpackConfig.marvel.addBuildOutFilePropMapEntry,
plugins: [
commonsPlugin,
dedupePlugin,
fnCaseSensitivityPlugin,
sourceMapPlugin,
fnDonePlugin
]
};
webpackConfig.marvelDebug.output.pathinfo = true;
module.exports = webpackConfig;
The plugin works in my project when I don't include a separate entry for the original UglifyJsPlugin. Try removing that and add its config to the UglifyJsParallelPlugin.

Resources