why this error come 'can not read property summary of undefined' when running command grunt filerev_apply? - node.js

why I am getting can not read property summary of undefined error while I run grunt filerev_apply or grunt filerev_replace . And when I run grunt.filerev.summary
It shows grunt.filerev.summary is not recognized as internal or external command.
Gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
filerev: {
options: {
algorithm: 'md5',
length: 8
},
images: {
src: ['views/common/abc.html'],
}
},
filerev_replace: {
options: {
assets_root: 'views/common/abc.html'
},
compiled_assets: {
src: 'views/common/abc.html'
},
views: {
options: {
views_root: 'views/'
},
src: 'views/**/*.html'
}
},
useminPrepare: {
html: 'index.html',
options: {
dest: 'indexfolder'
}
},
usemin: {
html: 'indexfolder/index.html',
options: {
dirs: ['views','views1'],
assetsDirs: ['views','views1'],
revmap: ''
}
},
filerev_apply: {
files: [
{
//expand: true,
//cwd: 'views',
src: ['views/**/*.html'],
//dest: 'views'
}
]
},
reload: {
//port: 8000,
proxy: {
host: 'localhost',
port: 80
}
},
watch: {
sass: {
files: ['views/**/*.html'],
tasks: ['reload'],
options: {
livereload: true,
}
}
}
});
grunt.loadNpmTasks('grunt-usemin');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-reload');
grunt.loadNpmTasks('grunt-filerev');
grunt.loadNpmTasks('grunt-filerev-apply');
grunt.loadNpmTasks('grunt-filerev-replace');
grunt.registerTask('default', ['usemin', 'useminPrepare', 'watch','connect', 'reload', 'filerev', 'filerev_apply', 'filerev_replace']);
};

Related

Grunt CLI crashing trying to compile bootstrap.less

