Search code examples
angularjsgruntjsbower-install

grunt bower-install puts script tags in wrong order


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"
  }
}

Solution

  • I fixed this issue by using the grunt task "grunt-wiredep" instead of "grunt-bower-install".