Related
I'm new to grunt so I apologize if this question is a little silly.
I've got the following grunt file I've inherited and been modifying/updating:
'use strict';
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt);
require('time-grunt')(grunt);
var getVersion = function(){
var thisVer = require('./bower.json').version || '0.0.0';
var nextVer = '';
var nextVerList = thisVer.split('.');
var nextPatch = new String(new Number(nextVerList.pop()) + 1);
nextVerList.push(nextPatch);
nextVer = nextVerList.join('.');
return nextVer;
}
grunt.initConfig({
yeoman: { app: require('./bower.json').appPath || 'app',
dist: 'dist',
quickdist: 'release-quick',
version: getVersion()
},
clean: {
dist: {
force : true,
files: [{
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/*',
'!<%= yeoman.dist %>/.git*'
]
}]
}
},
// Put files not handled in other tasks here
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'*.html',
'views/{,**/}*.html',
'lib/**/*',
'images/{,*/}*.{gif,webp}',
'styles/fonts/*'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= yeoman.dist %>/images',
src: [
'generated/*'
]
}]
}
},
compass: {
options: {
sassDir: '<%= yeoman.app %>/scss',
cssDir: '<%= yeoman.app %>/styles',
generatedImagesDir: '<%= yeoman.app %>/images/generated',
imagesDir: '<%= yeoman.app %>/images',
javascriptsDir: '<%= yeoman.app %>/scripts',
fontsDir: '<%= yeoman.app %>/fonts',
importPath: '<%= yeoman.app %>/lib',
require: [ 'bootstrap-sass', 'compass/import-once/activate' ],
httpImagesPath: '/images',
httpGeneratedImagesPath: '/images/generated',
httpFontsPath: '/fonts',
relativeAssets: true
},
clean: {
options: {
clean: true,
trace: true,
force: true,
debugInfo: false
}
},
dist: {
options: {
debugInfo: false,
trace: true
}
}
},
autoprefixer: {
options: ['last 1 version'],
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/styles/',
src: '{,*/}*.css',
dest: '<%= yeoman.app %>/styles/'
}]
}
},
cssmin: {
dist: {
files: {
'<%= yeoman.dist %>/styles/styles.css': [
'.tmp/styles/{,*/}*.css',
'<%= yeoman.app %>/styles/{,*/}*.css'
]
}
}
},
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.{png,jpg,jpeg}',
dest: '<%= yeoman.dist %>/images'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.svg',
dest: '<%= yeoman.dist %>/images'
}]
}
},
ngAnnotate: {
dist: {
files: [
{
dest: '.tmp/scripts/scripts.js',
src: ['app/scripts/**/*.js'],
}
]
}
},
uglify: {
all_src : {
options : {
mangleProperties: false,
sourceMap : false,
},
files: [
{
dest : 'dist/scripts/scripts.min.js',
src: [ '.tmp/scripts/**/*.js', 'app/scripts/**/*.js' ],
},
{
expand: true,
cwd: 'app/js/',
src: ['*.js', '!*.min.js'],
dest: 'dist/js/',
ext: '.min.js'
}
]
}
},
injector: {
options: {
ignorePath: 'app/', // strips 'app/' from the urls of files
"addRootSlash": false // strips leading '/' from path files
},
local_dependencies: {
files: {
'<%= yeoman.app %>/index.html': [
'<%= yeoman.app %>/scripts/**/*.js',
'<%= yeoman.app %>/styles/**/*.css'],
}
},
bower_dependencies: {
options: {
starttag: '<!-- injector:bower:{{ext}} -->'
},
files: {
'<%= yeoman.app %>/index.html': 'bower.json'
}
}
},
});
grunt.registerTask('build', function (target) {
var preTasks = [], postTasks = [];
var baseTasks = [ 'compass:clean', 'compass:dist','autoprefixer'];
switch(target){
case 'dist':
preTasks = [ 'clean:dist' ];
postTasks = [ 'cssmin', 'imagemin', 'svgmin', 'ngAnnotate', 'uglify', 'copy:dist', 'injector:dist' ];
break;
case 'dev':
default:
preTasks = [ ];
postTasks = [ 'injector' ];
break;
}
var tasks = preTasks.concat(baseTasks).concat(postTasks);
console.log(tasks);
return grunt.task.run(tasks);
});
grunt.registerTask('default', [
'build:dev'
]);
grunt.registerTask('build-dist', [
'build:dist'
]);
/*
grunt.registerTask('build', [
'clean:dist',
'compass:clean',
'compass:dist',
'copy:styles',
'imagemin',
'svgmin',
'injector',
'autoprefixer',
'ngAnnotate',
'copy:dist',
'cssmin',
'uglify',
'htmlmin'
]);//*/
};
I'm trying to get "injector" to run on yeoman.app if the task is dev, based on the folders in the app folder, and on yeoman.dist if the task is prod, based the folders in the dist folder.
The problem I'm running into is it doesn't appear I can create a sub-item under the injector configuration one for app, one for dist, so I run it with:
injector:app
or
injector:dist
As a result the value in the config seems stuck on what it was when the config was set.
What's the proper way to handle this?
Figured it out. Add a var to the config, use that var in the injector code, and set that var prior to running the task list:
'use strict';
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt);
require('time-grunt')(grunt);
var getVersion = function(){
var thisVer = require('./bower.json').version || '0.0.0';
var nextVer = '';
var nextVerList = thisVer.split('.');
var nextPatch = new String(new Number(nextVerList.pop()) + 1);
nextVerList.push(nextPatch);
nextVer = nextVerList.join('.');
return nextVer;
}
var yeomanConfig = { app: require('./bower.json').appPath || 'app',
dist: 'dist',
quickdist: 'release-quick',
version: getVersion()
}
grunt.initConfig({
yeoman: yeomanConfig,
injectorTarget : yeomanConfig.app,
clean: {
dist: {
force : true,
files: [{
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/*',
'!<%= yeoman.dist %>/.git*'
]
}]
}
},
// Put files not handled in other tasks here
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'*.html',
'views/{,**/}*.html',
'lib/**/*',
'images/{,*/}*.{gif,webp}',
'styles/fonts/*'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= yeoman.dist %>/images',
src: [
'generated/*'
]
}]
}
},
compass: {
options: {
sassDir: '<%= yeoman.app %>/scss',
cssDir: '<%= yeoman.app %>/styles',
generatedImagesDir: '<%= yeoman.app %>/images/generated',
imagesDir: '<%= yeoman.app %>/images',
javascriptsDir: '<%= yeoman.app %>/scripts',
fontsDir: '<%= yeoman.app %>/fonts',
importPath: '<%= yeoman.app %>/lib',
require: [ 'bootstrap-sass', 'compass/import-once/activate' ],
httpImagesPath: '/images',
httpGeneratedImagesPath: '/images/generated',
httpFontsPath: '/fonts',
relativeAssets: true
},
clean: {
options: {
clean: true,
trace: true,
force: true,
debugInfo: false
}
},
dist: {
options: {
debugInfo: false,
trace: true
}
}
},
autoprefixer: {
options: ['last 1 version'],
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/styles/',
src: '{,*/}*.css',
dest: '<%= yeoman.app %>/styles/'
}]
}
},
cssmin: {
dist: {
files: {
'<%= yeoman.dist %>/styles/styles.css': [
'.tmp/styles/{,*/}*.css',
'<%= yeoman.app %>/styles/{,*/}*.css'
]
}
}
},
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.{png,jpg,jpeg}',
dest: '<%= yeoman.dist %>/images'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.svg',
dest: '<%= yeoman.dist %>/images'
}]
}
},
ngAnnotate: {
dist: {
files: [
{
dest: '.tmp/scripts/scripts.js',
src: ['app/scripts/**/*.js'],
}
]
}
},
uglify: {
all_src : {
options : {
mangleProperties: false,
sourceMap : false,
},
files: [
{
dest : 'dist/scripts/scripts.min.js',
src: [ '.tmp/scripts/**/*.js', 'app/scripts/**/*.js' ],
},
{
expand: true,
cwd: 'app/js/',
src: ['*.js', '!*.min.js'],
dest: 'dist/js/',
ext: '.min.js'
}
]
}
},
injector: {
options: {
ignorePath: '<%= injectorTarget %>/', // strips 'app/' from the urls of files
"addRootSlash": false // strips leading '/' from path files
},
local_dependencies: {
files: {
'<%= injectorTarget %>/index.html': [
'<%= injectorTarget %>/scripts/**/*.js',
'<%= injectorTarget %>/styles/**/*.css'],
}
},
bower_dependencies: {
options: {
starttag: '<!-- injector:bower:{{ext}} -->'
},
files: {
'<%= injectorTarget %>/index.html': 'bower.json'
}
}
},
});
grunt.registerTask('build', function (target) {
var preTasks = [], postTasks = [];
var baseTasks = [ 'compass:clean', 'compass:dist','autoprefixer'];
var baseTasks = [];
switch(target){
case 'prod':
grunt.config.set("injectorTarget", yeomanConfig.dist);
//preTasks = [ 'clean:dist' ];
//postTasks = [ 'cssmin', 'imagemin', 'svgmin', 'ngAnnotate', 'uglify', 'copy:dist', 'injector' ];
postTasks = [ 'injector' ];
break;
case 'dev':
default:
grunt.config.set("injectorTarget", yeomanConfig.app);
preTasks = [ ];
postTasks = [ 'injector' ];
break;
}
var tasks = preTasks.concat(baseTasks).concat(postTasks);
console.log(tasks);
return grunt.task.run(tasks);
});
grunt.registerTask('default', [
'build:dev'
]);
grunt.registerTask('Serve-Prod', [
'build:prod'
]);
/*
grunt.registerTask('build', [
'clean:dist',
'compass:clean',
'compass:dist',
'copy:styles',
'imagemin',
'svgmin',
'injector',
'autoprefixer',
'ngAnnotate',
'copy:dist',
'cssmin',
'uglify',
'htmlmin'
]);//*/
};
I'm having issues with my grunt serve task. It seems to hang when it gets to the express:dev task;
Running "express:dev" (express) task
Starting background Express server
Debugger listening on port 5858
This an existing project where grunt serve used to work fine. This issue started yesterday when my Mac ran out of power mid process; in my head its either that or I have inadvertently changed something and broken it just before the mac went down and the power thing is just coincidence.
Has anyone got any ideas?
'use strict';
module.exports = function(grunt) {
require('load-grunt-tasks')(grunt);
var deploySettings = grunt.file.readJSON('config.json'),
deploy = deploySettings.production;
var useminSettings = []
var appConfig = {
app: require('./bower.json').appPath || 'app',
dist: 'dist' //require('./bower.json').distPath ||
};
grunt.initConfig({
mainApp: appConfig,
express: {
options: {
port: process.env.PORT || 9000
},
dev: {
options: {
script: 'app.js',
debug: true,
node_env: 'development',
livereload:true,
serverreload: true
}
},
prod: {
options: {
script: 'dist/app.js',
node_env: 'production'
}
}
},
watch: {
bower: {
files: ['bower.json'],
tasks: ['wiredep']
},
js : {
files: ['<%= mainApp.app %>/js/**/*.js'],
tasks: ['newer:jshint:all'],
options: {
livereload: true //'<%= connect.options.livereload %>'
}
},
gruntfile: {
files: ['Gruntfile.js']
},
less: {
files: ['<%= mainApp.app %>/css/**/*.less'],
tasks: ['less:development']
},
livereload: {
options: {
livereload : true //'<%= connect.options.livereload %>'
},
files: [
'<%= mainApp.app %>/**/*.html',
'<%= mainApp.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
},
express: {
files: [
'server/**/*.{js,json}'
],
tasks: ['less:development','express:dev', 'wait'],
options: {
livereload: true,
nospawn: true //Without this option specified express won't be reloaded
}
}
},
// The actual grunt server settings
/*
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: '0.0.0.0',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
}
}
}
},
*/
// Automatically inject Bower components into the app
wiredep: {
app: {
src: ['<%= mainApp.app %>/index.html']
//ignorePath: /\.\.\//
}
},
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all: {
src: [
'Gruntfile.js',
'<%= mainApp.app %>/js/{,*/}*.js'
]
}
},
//compiles our less down
less : {
development:{
options:{
path: '<%= mainApp.app %>/css/main.less',
rootPath: '/css/',
relativeUrls: false
},
files: {
'<%= mainApp.app %>/css/main.css' : '<%= mainApp.app %>/css/main.less'
}
}
},
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src : [
'.tmp',
'<%= mainApp.dist %>/{,*/}*',
'<%= mainApp.dist %>/.git*'
]
}]
},
server: '.tmp'
},
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
html: '<%= mainApp.app %>/index.html',
options: {
dest: '<%= mainApp.dist %>/public',
flow: {
html: {
steps: {
js: ['concat', 'uglifyjs'],
css: ['cssmin']
},
post: {}
}
}
}
},
// Add vendor prefixed styles
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '<%= mainApp.dist %>/public/styles/'
}]
}
},
// ng-annotate tries to make the code safe for minification automatically
// by using the Angular long form for dependency injection.
ngAnnotate: {
dist: {
files: [{
expand: true,
cwd: '.tmp/concat/scripts',
src: ['*.js'],
dest: '.tmp/concat/scripts'
}]
}
},
//copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= mainApp.app %>',
dest: '<%= mainApp.dist %>/public',
src:[
'*.html',
'views/partials/{,*/}*.html',
'static/img/{,*/}*.{png,jpg,jpeg,gif,ico,svg}',
'css/fonts/{,*/}*.{ttf,woff,eot,otf}'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= mainApp.dist %>/public/images',
src: ['generated/*']
}, {
expand: true,
cwd: 'public/bower_components/bootstrap/dist',
src: 'fonts/{,*/}*.{ttf,woff,eot,otf}',
dest: '<%= mainApp.dist %>/public'
}, {
expand: true,
dest: '<%= mainApp.dist %>',
src: [
'app.js',
'package.json',
'server/**/*'
]
}]
},
debug: {
files: [{
expand: true,
dot: true,
cwd: '<%= mainApp.app %>',
dest: '<%= mainApp.dist %>',
src:[
'*.html',
'views/partials/{,*/}*.html',
'js/{,*/}*.js',
'css/{,*/}*.css',
'static/img/{,*/}*.{png,jpg,jpeg,gif}',
'css/fonts/{,*/}*.{ttf,woff,eot,otf}'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= mainApp.dist %>/images',
src: ['generated/*']
}, {
expand: true,
cwd: 'public/bower_components/bootstrap/dist',
src: 'fonts/{,*/}*.{ttf,woff,eot,otf}',
dest: '<%= mainApp.dist %>'
}]
},
styles : {
expand: true,
cwd: '<%= mainApp.app %>/styles',
dest: '.tmp/styles',
src: '{,*/}*.css'
}
},
// Run some tasks in parallel to speed up the build process
concurrent: {
dist:[
'copy:styles'
]
},
// Replace Google CDN references
cdnify: {
dist: {
html: ['<%= mainApp.dist %>/public/*.html']
}
},
// Renames files for browser caching purposes
filerev: {
dist: {
src: [
'<%= mainApp.dist %>/public/scripts/{,*/}*.js',
'<%= mainApp.dist %>/public/styles/{,*/}*.css'
// '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
// '<%= yeoman.dist %>/styles/fonts/*'
]
}
},
// Performs rewrites based on filerev and the useminPrepare configuration
usemin: {
html: ['<%= mainApp.dist %>/public/{,*/}*.html'],
css: ['<%= mainApp.dist %>/public/styles/{,*/}*.css'],
options: {
assetsDirs: ['<%= mainApp.dist %>/public']
}
},
htmlmin: {
dist: {
options: {
collapseWhitespace: true,
conservativeCollapse: true,
collapseBooleanAttributes: true,
removeCommentsFromCDATA: true,
removeOptionalTags: true
},
files: [{
expand: true,
cwd: '<%= mainApp.dist %>',
src: ['*.html', 'views/partials{,*/}*.html'],
dest: '<%= mainApp.dist %>/public'
}]
}
},
imagemin : {
dynamic: { // Another target
files: [{
expand: true, // Enable dynamic expansion
cwd: '<%= mainApp.dist %>/public/static', // Src matches are relative to this path
src: ['**/*.{png,jpg,gif}'], // Actual patterns to match
dest: '<%= mainApp.dist %>/public/static' // Destination path prefix
}]
}
},
});
// Used for delaying livereload until after server has restarted
grunt.registerTask('wait', function () {
grunt.log.ok('Waiting for server reload...');
var done = this.async();
setTimeout(function () {
grunt.log.writeln('Done waiting!');
done();
}, 1500);
});
grunt.registerTask('express-keepalive', 'Keep grunt running', function() {
this.async();
});
grunt.registerTask('serve', 'Compile then start a connect web server', function(){
grunt.task.run([
'clean:server',
'less:development',
'wiredep',
// 'concurrent:server',
//'connect:livereload',
'express:dev',
//'express-keepalive',
'wait',
'watch'
]);
});
grunt.registerTask('build', function(){
grunt.task.run([
'clean:dist',
'less:development',
'wiredep',
'useminPrepare',
'concurrent:dist',
'copy:styles',
'autoprefixer',
'concat',
'ngAnnotate',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'filerev',
'usemin',
'htmlmin',
'express:dev'
]);
});
grunt.registerTask('debug', [
'clean:dist',
'less:development',
'wiredep',
'copy:debug'
]);
grunt.registerTask('default', [
'serve'
]);
};
I found the solution to this by reverting to a previous git and manually adding changed.
Somehow it was an issue with node-scheduler. I was scheduling a task using a recurrence rule for dayOfWeek = 7. This was producing the error in grunt serve, nothing to do with the grunt file as it happens.
I changed this to dayOfWeek = 0 and it was fine.
If I use any grunt task it throws this error. Someone on the irc channel said it was possible that my gruntfile was corrupt, but there is no information on the internet that could help me learn to fix this issue
Warning: Task "(some task)" not found. Use --force to continue.
Aborted due to warnings.
Execution Time (2014-07-22 18:06:52 UTC)
loading tasks 5ms ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 28%
serve 12ms ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 67%
Total 18ms
If I do grunt serve the error says that task "clean:server can be found".
but my gruntfile contains clean server
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= config.dist %>/*',
'!<%= config.dist %>/.git*'
]
}]
},
server: '.tmp'
}
Here is the entire gruntfile.js
// Generated on 2014-07-22 using generator-webapp 0.4.9
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
// Configurable paths
var config = {
app: 'app',
dist: 'dist'
};
// Define the configuration for all the tasks
grunt.initConfig({
// Project settings
config: config,
// Watches files for changes and runs tasks based on the changed files
watch: {
bower: {
files: ['bower.json'],
tasks: ['bowerInstall']
},
js: {
files: ['<%= config.app %>/scripts/{,*/}*.js'],
tasks: ['jshint'],
options: {
livereload: true
}
},
jstest: {
files: ['test/spec/{,*/}*.js'],
tasks: ['test:watch']
},
gruntfile: {
files: ['Gruntfile.js']
},
sass: {
files: ['<%= config.app %>/styles/{,*/}*.{scss,sass}'],
tasks: ['sass:server', 'autoprefixer']
},
styles: {
files: ['<%= config.app %>/styles/{,*/}*.css'],
tasks: ['newer:copy:styles', 'autoprefixer']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= config.app %>/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'<%= config.app %>/images/{,*/}*'
]
}
},
// The actual grunt server settings
connect: {
options: {
port: 9000,
open: true,
livereload: 35729,
// Change this to '0.0.0.0' to access the server from outside
hostname: 'localhost'
},
livereload: {
options: {
middleware: function(connect) {
return [
connect.static('.tmp'),
connect().use('/bower_components', connect.static('./bower_components')),
connect.static(config.app)
];
}
}
},
test: {
options: {
open: false,
port: 9001,
middleware: function(connect) {
return [
connect.static('.tmp'),
connect.static('test'),
connect().use('/bower_components', connect.static('./bower_components')),
connect.static(config.app)
];
}
}
},
dist: {
options: {
base: '<%= config.dist %>',
livereload: false
}
}
},
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= config.dist %>/*',
'!<%= config.dist %>/.git*'
]
}]
},
server: '.tmp'
},
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all: [
'Gruntfile.js',
'<%= config.app %>/scripts/{,*/}*.js',
'!<%= config.app %>/scripts/vendor/*',
'test/spec/{,*/}*.js'
]
},
// Mocha testing framework configuration options
mocha: {
all: {
options: {
run: true,
urls: ['http://<%= connect.test.options.hostname %>:<%= connect.test.options.port %>/index.html']
}
}
},
// Compiles Sass to CSS and generates necessary files if requested
sass: {
options: {
loadPath: [
'bower_components'
]
},
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/styles',
src: ['*.scss'],
dest: '.tmp/styles',
ext: '.css'
}]
},
server: {
files: [{
expand: true,
cwd: '<%= config.app %>/styles',
src: ['*.scss'],
dest: '.tmp/styles',
ext: '.css'
}]
}
},
// Add vendor prefixed styles
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
// Automatically inject Bower components into the HTML file
bowerInstall: {
app: {
src: ['<%= config.app %>/index.html'],
exclude: ['bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap.js']
},
sass: {
src: ['<%= config.app %>/styles/{,*/}*.{scss,sass}']
}
},
// Renames files for browser caching purposes
rev: {
dist: {
files: {
src: [
'<%= config.dist %>/scripts/{,*/}*.js',
'<%= config.dist %>/styles/{,*/}*.css',
'<%= config.dist %>/images/{,*/}*.*',
'<%= config.dist %>/styles/fonts/{,*/}*.*',
'<%= config.dist %>/*.{ico,png}'
]
}
}
},
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
options: {
dest: '<%= config.dist %>'
},
html: '<%= config.app %>/index.html'
},
// Performs rewrites based on rev and the useminPrepare configuration
usemin: {
options: {
assetsDirs: ['<%= config.dist %>', '<%= config.dist %>/images']
},
html: ['<%= config.dist %>/{,*/}*.html'],
css: ['<%= config.dist %>/styles/{,*/}*.css']
},
// The following *-min tasks produce minified files in the dist folder
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/images',
src: '{,*/}*.{gif,jpeg,jpg,png}',
dest: '<%= config.dist %>/images'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/images',
src: '{,*/}*.svg',
dest: '<%= config.dist %>/images'
}]
}
},
htmlmin: {
dist: {
options: {
collapseBooleanAttributes: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
removeCommentsFromCDATA: true,
removeEmptyAttributes: true,
removeOptionalTags: true,
removeRedundantAttributes: true,
useShortDoctype: true
},
files: [{
expand: true,
cwd: '<%= config.dist %>',
src: '{,*/}*.html',
dest: '<%= config.dist %>'
}]
}
},
// By default, your `index.html`'s <!-- Usemin block --> will take care of
// minification. These next options are pre-configured if you do not wish
// to use the Usemin blocks.
// cssmin: {
// dist: {
// files: {
// '<%= config.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css',
// '<%= config.app %>/styles/{,*/}*.css'
// ]
// }
// }
// },
// uglify: {
// dist: {
// files: {
// '<%= config.dist %>/scripts/scripts.js': [
// '<%= config.dist %>/scripts/scripts.js'
// ]
// }
// }
// },
// concat: {
// dist: {}
// },
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= config.app %>',
dest: '<%= config.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'images/{,*/}*.webp',
'{,*/}*.html',
'styles/fonts/{,*/}*.*'
]
}]
},
styles: {
expand: true,
dot: true,
cwd: '<%= config.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
// Generates a custom Modernizr build that includes only the tests you
// reference in your app
modernizr: {
dist: {
devFile: 'bower_components/modernizr/modernizr.js',
outputFile: '<%= config.dist %>/scripts/vendor/modernizr.js',
files: {
src: [
'<%= config.dist %>/scripts/{,*/}*.js',
'<%= config.dist %>/styles/{,*/}*.css',
'!<%= config.dist %>/scripts/vendor/*'
]
},
uglify: true
}
},
// Run some tasks in parallel to speed up build process
concurrent: {
server: [
'copy:styles'
],
test: [
'copy:styles'
],
dist: [
'sass',
'copy:styles',
'imagemin',
'svgmin'
]
}
});
grunt.registerTask('serve', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
grunt.registerTask('server', function (target) {
grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
grunt.task.run([target ? ('serve:' + target) : 'serve']);
});
grunt.registerTask('test', function (target) {
if (target !== 'watch') {
grunt.task.run([
'clean:server',
'concurrent:test',
'autoprefixer'
]);
}
grunt.task.run([
'connect:test',
'mocha'
]);
});
grunt.registerTask('build', [
'clean:dist',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'cssmin',
'uglify',
'copy:dist',
'modernizr',
'rev',
'usemin',
'htmlmin'
]);
grunt.registerTask('default', [
'newer:jshint',
'test',
'build'
]);
};
May be you accidentally deleted some file in the node_modules/grunt-contrib-clean directory.
Delete this dir and repeat the npm install. I also detected the problem and this worked for me.
I used Yeoman to scaffold my site. I want to use jade templates which so far is half working, my jade files go to the tmp as html files folder and livereload is displaying this fine, but when I run grunt to build my site the html files from folder .tmp do not get placed into my public_html folder. All other folders/assets as expected are going to public_html.
Here is my folder structure apologies for the bad illustration:
site name
---- .sass cache
---- .tmp
app
---- bower_components
---- images
---- jade
---- scripts
---- styles
public_html
---- bower_components
---- scripts
---- styles
// Generated on 2013-11-11 using generator-webapp 0.4.3
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
// show elapsed time at the end
require('time-grunt')(grunt);
// load all grunt tasks
require('load-grunt-tasks')(grunt);
grunt.initConfig({
// configurable paths
site_name: {
app: 'app',
public_html: 'public_html'
},
watch: {
compass: {
files: ['<%= site_name.app %>/styles/{,*/}*.{scss,sass}'],
tasks: ['compass:server', 'autoprefixer']
},
styles: {
files: ['<%= site_name.app %>/styles/{,*/}*.css'],
tasks: ['copy:styles', 'autoprefixer']
},
jade: {
files: ['<%= site_name.app %>/jade/{,*/}*.jade'],
tasks: ['jade']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'.tmp/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'{.tmp,<%= site_name.app %>}/scripts/{,*/}*.js',
'<%= site_name.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
connect: {
options: {
port: 9000,
livereload: 35729,
// change this to '0.0.0.0' to access the server from outside
hostname: 'localhost'
},
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= site_name.app %>'
]
}
},
test: {
options: {
base: [
'.tmp',
'test',
'<%= site_name.app %>'
]
}
},
public_html: {
options: {
open: true,
base: '<%= site_name.public_html %>'
}
}
},
clean: {
public_html: {
files: [{
dot: true,
src: [
'.tmp',
'<%= site_name.public_html %>/*',
'!<%= site_name.public_html %>/.git*'
]
}]
},
server: '.tmp'
},
jshint: {
options: {
jshintrc: '.jshintrc'
},
all: [
'Gruntfile.js',
'<%= site_name.app %>/scripts/{,*/}*.js',
'!<%= site_name.app %>/scripts/vendor/*',
'test/spec/{,*/}*.js'
]
},
mocha: {
all: {
options: {
run: true,
urls: ['http://<%= connect.test.options.hostname %>:<%= connect.test.options.port %>/index.html']
}
}
},
compass: {
options: {
sassDir: '<%= site_name.app %>/styles',
cssDir: '.tmp/styles',
generatedImagesDir: '.tmp/images/generated',
imagesDir: '<%= site_name.app %>/images',
javascriptsDir: '<%= site_name.app %>/scripts',
fontsDir: '<%= site_name.app %>/styles/fonts',
importPath: '<%= site_name.app %>/bower_components',
httpImagesPath: '/images',
httpGeneratedImagesPath: '/images/generated',
httpFontsPath: '/styles/fonts',
relativeAssets: false,
assetCacheBuster: false
},
public_html: {
options: {
generatedImagesDir: '<%= site_name.public_html %>/images/generated'
}
},
server: {
options: {
debugInfo: true
}
}
},
autoprefixer: {
options: {
browsers: ['last 1 version']
},
public_html: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
// not used since Uglify task does concat,
// but still available if needed
/*concat: {
public_html: {}
},*/
'bower-install': {
app: {
html: '<%= site_name.app %>/index.html',
ignorePath: '<%= site_name.app %>/'
}
},
// not enabled since usemin task does concat and uglify
// check index.html to edit your build targets
// enable this task if you prefer defining your build targets here
/*uglify: {
public_html: {}
},*/
rev: {
public_html: {
files: {
src: [
'<%= site_name.public_html %>/scripts/{,*/}*.js',
'<%= site_name.public_html %>/styles/{,*/}*.css',
'<%= site_name.public_html %>/images/{,*/}*.{png,jpg,jpeg,gif,webp}',
'<%= site_name.public_html %>/styles/fonts/{,*/}*.*'
]
}
}
},
jade: {
public_html: {
options: {
pretty: true
},
files: [{
expand: true,
cwd: '<%= site_name.app %>/jade',
dest: '.tmp',
src: '{,*/}*.jade',
ext: '.html'
}]
}
},
useminPrepare: {
options: {
dest: '<%= site_name.public_html %>'
},
html: '<%= site_name.app %>/index.html'
},
usemin: {
options: {
dirs: ['<%= site_name.public_html %>']
},
html: ['<%= site_name.public_html %>/{,*/}*.html'],
css: ['<%= site_name.public_html %>/styles/{,*/}*.css']
},
imagemin: {
public_html: {
files: [{
expand: true,
cwd: '<%= site_name.app %>/images',
src: '{,*/}*.{png,jpg,jpeg}',
dest: '<%= site_name.public_html %>/images'
}]
}
},
svgmin: {
public_html: {
files: [{
expand: true,
cwd: '<%= site_name.app %>/images',
src: '{,*/}*.svg',
dest: '<%= site_name.public_html %>/images'
}]
}
},
cssmin: {
// This task is pre-configured if you do not wish to use Usemin
// blocks for your CSS. By default, the Usemin block from your
// `index.html` will take care of minification, e.g.
//
// <!-- build:css({.tmp,app}) styles/main.css -->
//
// public_html: {
// files: {
// '<%= site_name.public_html %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css',
// '<%= site_name.app %>/styles/{,*/}*.css'
// ]
// }
// }
},
htmlmin: {
public_html: {
options: {
/*removeCommentsFromCDATA: true,
// https://github.com/murata/grunt-usemin/issues/44
//collapseWhitespace: true,
collapseBooleanAttributes: true,
removeAttributeQuotes: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeOptionalTags: true*/
},
files: [{
expand: true,
cwd: '.tmp',
src: '*.html',
dest: '<%= site_name.public_html %>'
}]
}
},
// Put files not handled in other tasks here
copy: {
public_html: {
files: [{
expand: true,
dot: true,
cwd: '<%= site_name.app %>',
dest: '<%= site_name.public_html %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'images/{,*/}*.{webp,gif}',
'styles/fonts/{,*/}*.*',
'bower_components/sass-bootstrap/fonts/*.*'
]
}]
},
styles: {
expand: true,
dot: true,
cwd: '<%= site_name.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
modernizr: {
devFile: '<%= site_name.app %>/bower_components/modernizr/modernizr.js',
outputFile: '<%= site_name.public_html %>/bower_components/modernizr/modernizr.js',
files: [
'<%= site_name.public_html %>/scripts/{,*/}*.js',
'<%= site_name.public_html %>/styles/{,*/}*.css',
'!<%= site_name.public_html %>/scripts/vendor/*'
],
uglify: true
},
concurrent: {
server: [
'compass',
'copy:styles'
],
test: [
'copy:styles'
],
public_html: [
'compass',
'copy:styles',
'imagemin',
'svgmin',
'htmlmin'
]
}
});
grunt.registerTask('server', function (target) {
if (target === 'public_html') {
return grunt.task.run(['build', 'connect:public_html:keepalive']);
}
grunt.task.run([
'clean:server',
'jade',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
grunt.registerTask('test', [
'clean:server',
'concurrent:test',
'autoprefixer',
'connect:test',
'mocha'
]);
grunt.registerTask('build', [
'clean:public_html',
'useminPrepare',
'concurrent:public_html',
'jade',
'autoprefixer',
'concat',
'cssmin',
'uglify',
'modernizr',
'copy:public_html',
'rev',
'usemin'
]);
grunt.registerTask('default', [
/*'jshint',*/
'test',
'build'
]);
};
What happens when you run grunt htmlmin?
I'm thinking that the htmlmin task isn't running, for some reason. Perhaps it's not running because of the concurrent task, as in this other SO answer:
Grunt build - Running "concurrent:dist" (concurrent) task Killed
Notice that in your gruntfile, the htmlmin declaration copies html files from .tmp into <%= site_name.public_html %>.
You might also try grunt build --force to make grunt continue through any errors that may be preventing grunt from eventually running htmlmin.
Think your issue is in your htmlmin task
htmlmin: {
public_html: {
options: {
/*removeCommentsFromCDATA: true,
// https://github.com/murata/grunt-usemin/issues/44
//collapseWhitespace: true,
collapseBooleanAttributes: true,
removeAttributeQuotes: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeOptionalTags: true*/
},
files: [{
expand: true,
cwd: '.tmp',
src: '*.html',
dest: '<%= site_name.public_html %>'
}]
}
},
needs / at end of '<%= site_name.public_html %>' eg
dest: '<%= site_name.public_html %>/'
maybe ?
http://www.sitepoint.com/kickstart-your-angularjs-development-with-yeoman-grunt-and-bower
After following this interesting guide about Angular, Yeoman, Bower and Grunt I was able tot bootstrap an Angular application.
Everything works fine except the testing with Karma. When I run:
grunt test
I get the following error:
Warning: Task "karma" not found. Used --force, continuing.
Done, but with warnings
I checked if I have installed Karma, but that is installed. For Grunt it appears you need to install grunt-karma. So I tried that throughout the following command:
npm install grunt-karma --save-dev
This gives me errrors like:
errno: 53,
code: 'ENOTEMPTY',
path: 'C:\\tmp\\phantomjs\\phantom-1.9.2-windows-.zip-extract-' ..
I am on Windows and executing commands from the powershell.
Hope someone can help.
Edit karma.conf.js and gruntfile
// Karma configuration
// http://karma-runner.github.io/0.10/config/configuration-file.html
module.exports = function(config) {
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
// testing framework to use (jasmine/mocha/qunit/...)
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'app/bower_components/angular/angular.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/bower_components/angular-resource/angular-resource.js',
'app/bower_components/angular-cookies/angular-cookies.js',
'app/bower_components/angular-sanitize/angular-sanitize.js',
'app/scripts/*.js',
'app/scripts/**/*.js',
'test/mock/**/*.js',
'test/spec/**/*.js'
],
// list of files / patterns to exclude
exclude: [],
// web server port
port: 8080,
// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: ['Chrome'],
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: false
});
};
Gruntfile
// Generated on 2013-11-02 using generator-angular 0.5.1
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-karma');
require('load-grunt-tasks')(grunt);
require('time-grunt')(grunt);
grunt.initConfig({
yeoman: {
// configurable paths
app: require('./bower.json').appPath || 'app',
dist: 'dist'
},
watch: {
coffee: {
files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'],
tasks: ['coffee:dist']
},
coffeeTest: {
files: ['test/spec/{,*/}*.coffee'],
tasks: ['coffee:test']
},
compass: {
files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
tasks: ['compass:server', 'autoprefixer']
},
styles: {
files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
tasks: ['copy:styles', 'autoprefixer']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= yeoman.app %>/{,*/}*.html',
'.tmp/styles/{,*/}*.css',
'{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js',
'<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
autoprefixer: {
options: ['last 1 version'],
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= yeoman.app %>'
]
}
},
test: {
options: {
port: 9001,
base: [
'.tmp',
'test',
'<%= yeoman.app %>'
]
}
},
dist: {
options: {
base: '<%= yeoman.dist %>'
}
}
},
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/*',
'!<%= yeoman.dist %>/.git*'
]
}]
},
server: '.tmp'
},
jshint: {
options: {
jshintrc: '.jshintrc'
},
all: [
'Gruntfile.js',
'<%= yeoman.app %>/scripts/{,*/}*.js'
]
},
coffee: {
options: {
sourceMap: true,
sourceRoot: ''
},
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/scripts',
src: '{,*/}*.coffee',
dest: '.tmp/scripts',
ext: '.js'
}]
},
test: {
files: [{
expand: true,
cwd: 'test/spec',
src: '{,*/}*.coffee',
dest: '.tmp/spec',
ext: '.js'
}]
}
},
compass: {
options: {
sassDir: '<%= yeoman.app %>/styles',
cssDir: '.tmp/styles',
generatedImagesDir: '.tmp/images/generated',
imagesDir: '<%= yeoman.app %>/images',
javascriptsDir: '<%= yeoman.app %>/scripts',
fontsDir: '<%= yeoman.app %>/styles/fonts',
importPath: '<%= yeoman.app %>/bower_components',
httpImagesPath: '/images',
httpGeneratedImagesPath: '/images/generated',
httpFontsPath: '/styles/fonts',
relativeAssets: false
},
dist: {},
server: {
options: {
debugInfo: true
}
}
},
// not used since Uglify task does concat,
// but still available if needed
/*concat: {
dist: {}
},*/
rev: {
dist: {
files: {
src: [
'<%= yeoman.dist %>/scripts/{,*/}*.js',
'<%= yeoman.dist %>/styles/{,*/}*.css',
'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/styles/fonts/*'
]
}
}
},
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>'
}
},
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*.html'],
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
options: {
dirs: ['<%= yeoman.dist %>']
}
},
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.{png,jpg,jpeg}',
dest: '<%= yeoman.dist %>/images'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.svg',
dest: '<%= yeoman.dist %>/images'
}]
}
},
cssmin: {
// By default, your `index.html` <!-- Usemin Block --> will take care of
// minification. This option is pre-configured if you do not wish to use
// Usemin blocks.
// dist: {
// files: {
// '<%= yeoman.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css',
// '<%= yeoman.app %>/styles/{,*/}*.css'
// ]
// }
// }
},
htmlmin: {
dist: {
options: {
/*removeCommentsFromCDATA: true,
// https://github.com/yeoman/grunt-usemin/issues/44
//collapseWhitespace: true,
collapseBooleanAttributes: true,
removeAttributeQuotes: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeOptionalTags: true*/
},
files: [{
expand: true,
cwd: '<%= yeoman.app %>',
src: ['*.html', 'views/*.html'],
dest: '<%= yeoman.dist %>'
}]
}
},
// Put files not handled in other tasks here
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'bower_components/**/*',
'images/{,*/}*.{gif,webp}',
'styles/fonts/*'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= yeoman.dist %>/images',
src: [
'generated/*'
]
}]
},
styles: {
expand: true,
cwd: '<%= yeoman.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
concurrent: {
server: [
'coffee:dist',
'compass:server',
'copy:styles'
],
test: [
'coffee',
'compass',
'copy:styles'
],
dist: [
'coffee',
'compass:dist',
'copy:styles',
'imagemin',
'svgmin',
'htmlmin'
]
},
karma: {
unit: {
configFile: 'karma.conf.js',
singleRun: true
}
},
cdnify: {
dist: {
html: ['<%= yeoman.dist %>/*.html']
}
},
ngmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.dist %>/scripts',
src: '*.js',
dest: '<%= yeoman.dist %>/scripts'
}]
}
},
uglify: {
dist: {
files: {
'<%= yeoman.dist %>/scripts/scripts.js': [
'<%= yeoman.dist %>/scripts/scripts.js'
]
}
}
}
});
grunt.registerTask('server', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
grunt.registerTask('test', [
'clean:server',
'concurrent:test',
'autoprefixer',
'connect:test',
'karma'
]);
grunt.registerTask('build', [
'clean:dist',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'copy:dist',
'cdnify',
'ngmin',
'cssmin',
'uglify',
'rev',
'usemin'
]);
grunt.registerTask('default', [
'jshint',
'test',
'build'
]);
};
Download phantomjs package from https://github.com/Obvious/phantomjs
Unpack and copy it into node_modules of your project.
Run below command gain:
npm install grunt-karma --save-dev
Hope this help.
I had to turn off antivirus (Eset).
The only solution for me that work is:
sudo npm install grunt-karma karma karma-phantomjs-launcher karma-jasmine jasmine-core phantomjs-prebuilt --save-dev
grunt test
or:
grunt serve,
it's work !