I have been working on my mac for some time on a web app, compiling using Grunt on my mac - never a problem compiling.
I just set the project up on a new ultrabook PC (Acer Spin 5, i5, 8gig RAM, small but capable), but if I don't remove almost all entries in bootstrap.less the compile fails.
I start my compile using:
grunt dev -env=dev -f --verbose
The error I'm getting is:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
I've read about setting "max-old-space-size" setting for node, but I am not entirely sure how to set it up in my gruntfile.js or package.json (I'm not so well versed in Grunt/Node on the whole).
If I remove all but the first couple of imports in bootstrap.less the compile finishes as expected.
My gruntfile is a bit of a monster too, too long to post in fact ;( I have removed irrelevant parts of it below:
module.exports = function (grunt) {
'use strict';
// Force use of Unix newlines
grunt.util.linefeed = '\n';
RegExp.quote = function (string) {
return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
};
var fs = require('fs');
var path = require('path');
var npmShrinkwrap = require('npm-shrinkwrap');
var generateGlyphiconsData = require('./grunt/bs-glyphicons-data-generator.js');
var BsLessdocParser = require('./grunt/bs-lessdoc-parser.js');
var getLessVarsData = function () {
var filePath = path.join(__dirname, 'less/variables.less');
var fileContent = fs.readFileSync(filePath, {
encoding: 'utf8'
});
var parser = new BsLessdocParser(fileContent);
return {
sections: parser.parseFile()
};
};
var generateRawFiles = require('./grunt/bs-raw-files-generator.js');
var generateCommonJSModule = require('./grunt/bs-commonjs-generator.js');
var configBridge = grunt.file.readJSON('./grunt/configBridge.json', {
encoding: 'utf8'
});
Object.keys(configBridge.paths).forEach(function (key) {
configBridge.paths[key].forEach(function (val, i, arr) {
arr[i] = path.join('./docs/assets', val);
});
});
grunt.loadNpmTasks('grunt-include-replace-more');
grunt.loadNpmTasks('grunt-dev-prod-switch');
grunt.loadNpmTasks('grunt-minify-html');
grunt.loadNpmTasks('grunt-symlink');
// Project configuration.
grunt.initConfig({
// Metadata.
pkg: grunt.file.readJSON('package.json'),
banner: '/*!\n' +
' * Plenty.rdthree.com v<%= pkg.version %> (<%= pkg.homepage %>)\n' +
' * Copyright 2015-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
' * Licensed under <%= pkg.license.type %> (<%= pkg.license.url %>)\n' +
' */\n',
jqueryCheck: configBridge.config.jqueryCheck.join('\n'),
jqueryVersionCheck: configBridge.config.jqueryVersionCheck.join('\n'),
// Task configuration.
clean: {
dist: 'dist',
docs: 'docs/dist',
pageSpecificJS: ['dist/js/pageScripts/*.js', '!dist/js/pageScripts/*.min.js'],
pageSpecificCSS: ['dist/css/*.css', '!dist/css/*.min.css']
},
jshint: {
options: {
jshintrc: 'js/.jshintrc'
},
grunt: {
options: {
jshintrc: 'grunt/.jshintrc'
},
src: ['Gruntfile.js', 'grunt/*.js']
},
core: {
src: 'js/*.js'
},
test: {
options: {
jshintrc: 'js/tests/unit/.jshintrc'
},
src: 'js/tests/unit/*.js'
},
assets: {
src: ['docs/assets/js/src/*.js', 'docs/assets/js/*.js', '!docs/assets/js/*.min.js']
}
},
jscs: {
options: {
config: 'js/.jscsrc'
},
grunt: {
src: '<%= jshint.grunt.src %>'
},
core: {
src: '<%= jshint.core.src %>'
},
test: {
src: '<%= jshint.test.src %>'
},
assets: {
options: {
requireCamelCaseOrUpperCaseIdentifiers: null
},
src: '<%= jshint.assets.src %>'
}
},
symlink: {
prod: {
dest: 'dist/prod',
relativeSrc: '../dist',
options: {
type: 'dir'
} // 'file' by default
},
perf: {
dest: 'dist/perf',
relativeSrc: '../dist',
options: {
type: 'dir'
} // 'file' by default
},
},
concat: {
bootstrap: {
options: {
banner: '<%= banner %>\n<%= jqueryCheck %>\n<%= jqueryVersionCheck %>',
stripBanners: false
},
src: [
'js/vendor/jquery-migrate-3.0.0.js',
'js/bootstrap/transition.js',
'js/bootstrap/alert.js',
'js/bootstrap/button.js',
'js/bootstrap/carousel.js',
'js/bootstrap/collapse.js',
'js/bootstrap/dropdown.js',
'js/bootstrap/modal.js',
'js/bootstrap/tooltip.js',
'js/bootstrap/popover.js',
'js/bootstrap/tab.js'
],
dest: 'dist/js/<%= pkg.name %>.js'
}
},
minifyHtml: {
options: {
cdata: true
},
dist: {
files: [{
expand: true,
cwd: 'dist',
src: ['*.html'],
dest: 'dist'
}]
}
},
dev_prod_switch: {
options: {
environment: grunt.option('env') || 'dev',
env_char: '#',
env_block_dev: 'env:dev',
env_block_prod: 'env:prod'
},
dynamic_mappings: {
files: [{
expand: true,
cwd: 'dist',
src: ['*.html', 'mobile/*.html', 'js/includes.js', 'mobile/js/mobile.js', 'js/includes.min.js', 'js/pageScripts/setup*.js', 'js/touch/touch-support*.js'],
dest: 'dist'
}]
}
},
uglify: {
options: {
preserveComments: 'false'
},
core: {
src: '<%= concat.bootstrap.dest %>',
dest: 'dist/js/<%= pkg.name %>.min.js'
},
includes: {
src: 'dist/js/includes.js',
dest: 'dist/js/includes.min.js'
},
mobile: {
src: 'dist/mobile/js/mobile.js',
dest: 'dist/mobile/js/mobile.min.js'
},
customize: {
src: configBridge.paths.customizerJs,
dest: 'docs/assets/js/customize.min.js'
},
docsJs: {
src: configBridge.paths.docsJs,
dest: 'docs/assets/js/docs.min.js'
},
dashboard: {
src: 'dist/js/pageScripts/dashboard.js',
dest: 'dist/js/pageScripts/dashboard.min.js'
},
setup: {
src: 'dist/js/pageScripts/setup.js',
dest: 'dist/js/pageScripts/setup.min.js'
},
billing: {
src: 'dist/js/pageScripts/billing.js',
dest: 'dist/js/pageScripts/billing.min.js'
},
schedule: {
src: 'dist/js/pageScripts/schedule.js',
dest: 'dist/js/pageScripts/schedule.min.js'
},
},
qunit: {
options: {
inject: 'js/tests/unit/phantom.js'
},
files: 'js/tests/index.html'
},
less: {
compileCore: {
options: {
strictMath: false,
sourceMap: false,
outputSourceFiles: true,
sourceMapURL: '<%= pkg.name %>.css.map',
sourceMapFilename: 'dist/css/<%= pkg.name %>.css.map'
},
src: 'less/bootstrap.less',
dest: 'dist/css/<%= pkg.name %>.css'
},
},
autoprefixer: {
options: {
browsers: configBridge.config.autoprefixerBrowsers
},
core: {
options: {
map: true
},
src: 'dist/css/<%= pkg.name %>.css'
},
theme: {
options: {
map: true
},
src: 'dist/css/<%= pkg.name %>-theme.css'
},
plenty: {
options: {
map: true
},
src: 'dist/css/plenty.css'
},
docs: {
src: ['docs/assets/css/anchor.css', 'docs/assets/css/src/docs.css']
},
examples: {
expand: true,
cwd: 'docs/examples/',
src: ['**/*.css'],
dest: 'docs/examples/'
}
},
csslint: {
options: {
csslintrc: 'less/.csslintrc'
},
dist: [
'dist/css/bootstrap.css',
'dist/css/bootstrap-theme.css'
],
examples: [
'docs/examples/**/*.css'
],
docs: {
options: {
ids: false,
'overqualified-elements': false
},
src: 'docs/assets/css/src/docs.css'
}
},
cssmin: {
options: {
// TODO: disable `zeroUnits` optimization once clean-css 3.2 is released
// and then simplify the fix for https://github.com/twbs/bootstrap/issues/14837 accordingly
compatibility: 'ie8',
keepSpecialComments: '*',
advanced: false
},
minifyCore: {
src: 'dist/css/<%= pkg.name %>.css',
dest: 'dist/css/<%= pkg.name %>.min.css'
},
minifyTheme: {
src: 'dist/css/<%= pkg.name %>-theme.css',
dest: 'dist/css/<%= pkg.name %>-theme.min.css'
},
minifyPlenty: {
src: 'dist/css/plenty.css',
dest: 'dist/css/plenty.min.css'
},
minifySetup: {
src: 'dist/css/setup.css',
dest: 'dist/css/setup.min.css'
},
minifyDashboard: {
src: 'dist/css/dashboard.css',
dest: 'dist/css/dashboard.min.css'
},
},
usebanner: {
options: {
position: 'top',
banner: '<%= banner %>'
},
files: {
src: 'dist/css/*.css'
}
},
csscomb: {
options: {
config: 'less/.csscomb.json'
},
dist: {
expand: true,
cwd: 'dist/css/',
src: ['*.css', '!*.min.css'],
dest: 'dist/css/'
},
examples: {
expand: true,
cwd: 'docs/examples/',
src: '**/*.css',
dest: 'docs/examples/'
},
docs: {
src: 'docs/assets/css/src/docs.css',
dest: 'docs/assets/css/src/docs.css'
}
},
copy: {
fonts: {
expand: true,
src: 'fonts/*',
dest: 'dist/'
},
docs: {
expand: true,
cwd: 'dist/',
src: [
'**/*'
],
dest: 'docs/dist/'
},
img: {
cwd: 'img', // set working folder / root to copy
src: '**/*', // copy all files and subfolders
dest: 'dist/img', // destination folder
expand: true // required when using cwd
},
ajax: {
cwd: 'ajax', // set working folder / root to copy
src: '**/*', // copy all files and subfolders
dest: 'dist/ajax', // destination folder
expand: true // required when using cwd
},
},
includereplacemore: {
your_target: {
options: {
// Task-specific options go here.
},
// Files to perform replacements and includes with
src: ['*.html', 'ajax/*.html', "mobile/*.html"],
// Destination directory to copy files to
dest: 'dist/'
}
},
connect: {
server: {
options: {
port: 3000,
base: '.'
}
}
},
jekyll: {
options: {
config: '_config.yml'
},
docs: {},
github: {
options: {
raw: 'github: true'
}
}
},
jade: {
options: {
pretty: true,
data: getLessVarsData
},
customizerVars: {
src: 'docs/_jade/customizer-variables.jade',
dest: 'docs/_includes/customizer-variables.html'
},
customizerNav: {
src: 'docs/_jade/customizer-nav.jade',
dest: 'docs/_includes/nav/customize.html'
}
},
htmllint: {
options: {
ignore: [
'Attribute "autocomplete" not allowed on element "button" at this point.',
'Attribute "autocomplete" not allowed on element "input" at this point.',
'Element "img" is missing required attribute "src".'
]
},
src: '_gh_pages/**/*.html'
},
watch: {
src: {
files: '<%= jshint.core.src %>',
tasks: ['jshint:src', 'qunit', 'concat']
},
test: {
files: '<%= jshint.test.src %>',
tasks: ['jshint:test', 'qunit']
},
less: {
files: 'less/**/*.less',
tasks: 'less'
}
},
sed: {
versionNumber: {
pattern: (function () {
var old = grunt.option('oldver');
return old ? RegExp.quote(old) : old;
})(),
replacement: grunt.option('newver'),
recursive: true
}
},
'saucelabs-qunit': {
all: {
options: {
build: process.env.TRAVIS_JOB_ID,
throttled: 10,
maxRetries: 3,
maxPollRetries: 4,
urls: ['http://127.0.0.1:3000/js/tests/index.html?hidepassed'],
browsers: grunt.file.readYAML('grunt/sauce_browsers.yml')
}
}
},
exec: {
npmUpdate: {
command: 'npm update'
}
},
compress: {
main: {
options: {
archive: 'bootstrap-<%= pkg.version %>-dist.zip',
mode: 'zip',
level: 9,
pretty: true
},
files: [{
expand: true,
cwd: 'dist/',
src: ['**'],
dest: 'bootstrap-<%= pkg.version %>-dist'
}]
}
}
});
// These plugins provide necessary tasks.
require('load-grunt-tasks')(grunt, {
scope: 'devDependencies'
});
require('time-grunt')(grunt);
// Docs HTML validation task
grunt.registerTask('validate-html', ['jekyll:docs', 'htmllint']);
var runSubset = function (subset) {
return !process.env.TWBS_TEST || process.env.TWBS_TEST === subset;
};
var isUndefOrNonZero = function (val) {
return val === undefined || val !== '0';
};
// Test task.
var testSubtasks = [];
// Skip core tests if running a different subset of the test suite
if (runSubset('core') &&
// Skip core tests if this is a Savage build
process.env.TRAVIS_REPO_SLUG !== 'twbs-savage/bootstrap') {
testSubtasks = testSubtasks.concat(['dist-css', 'dist-js', 'csslint:dist', 'test-js', 'docs']);
}
// Skip HTML validation if running a different subset of the test suite
if (runSubset('validate-html') &&
// Skip HTML5 validator on Travis when [skip validator] is in the commit message
isUndefOrNonZero(process.env.TWBS_DO_VALIDATOR)) {
testSubtasks.push('validate-html');
}
// Only run Sauce Labs tests if there's a Sauce access key
if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' &&
// Skip Sauce if running a different subset of the test suite
runSubset('sauce-js-unit') &&
// Skip Sauce on Travis when [skip sauce] is in the commit message
isUndefOrNonZero(process.env.TWBS_DO_SAUCE)) {
testSubtasks.push('connect');
testSubtasks.push('saucelabs-qunit');
}
grunt.registerTask('test', testSubtasks);
grunt.registerTask('test-js', ['jshint:core', 'jshint:test', 'jshint:grunt', 'jscs:core', 'jscs:test', 'jscs:grunt', 'qunit']);
// JS distribution task.
grunt.registerTask('dist-js', ['concat', 'uglify:core', 'commonjs', 'includereplacemore']);
// JS minify page specific scripts
grunt.registerTask('uglify-pageScripts', ['uglify:dashboard', 'uglify:setup', 'uglify:billing', 'uglify:schedule', 'uglify:inventory', 'uglify:grainMarketing', 'uglify:map', 'uglify:organization', 'uglify:plans', 'uglify:schedule', 'uglify:services', 'uglify:servicessetup', 'uglify:timeentry', 'uglify:signin', 'uglify:characterPatterns', "uglify:mobile"]);
grunt.registerTask('uglify-touchScripts', ['uglify:touch_dashboard', 'uglify:touch_setup', 'uglify:touch_billing', 'uglify:touch_schedule', 'uglify:touch_inventory', 'uglify:touch_grainMarketing', 'uglify:touch_map', 'uglify:touch_organization', 'uglify:touch_plans', 'uglify:touch_schedule', 'uglify:touch_services', 'uglify:touch_servicessetup', 'uglify:touch_timeentry', 'uglify:touch_support']);
grunt.registerTask('uglify-mobile-pageScripts', ['uglify:mobile_activityList', 'uglify:mobile_addActivity', 'uglify:mobile_addPhotos', 'uglify:mobile_contactList', 'uglify:mobile_getPrepared', 'uglify:mobile_notes', 'uglify:mobile_schedule', 'uglify:mobile_taskDetail', 'uglify:mobile_taskInProgress', 'uglify:mobile_requirements', 'uglify:mobile_collect', 'uglify:mobile_viewPhoto', 'uglify:mobile_returnProducts', 'uglify:mobile_returnProduct']);
// Compile Page CSS
grunt.registerTask('compile-pageCSS', ['less:compilePlenty', 'less:compileSetup', 'less:compileDashboard', 'less:compileField', 'less:compileSignin', 'less:compileMobile']);
// Mimify CSS
grunt.registerTask('minify-pageCSS', ['cssmin:minifyCore', 'cssmin:minifyTheme', 'cssmin:minifyPlenty', 'cssmin:minifyDashboard', 'cssmin:minifySetup', 'cssmin:minifyField', 'cssmin:minifySignin', 'cssmin:minifyMobile']);
// JS Default Task.
grunt.registerTask('default-js', ['concat', 'uglify:core', 'uglify:includes', 'uglify:mobile', 'uglify-pageScripts', 'uglify-touchScripts', 'uglify-mobile-pageScripts', 'commonjs', 'includereplacemore']);
// CSS distribution task.
grunt.registerTask('less-compile', ['less:compileCore', 'less:compileTheme', 'compile-pageCSS', 'minify-pageCSS']);
grunt.registerTask('dist-css', ['less-compile', 'autoprefixer:core', 'autoprefixer:theme', 'autoprefixer:plenty', 'usebanner', 'csscomb:dist']);
// create symlinks
grunt.registerTask("symlinks", ['symlink:prod', 'symlink:perf']);
// Full distribution task.
grunt.registerTask('dev', ['clean:dist', 'dist-css', 'copy:fonts', 'copy:fontAwesome', 'symlinks', 'copy:weatherIcons', 'copy:intlTelInput', 'copy:phoneLib', 'copy:jquery311', 'copy:charPatterns', 'copy:pageScripts', 'copy:outdatedbrowser', 'copy:flatPickr', 'copy:hammertime', 'copy:hammerjs', 'copy:initialize', 'copy:touchsupport', 'copy:dropzone', 'copy:mobile', 'copy:xeditable', 'copy:manifest', 'copy:htaccess', 'copy:img', 'copy:ajax', 'dist-js', 'dev_prod_switch', 'minifyHtml']);
// Default task.
grunt.registerTask('prod', ['clean:dist', 'dist-css', 'copy:fonts', 'copy:fontAwesome', 'symlinks', 'copy:weatherIcons', 'copy:intlTelInput', 'copy:phoneLib', 'copy:jquery311', 'copy:charPatterns', 'copy:pageScripts', 'copy:outdatedbrowser', 'copy:flatPickr', 'copy:hammertime', 'copy:hammerjs', 'copy:initialize', 'copy:touchsupport', 'copy:dropzone', 'copy:mobile', 'copy:xeditable', 'copy:manifest', 'copy:htaccess', 'copy:img', 'copy:ajax', 'default-js', 'clean:pageSpecificJS', 'clean:pageSpecificCSS', 'dev_prod_switch', 'minifyHtml']);
// Version numbering task.
// grunt change-version-number --oldver=A.B.C --newver=X.Y.Z
// This can be overzealous, so its changes should always be manually reviewed!
grunt.registerTask('change-version-number', 'sed');
grunt.registerTask('build-glyphicons-data', function () {
generateGlyphiconsData.call(this, grunt);
});
// task for building customizer
grunt.registerTask('build-customizer', ['build-customizer-html', 'build-raw-files']);
grunt.registerTask('build-customizer-html', 'jade');
grunt.registerTask('build-raw-files', 'Add scripts/less files to customizer.', function () {
var banner = grunt.template.process('<%= banner %>');
generateRawFiles(grunt, banner);
});
grunt.registerTask('commonjs', 'Generate CommonJS entrypoint module in dist dir.', function () {
var srcFiles = grunt.config.get('concat.bootstrap.src');
var destFilepath = 'dist/js/npm.js';
generateCommonJSModule(grunt, srcFiles, destFilepath);
});
// Docs task.
grunt.registerTask('docs-css', ['autoprefixer:docs', 'autoprefixer:examples', 'csscomb:docs', 'csscomb:examples', 'cssmin:docs']);
grunt.registerTask('lint-docs-css', ['csslint:docs', 'csslint:examples']);
grunt.registerTask('docs-js', ['uglify:docsJs', 'uglify:customize']);
grunt.registerTask('lint-docs-js', ['jshint:assets', 'jscs:assets']);
grunt.registerTask('docs', ['docs-css', 'lint-docs-css', 'docs-js', 'lint-docs-js', 'clean:docs', 'copy:docs', 'build-glyphicons-data', 'build-customizer']);
grunt.registerTask('prep-release', ['jekyll:github', 'compress']);
// Task for updating the cached npm packages used by the Travis build (which are controlled by test-infra/npm-shrinkwrap.json).
// This task should be run and the updated file should be committed whenever Bootstrap's dependencies change.
grunt.registerTask('update-shrinkwrap', ['exec:npmUpdate', '_update-shrinkwrap']);
grunt.registerTask('_update-shrinkwrap', function () {
var done = this.async();
npmShrinkwrap({
dev: true,
dirname: __dirname
}, function (err) {
if (err) {
grunt.fail.warn(err);
}
var dest = 'test-infra/npm-shrinkwrap.json';
fs.renameSync('npm-shrinkwrap.json', dest);
grunt.log.writeln('File ' + dest.cyan + ' updated.');
done();
});
});
};
Any assistance appreciated - thanks
I split up the bootstrap.less into two files which solved the issue

