I'm using grunt and yeoman in an AngularJS application. grunt version is 0.4.5. When I run "grunt bower-install" it changes the order of the script tags in my index.html, and the new order is wrong:
<!-- bower:js -->
<script src="vendor/jquery/jquery.js"></script>
<script src="vendor/sass-bootstrap-compass/dist/js/sass-bootstrap.js"></script>
<script src="vendor/angular-route/angular-route.js"></script>
<script src="vendor/angular-resource/angular-resource.js"></script>
<script src="vendor/angular-cookies/angular-cookies.js"></script>
<script src="vendor/angular/angular.js"></script>
<script src="vendor/angular-sanitize/angular-sanitize.js"></script>
<!-- endbower -->
As you can see angular.js comes after most of the angular modules. This results in errors when running the application. Manually shifting angular.js to just below jquery.js solves the issue, but this is no permanent solution ofcourse.
How can I tell grunt to put angular.js above the angular-modules?
Thanks
grunt-file:
// Generated on 2014-01-14
'use strict';
module.exports = function (grunt) {
//Loads all grunt tasks from package.json with globbing pattern.
require('load-grunt-tasks')(grunt);
//required for tailing
var fs = require('fs');
//required for tailing
var path = require('path');
grunt.initConfig(
{
yeoman: {
// configurable paths
app: 'src',
test: 'test',
dist: 'dist',
log: 'log'
},
autoprefixer: {
options: {
browser: ['last 2 version', 'ie 8', 'ie 9']
},
dev: {
expand: true,
src: '<%= yeoman.app %>/style/*.css'
},
dist: {
expand: false,
src: '<%= yeoman.dist %>/style/*.css'
}
},
//Checks javascript files for common errors
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: 'jshint/jshintreporter.js',
reporterOutput: 'log/jshint.log'
},
//Lint the app javascript
app: ['<%= yeoman.app %>/app/{,*/}*.js'],
//Lint the test javascript, excluding test coverage files
test: ['<%= yeoman.test %>/**/*.js', '!<%= yeoman.test %>/coverage/**/*.*'],
//Lint the gruntfile, app javascript, and test javascript, excluding test coverage
all: [
'Gruntfile.js',
'<%= yeoman.app %>/app/**/*.js',
'<%= yeoman.test %>/**/*.js',
'!<%= yeoman.test %>/coverage/**/*.*'
]
},
/*Building distributable*/
//Removes tmp files generated by concat, and clear the dist folder
clean: {
dist: '<%= yeoman.dist %>',
tmp: '.tmp'
},
//copy files from the source to the dist folder
copy: {
dist: {
files: [
{
expand: true,
cwd: '<%= yeoman.app %>',
src: ['favicon.ico', '**/*.html', '**/images/**', '**/fonts/**', 'style/*.css', 'polyfills/**', '**/*.json', '!vendor/**'],
dest: '<%= yeoman.dist %>'
},
{
expand: true,
cwd: '<%= yeoman.app %>/vendor/components-font-awesome',
src: ['fonts/**'],
dest: '<%= yeoman.dist %>'
}
]
}
},
//Puts javascript and css links in an html file in the defined <!-- bower --> blocks
'bower-install': {
target: {
// Point to the html file that should be updated
// when you run `grunt bower-install`
html: '<%= yeoman.app %>/index.html',
// Optional:
// If your file paths shouldn't contain a certain
// portion of a url, it can be excluded
ignorePath: '<%= yeoman.app %>/'
// Customize how your stylesheets are included on
// your page.
//
// default: '<link rel="stylesheet" href="{{filePath}}" />'
// cssPattern: '<link href="{{filePath}}" rel="stylesheet"/>',
// Customize how your <script>s are included into
// your HTML file.
//
// default: '<script src="{{filePath}}"></script>'
//jsPattern: '<script src="{{filePath}}" type="text/javascript"></script>'
}
},
compass: {
dev: {
options: {
outputStyle: 'expanded',
sassDir: '<%= yeoman.app %>/style/sass/',
cssDir: '<%= yeoman.app %>/style'
}
},
distClean: {
options: {
outputStyle: 'compressed',
sassDir: '<%= yeoman.app %>/style/sass',
cssDir: '<%= yeoman.app %>/style',
clean: true
}
},
dist: {
options: {
outputStyle: 'compressed',
sassDir: '<%= yeoman.app %>/style/sass',
cssDir: '<%= yeoman.app %>/style'
}
}
},
uglify: {
options: {
mangle: false,
beautify: true,
preserveComments: true
}
},
//Generates config for concat, cssmin, and uglify tasks
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>',
flow: {
steps: {js: ['concat', 'uglifyjs'], css: ['concat', 'cssmin']},
post: {}
}
}
},
//Runs the generated config from useminPrepare on concat, cssmin, and uglify on the <!-- build --> blocks
usemin: {
//html: ['<%= yeoman.dist %>/**/*.html'],
html: ['<%= yeoman.dist %>/index.html'],
css: ['<%= yeoman.dist %>/style/*.css'],
options: {
assetsDirs: ['<%= yeoman.dist %>', '<%= yeoman.dist %>/images'],
basedir: ['<%= yeoman.dist %>']
}
},
//Optimizes images
imagemin: {
dist: {
files: [
{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '**/*.{png,jpg,jpeg,gif}',
dest: '<%= yeoman.dist %>/images'
}
]
}
},
//Changes angular code to minification safe angular code
ngmin: {
dist: {
expand: true,
cwd: '.tmp/concat/js',
src: ['*.js'],
dest: '.tmp/concat/js'
}
},
//Adds a hashed revision number to the javascript and css links
rev: {
dist: {
files: {
src: [
'<%= yeoman.dist %>/js/{,*/}*.js',
'<%= yeoman.dist %>/style/{,*/}*.css',
'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif}'
]
}
}
},
/*Development*/
//Watches files for changes, add tasks to run on change detection
watch: {
livereload: {
options: {
livereload: true
},
files: [
'<%= yeoman.app %>/app/**/*.html',
'<%= yeoman.app %>/app/**/*.js',
'<%= yeoman.app %>/style/**/*.css',
'<%= yeoman.app %>/favicon.ico',
'<%= yeoman.app %>/images/**/*.{png,jpg,jpeg}'
]
},
jshint: {
files: '<%= yeoman.app %>/app/{,*/}*.js',
tasks: ['jshint:app']
},
compass: {
files: '<%= yeoman.app %>/style/sass/{,*/}*.{scss,sass}',
tasks: ['compass:dev', 'autoprefixer:dev']
},
'tail': {
files: ['<%= yeoman.log %>/*.log']
}
},
karma: {
options: {
configFile: 'karma.conf.js'
},
dev: {
singleRun: true,
autoWatch: false,
port: 9877
},
dist: {
browsers: ['PhantomJS', 'Chrome', 'Firefox', 'IE'],
singleRun: true,
autoWatch: false,
port: 8765
}
},
//Connects to a grunt development server with live reload (refresh upon change)
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' or '*' to access the server from outside.
hostname: 'localhost',
open: true
},
dev: {
options: {
base: '<%= yeoman.app %>',
livereload: 35729
}
},
dist: {
options: {
base: '<%= yeoman.dist %>'
}
}
},
env: {
prod: {
NODE_ENV: 'PRODUCTION'
}
},
uncode: {
options: {test: 'ok'}
}
});
/* Register public grunt task flows */
grunt.registerTask('default', [
'jshint:app',
'bower-install'//,
//'karma:dist'
]);
grunt.registerTask('dist', [
'default',
'build'
]);
grunt.registerTask('test', [
'karma:dist'
]);
/* Karma should be launched as standalone, with 'start karma start karma.conf.js' for Windows, or 'karma start karma.conf.js &' for *nix systems */
/* Both server tasks should be launched with either 'start grunt server' for Windows, or 'grunt server &' for *nix systems */
grunt.registerTask('serve', [
'connect:dev',
'watch'
]);
grunt.registerTask('dist-server', [
'dist',
'connect:dist:keepalive'
]);
/* Grunt tasks not to be used from the cmd, only in above tasks */
grunt.registerTask('build', [
'clean:dist',
'compass:distClean',
'useminPrepare',
'imagemin',
'compass:dist',
'concat',
'ngmin:dist',
'copy:dist',
'cssmin',
'autoprefixer:dist',
'uglify',
'rev',
'uncode',
'lineFeed',
'usemin',
'clean:tmp'
]);
/* tail the *.log files in /log */
grunt.registerTask('tail', function () {
grunt.task.run(['watch:tail']);
grunt.event.on('watch', function (action, filepath, target) {
grunt.log.writeln(target + ': ' + filepath + ' has ' + action);
fs.readFile(path.join(process.cwd(), filepath), function (err, data) {
console.log(data.toString());
});
});
});
grunt.registerTask('lineFeed', function () {
var fullPath = path.join(process.cwd(), 'dist/index.html');
var index = fs.readFileSync(fullPath, 'utf8');
index = index.split('\r\n').join('\n');
fs.writeFileSync(fullPath, index);
});
grunt.registerTask('uncode', function () {
var fullPath = path.join(process.cwd(), 'dist/index.html');
var index = fs.readFileSync(fullPath, 'utf8');
var startMockers = index.indexOf('<!-- mockers -->');
var endMockersTag = '<!-- endmockers -->';
var endMockers = index.indexOf(endMockersTag);
if (startMockers > 0 && endMockers > startMockers) {
index = index.substring(0, startMockers) + index.substring(endMockers + endMockersTag.length);
fs.writeFileSync(fullPath, index);
console.log('uncoded from ', startMockers, ' to ', endMockers);
} else {
console.log('nothing to uncode...');
}
});
};
bower.json file:
{
"name": "portaal",
"version": "0.0.0",
"dependencies": {
"jquery": "~1.10.2",
"angular": "~1.2.1",
"angular-route": "~1.2.1",
"angular-resource": "~1.2.1",
"components-font-awesome": "~4.0.3",
"angular-cookies": "~1.2.10",
"sass-bootstrap-compass": "~3.0.21",
"angular-translate": "<2",
"angular-translate-loader-static-files": "<2",
"angular-sanitize": "~1.2.19",
"ng-file-upload": "~1.6.3",
"ng-file-upload-shim": "~1.6.3"
},
"devDependencies": {
"angular-mocks": "~1.2.0"
},
"resolutions": {
"angular": "1.2.23"
}
}
I fixed this issue by using the grunt task "grunt-wiredep" instead of "grunt-bower-install".