WebStorm / grunt debug run throwing EADDRINUSE error

I have a Node/Angular app, developed using the WebStorm IDE. I can run the application fine via WebStorm (Shift + F10). However, any time I try to run in debug mode, I am receiving the EADDRINUSE error:
Running "concurrent:default" (concurrent) task
Verifying property concurrent.default exists in config...OK
Files: [no src] -> default
Options: limit=10, logConcurrentOutput
Error: listen EADDRINUSE :::52387
Here is my gruntfile.js - like I said, WebStorm builds and runs it just fine, until I try to run it in debug mode, where it throws the error:
'use strict';
var fs = require('fs');
module.exports = function(grunt) {
// Unified Watch Object
var watchFiles = {
serverViews: ['app/views/**/*.*'],
serverJS: ['gruntfile.js', 'server.js', 'config/**/*.js', 'app/**/*.js', '!app/tests/'],
clientViews: ['public/modules/**/views/**/*.html'],
sass: ['public/css/*.scss'],
clientJS: ['public/js/*.js', 'public/modules/**/*.js'],
clientCSS: ['public/modules/**/*.css'],
mochaTests: ['app/tests/**/*.js']
};
// Project Configuration
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
watch: {
serverViews: {
files: watchFiles.serverViews,
options: {
livereload: true
}
},
serverJS: {
files: watchFiles.serverJS,
tasks: ['jshint'],
options: {
livereload: true
}
},
clientViews: {
files: watchFiles.clientViews,
options: {
livereload: true
}
},
clientJS: {
files: watchFiles.clientJS,
tasks: ['jshint'],
options: {
livereload: true
}
},
clientCSS: {
files: watchFiles.clientCSS,
tasks: ['csslint'],
options: {
livereload: true
}
},
sass: {
files: watchFiles.sass,
tasks: ['sass:dev'],
options: {
livereload: true
}
},
mochaTests: {
files: watchFiles.mochaTests,
tasks: ['test:server'],
}
},
jshint: {
all: {
src: watchFiles.clientJS.concat(watchFiles.serverJS),
options: {
jshintrc: true
}
}
},
csslint: {
options: {
csslintrc: '.csslintrc'
},
all: {
src: watchFiles.clientCSS
}
},
uglify: {
production: {
options: {
mangle: false
},
files: {
'public/dist/application.min.js': 'public/dist/application.js'
}
}
},
cssmin: {
combine: {
files: {
'public/dist/application.min.css': '<%= applicationCSSFiles %>'
}
}
},
nodemon: {
dev: {
script: 'server.js',
options: {
nodeArgs: ['--debug'],
ext: 'js,html',
watch: watchFiles.serverViews.concat(watchFiles.serverJS)
}
}
},
'node-inspector': {
custom: {
options: {
'web-port': 1337,
'web-host': 'localhost',
'debug-port': 5858,
'save-live-edit': true,
'no-preload': true,
'stack-trace-limit': 50,
'hidden': []
}
}
},
concurrent: {
default: ['nodemon', 'watch'],
debug: ['nodemon', 'watch', 'node-inspector'],
options: {
logConcurrentOutput: true,
limit: 10
}
},
env: {
test: {
NODE_ENV: 'test'
},
secure: {
NODE_ENV: 'secure'
},
development: {
NODE_ENV: 'development'
}
},
mochaTest: {
src: watchFiles.mochaTests,
options: {
reporter: 'spec',
require: 'server.js'
}
},
karma: {
unit: {
configFile: 'karma.conf.js'
}
},
sass: {
dev: {
files: {
'public/css/style.css': 'public/css/*.scss'
}
}
},
copy: {
localConfig: {
src: 'config/env/local.example.js',
dest: 'config/env/local.js',
filter: function() {
return !fs.existsSync('config/env/local.js');
}
}
}
});
// Load NPM tasks
require('load-grunt-tasks')(grunt);
// Making grunt default to force in order not to break the project.
grunt.option('force', true);
// A Task for loading the configuration object
grunt.task.registerTask('loadConfig', 'Task that loads the config into a grunt option.', function() {
var init = require('./config/init')();
var config = require('./config/config');
grunt.config.set('applicationJavaScriptFiles', config.assets.js);
grunt.config.set('applicationCSSFiles', config.assets.css);
});
//Sass task
grunt.registerTask('default', ['lint', 'sass:dev', 'concurrent:default']);
// Debug task.
grunt.registerTask('debug', ['lint', 'copy:localConfig', 'concurrent:debug']);
// Secure task(s).
grunt.registerTask('secure', ['env:secure', 'lint', 'copy:localConfig', 'concurrent:default']);
// Lint task(s).
grunt.registerTask('lint', ['jshint', 'csslint']);
// Build task(s).
grunt.registerTask('build', ['lint', 'loadConfig', 'ngAnnotate', 'uglify', 'cssmin']);
// Test task.
grunt.registerTask('test', ['copy:localConfig', 'test:server', 'test:client']);
grunt.registerTask('test:server', ['env:test', 'mochaTest']);
grunt.registerTask('test:client', ['env:test', 'karma:unit']);
};
The problem is caused by the way Grunt spawns child tasks. By default, grunt.util.spawn() inherits main process arguments and starts child process with same options as the main process (--debug-brk=52387), so child process is started on the same debug port as the main process, causing EADDRINUSE. See https://github.com/gruntjs/grunt/issues/1420.
As a workaround, try adding process.execArgv = []; to the top of Gruntfile.js - it should help

Grunt-contrib-watch doesn't see new files

I made Gruntfile.js like this:
'use strict';
module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-favicons');
grunt.loadNpmTasks('grunt-contrib-imagemin');
grunt.loadNpmTasks('grunt-bake');
grunt.loadNpmTasks('grunt-contrib-htmlmin');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-autoprefixer');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-cwebp');
grunt.loadNpmTasks('grunt-responsive-images');
grunt.loadNpmTasks('grunt-retinafy');
grunt.loadNpmTasks('grunt-spritesmith');
grunt.loadNpmTasks('grunt-notify');
grunt.loadNpmTasks('grunt-contrib-watch');
require('load-grunt-tasks')(grunt);
grunt.initConfig({
pkg : grunt.file.readJSON('package.json'),
watch: {
html: {
files: ['./assets/**/*.html'],
tasks: ['html'],
options: {
spawn: false,
livereload: true,
},
},
less: {
files: ['./assets/less/**/*.less'],
tasks: ['less_files'],
options: {
spawn: false,
livereload: true,
},
},
js: {
files: ['./assets/js/**/*.js'],
tasks: ['js'],
options: {
spawn: false,
livereload: true,
},
},
img: {
files: ['./assets/images/**/*.png'],
tasks: ['img'],
options: {
spawn: false,
livereload: true,
},
},
favicon: {
files: ['./assets/favicon/favicon.png'],
tasks: ['favicon'],
options: {
spawn: false,
livereload: true,
},
},
icons: {
files: ['./assets/sprites/**/*.png'],
tasks: ['icons'],
options: {
spawn: false,
livereload: true,
},
},
},
shell: {
can_i_use_update: {
command: 'npm update caniuse-db'
}
},
favicons: {
options: {},
icons: {
src: 'assets/favicon/favicon.png',
dest: 'dist/favicons/'
}
},
imagemin: {
images: {
options: {
optimizationLevel: 4,
progressive: true,
interlaced: true
},
files: [{
expand: true,
cwd: './dist/images',
src: ['**/*.{png,jpg,jpeg,gif}'],
dest: './dist/images/'
}]
},
favicons: {
options: {
optimizationLevel: 4,
progressive: true,
interlaced: true
},
files: [{
expand: true,
cwd: './dist/favicons',
src: ['**/*.{png,jpg,jpeg,gif}'],
dest: './dist/favicons/'
}]
},
sprite: {
options: {
optimizationLevel: 4,
progressive: true,
interlaced: true
},
files: {
'./dist/images/sprite.png': './dist/images/sprite.png',
}
},
},
bake: {
build: {
options: {},
files: [{
expand: true,
cwd: './assets/',
src: ['*.html'],
dest: './dist/',
ext: '.html'
}]
}
},
htmlmin: {
dist: {
options: {
removeComments: true,
collapseWhitespace: true,
conservativeCollapse: true,
preserveLineBreaks: true
},
files: [{
expand: true,
cwd: './dist/',
src: ['**/*.html'],
dest: './dist/'
}]
}
},
less: {
build: {
options: {
compress: true,
ieCompat: true,
sourceMap: true,
sourceMapFilename: './dist/css/style.map',
sourceMapURL: 'css/style.map'
},
files: {
"./dist/css/style.css": "./assets/less/style.less"
}
}
},
autoprefixer: {
options: {
browsers: ['last 5 versions', 'ie 8', 'ie 9', '> 5%']
},
build: {
"./dist/css/style.css":"./dist/css/style.css"
},
},
concat: {
options: {},
dist: {
src: ['./assets/js/*.js'],
dest: './dist/js/script.js',
},
},
uglify: {
build: {
options: { compress: true },
files: { "./dist/js/script.js":"./dist/js/script.js" }
}
},
cwebp: {
build: {
options: {
q: 80,
alpha_q: 80
},
files: [{
expand: true,
cwd: './dist/images/',
src: ['**/*.{png,jpg,jpeg,gif}'],
dest: './dist/images/webp'
}]
}
},
responsive_images: {
build: {
options: {
engine:"im",
sizes: [{
width: 640,
},{
width: 1024,
},{
width: 1920
}]
},
files: [{
expand: true,
src: ['**.{jpg,gif,png}'],
cwd: './assets/images/',
custom_dest: './dist/images/responsive/{%= width %}/'
}]
}
},
retinafy: {
build: {
options: {
sizes: {
'75%': { suffix: '#1.5x' },
'100%': { suffix: '#2x' }
}
},
files: [{
expand: true,
cwd: './dist/images/',
src: ['**/*.{jpg,jpeg,gif,png}'],
dest: './dist/images/'
}],
}
},
sprite:{
all: {
src: './assets/sprites/*.png',
dest: './dist/images/sprite.png',
destCss: './assets/less/sprite.less'
}
},
notify_hooks: {
options: {
enabled: true,
max_jshint_notifications: 5, // maximum number of notifications from jshint output
title: "Project Name", // defaults to the name in package.json, or will use project directory's name
success: true, // whether successful grunt executions should be notified automatically
duration: 2 // the duration of notification in seconds, for `notify-send only
}
}
});
grunt.task.run('notify_hooks');
grunt.registerTask('html', ['bake', 'htmlmin']);
grunt.registerTask('less_files', ['less', 'autoprefixer']);
grunt.registerTask('js', ['concat', 'uglify']);
grunt.registerTask('img', ['responsive_images', 'retinafy', 'imagemin:images', 'cwebp']);
grunt.registerTask('favicon', ['favicons', 'imagemin:favicons']);
grunt.registerTask('icons', ['sprite', 'imagemin:sprite']);
grunt.registerTask('default', ['html','less_files','js','img','favicon','icons','watch']);
};
Everything works, even grunt-contrib watch, but only for old and modified files. It doesn't see any new files in watched folders. It doesn't work on different versions of grunt-contrib-watch. Any ideas?
node -v
v0.12.7
npm -v
2.11.3
OSX 10.10.4 Yosemite
I think you should strip the ./ at the beginning. It never needs to be prepended. It could be related to this issue when ./ is prepended, it breaks some of the events.
Try also setting the options to be:
options: {
event: ['changed', 'added', 'deleted']
}
The default setting is set to all but it has been reported that sometimes it doesn't work.
If all failed, there is an alternative solution. Drop grunt-contrib-watch and try grunt-simple-watch. Here you can find why grunt-contrib-watch is causing troubles.
Side note: I realized that you are loading all the tasks manually then using load-grunt-task like this:
grunt.loadNpmTasks('grunt-favicons');
grunt.loadNpmTasks('grunt-contrib-imagemin');
grunt.loadNpmTasks('grunt-bake');
grunt.loadNpmTasks('grunt-contrib-htmlmin');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-autoprefixer');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-cwebp');
grunt.loadNpmTasks('grunt-responsive-images');
grunt.loadNpmTasks('grunt-retinafy');
grunt.loadNpmTasks('grunt-spritesmith');
grunt.loadNpmTasks('grunt-notify');
grunt.loadNpmTasks('grunt-contrib-watch');
require('load-grunt-tasks')(grunt);
For your information; you don't need to load all the tasks because load-grunt-tasks do it for you automatically. load-grunt-tasks scan the packages.json file for the tasks that you have and automatically load them. You can safely remove all the grunt.loadNpmTasks(xxx) and that task will be loaded (as long as it is mentioned in packages.json)

Grunt watch task is not starting until the first output to console

My task configuration works fine but I have annoying issue where the watch task does not start to monitor unless I refresh a page or add a line for console output. So normally I am supposed to get:
Running "watch" task
Waiting...
But I don't get it until some output goes to the console.
Is it a bug?
My config is:
module.exports = function(grunt) {
grunt.initConfig({
concat: {
options: {
separator: '\n\n'
},
dev: {
src: ['ng_app/app.js', 'ng_app/**/*.js'],
dest: 'public/js/app.js'
}
},
less: {
dev: {
files: [
{
expand: true,
cwd: 'styles',
src: ['*.less', '!mixins.less', '!var.less'],
dest: 'public/css/',
ext: '.css'
},
{
expand: true,
cwd: 'styles/views',
src: ['*.less'],
dest: 'public/css/views',
ext: '.css'
}
]
}
},
express: {
dev: {
options: {
script: 'bin/www'
}
}
},
watch: {
options: {
livereload: true
},
express: {
files: ['**/*.js'],
tasks: ['express:dev'],
options: {
spawn: false
}
},
less: {
files: ['styles/**/*.less'],
tasks: ['less'],
options: {
livereload: false
}
},
concat: {
files: ['ng_app/**/*.js'],
tasks: ['concat'],
options: {
livereload: false
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-express-server');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['concat', 'less']);
grunt.registerTask('server', [ 'express:dev', 'watch' ]);
};

Grunt not live-reloading Sass/SCSS (NodeJS)

I am having a little trouble with Grunt, it's compiling my Sass/SCSS files (.scss I am using) but it won't LiveReload. I'm using the 'watch' dependency which integrates the LiveReload functionality.
Watch: https://github.com/gruntjs/grunt-contrib-watch
Sass/SCSS: https://github.com/gruntjs/grunt-contrib-sass
Here's my config below (relevant piece), can anyone advise as to where I'm going wrong? It live reloads for everyother file and folder.
grunt.initConfig({
connect: {
options: {
port: 9000,
hostname: 'localhost'
},
livereload: {
options: {
middleware: function ( connect ) {
return [
mountFolder(connect, 'app'),
lrSnippet
];
}
}
}
},
open: {
server: {
path: 'http://localhost:<%= connect.options.port %>'
}
},
sass: {
app: {
files: {
'./app/css/style.min.css': 'app/css/scss/style.scss'
}
}
},
watch: {
options: {
nospawn: true
},
css: {
files: './app/css/scss/*.scss',
tasks: ['sass'],
options: {
livereload: true,
},
},
livereload: {
options: {
livereload: LIVERELOAD_PORT
},
files: [
'app/{,*/}*.html',
'app/css/{,*/}*.{css,scss,sass}',
'app/js/{,*/}*.js',
'app/img/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
}
});
Instead of using the connect middleware, try using something like this in your watch task (coffeescript Gruntfile syntax below):
watch:
livereload:
files: "path/to/generated/css"
options:
livereload: true

Resources