Grunt usemin: concatenated JavaScript file not replaced in index.html file
Asked Answered
A

5

10

I started with an empty project generated by yeoman, and tried to edit the Gruntfile.js to fit my needs.

The grunt build task reads my index.html file, and concatenates my bower dependencies and generates a .vendor.js file.

I broke something in the workflow, and now usemin does not replace markups in my index.html file, even if the .vendor.js file is generated.

Here is my Gruntfile.js

    'use strict';

    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);

      // Define the configuration for all the tasks
      grunt.initConfig({

        // Project settings
        yeoman: {
          // configurable paths
          app: require('./bower.json').appPath || 'app',
          dist: 'dist',
        },
        express: {
          options: {
            port: process.env.PORT || 9000
          },
          dev: {
            options: {
              script: 'server.js',
              debug: true
            }
          },
          prod: {
            options: {
              script: 'dist/server.js',
              node_env: 'production'
            }
          }
        },
        open: {
          server: {
            url: 'http://localhost:<%= express.options.port %>'
          }
        },

        // Watches files for changes and runs tasks based on the changed files
        watch: {
          js: {
            files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
            tasks: ['newer:jshint:all'],
            options: {
              livereload: true
            }
          },
          jsTest: {
            files: ['test/spec/{,*/}*.js'],
            tasks: ['newer:jshint:test', 'karma']
          },
          compass: {
            files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
            tasks: ['compass:server', 'autoprefixer']
          },
          gruntfile: {
            files: ['Gruntfile.js']
          },
          livereload: {
            files: [
              '<%= yeoman.app %>/views/{,*//*}*.{html,handlebars}',
              '{.tmp,<%= yeoman.app %>}/styles/{,*//*}*.css',
              '{.tmp,<%= yeoman.app %>}/scripts/{,*//*}*.js',
              '<%= yeoman.app %>/images/{,*//*}*.{png,jpg,jpeg,gif,webp,svg}',
              '<%= yeoman.app %>/data/{,*/}*.{png,jpg,jpeg,gif,webp,svg,json,pdf}'
            ],

            options: {
              livereload: true
            }
          },
          express: {
            files: [
              'server.js',
              'lib/**/*.{js,json}'
            ],
            tasks: ['newer:jshint:server', 'express:dev'],
            options: {
              livereload: true,
              nospawn: true //Without this option specified express won't be reloaded
            }
          }
        },

        // Make sure code styles are up to par and there are no obvious mistakes
        jshint: {
          options: {
            jshintrc: '.jshintrc',
            reporter: require('jshint-stylish')
          },
          server: {
            options: {
              jshintrc: 'lib/.jshintrc'
            },
            src: [ 'lib/{,*/}*.js']
          },
          all: [
            '<%= yeoman.app %>/scripts/{,*/}*.js'
          ],
          test: {
            options: {
              jshintrc: 'test/.jshintrc'
            },
            src: ['test/spec/{,*/}*.js']
          }
        },

        // Empties folders to start fresh
        clean: {
          dist: {
            files: [{
              dot: true,
              src: [
                '.tmp',
                '<%= yeoman.dist %>/views/*',
                '<%= yeoman.dist %>/public/*',
                '!<%= yeoman.dist %>/public/.git*',
              ]
            }]
          },
          heroku: {
            files: [{
              dot: true,
              src: [
                'heroku/*',
                '!heroku/.git*',
                '!heroku/Procfile'
              ]
            }]
          },
          server: '.tmp'
        },

        // 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 app
        'bower-install': {
          app: {
            html: '<%= yeoman.app %>/views/edit/index.html',
            ignorePath: '<%= yeoman.app %>/'
          }
        },

        // Compiles Sass to CSS and generates necessary files if requested
        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,
            assetCacheBuster: false,
            raw: 'Sass::Script::Number.precision = 10\n'
          },
          dist: {
            options: {
              generatedImagesDir: '<%= yeoman.dist %>/public/images/generated'
            }
          },
          server: {
            options: {
              debugInfo: true
            }
          }
        },

        // Renames files for browser caching purposes
        rev: {
          dist: {
            files: {
              src: [
                '<%= yeoman.dist %>/public/scripts/{,*/}*.js',
                '<%= yeoman.dist %>/public/styles/{,*/}*.css',
                //'<%= yeoman.dist %>/public/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
                '<%= yeoman.dist %>/public/styles/fonts/*'
              ]
            }
          }
        },

        // The following *-min tasks produce minified files in the dist folder
        imagemin: {
          dist: {
            files: [{
              expand: true,
              cwd: '<%= yeoman.app %>/images',
              src: '{,*/}*.{png,jpg,jpeg,gif}',
              dest: '<%= yeoman.dist %>/public/images'
            }]
          }
        },


        // 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: ['<%= yeoman.app %>/views/edit/index.html'
                 //'<%= yeoman.app %>/../views/index.handlebars'
            ],
          options: {
            dest: '<%= yeoman.dist %>/public'
          }
        },

        // Performs rewrites based on rev and the useminPrepare configuration
        usemin: {
          html: ['<%= yeoman.dist %>/views/edit/index.html',
                 '<%= yeoman.dist %>/views/{,*/}*.handlebars'],
          css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
          options: {
            assetsDirs: ['<%= yeoman.dist %>/public', '<%= yeoman.dist %>/public/images']
          }
        },
        svgmin: {
          dist: {
            files: [{
              expand: true,
              cwd: '<%= yeoman.app %>/images',
              src: '{,*/}*.svg',
              dest: '<%= yeoman.dist %>/public/images'
            }]
          }
        },
        htmlmin: {
          dist: {
            options: {
              //collapseWhitespace: true,
              //collapseBooleanAttributes: true,
              //removeCommentsFromCDATA: true,
              //removeOptionalTags: true
            },
            files: {
              '<%= yeoman.dist %>/public/views/edit/index.html': '<%= yeoman.app %>/views/edit/index.html'
            }
            //files: [{
            //  expand: true,
            //  cwd: '<%= yeoman.app %>/views/edit',
            //  src: ['*.html', 'partials/*.html'],
            //  dest: '<%= yeoman.dist %>/public/views/edit'
            //}]
          }
        },

        // Allow the use of non-minsafe AngularJS files. Automatically makes it
        // minsafe compatible so Uglify does not destroy the ng references
        ngmin: {
          dist: {
            files: [{
              expand: true,
              cwd: '.tmp/concat/scripts',
              src: '*.js',
              dest: '.tmp/concat/scripts'
            }]
          }
        },

        // Replace Google CDN references
        cdnify: {
          dist: {
            html: ['<%= yeoman.dist %>/public/views/edit/*.html']
          }
        },

        // Copies remaining files to places other tasks can use
        copy: {
          dist: {
            files: [{
              expand: true,
              dot: true,
              cwd: '<%= yeoman.app %>',
              dest: '<%= yeoman.dist %>/public',
              src: [
                '*.{ico,png,txt}',
                '.htaccess',
                '*.html',
                //'views/edit/{,*/}*.html',
                //'templates/{,*/}*.html',
                'bower_components/**/*',
                'images/{,*/}*.{webp}',
                'data/{,*/}*.*',
                'fonts/**/*'
              ]
            },
            //{
            //  expand: true,
            //  dot: true,
            //  cwd: '<%= yeoman.app %>/views',
            //  dest: '<%= yeoman.dist %>/views',
            //  src: '**/*.handlebars'
            //},
            {
              expand: true,
              cwd: '.tmp/images',
              dest: '<%= yeoman.dist %>/public/images',
              src: ['generated/*']
      }, {
              expand: true,
              dest: '<%= yeoman.dist %>',
              src: [
                'package.json',
                'server.js',
                'lib/**/*'
              ]
            }]
          },
          styles: {
            expand: true,
            cwd: '<%= yeoman.app %>/styles',
            dest: '.tmp/styles/',
            src: '{,*/}*.css'
          }
        },

        // Run some tasks in parallel to speed up the build process
        concurrent: {
          server: [
            'compass:server'
          ],
          test: [
            'compass'
          ],
          dist: [
            'compass:dist',
            'imagemin',
            'svgmin',
            'htmlmin'
          ]
        },

        // 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: {
        //       '<%= yeoman.dist %>/styles/main.css': [
        //         '.tmp/styles/{,*/}*.css',
        //         '<%= yeoman.app %>/styles/{,*/}*.css'
        //       ]
        //     }
        //   }
        // },
        // uglify: {
        //   dist: {
        //     files: {
        //       '<%= yeoman.dist %>/scripts/scripts.js': [
        //         '<%= yeoman.dist %>/scripts/scripts.js'
        //       ]
        //     }
        //   }
        // },
        //concat: {
        //   dist: {}
        //},

        // Test settings
        karma: {
          unit: {
            configFile: 'karma.conf.js',
            singleRun: true
          }
        }
      });

      grunt.registerTask('express-keepalive', 'Keep grunt running', function() {
        this.async();
      });

      grunt.registerTask('serve', function (target) {
        if (target === 'dist') {
          return grunt.task.run(['build', 'express:prod', 'open', 'express-keepalive']);
        }

        grunt.task.run([
          'clean:server',
          'bower-install',
          'concurrent:server',
          'autoprefixer',
          'express:dev',
          'open',
          'watch'
        ]);
      });

      grunt.registerTask('server', function () {
        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
        grunt.task.run(['serve']);
      });

      grunt.registerTask('test', [
        'clean:server',
        'concurrent:test',
        'autoprefixer',
        'karma'
      ]);

      grunt.registerTask('build', [
        'clean:dist',
        'bower-install',
        'useminPrepare',
        'concurrent:dist',
        'autoprefixer',
        'concat',
        'ngmin',
        'copy:dist',
        'cdnify',
        'cssmin',
        'uglify',
        'rev',
        'usemin'
      ]);


      grunt.registerTask('heroku', function () {
        grunt.log.warn('The `heroku` task has been deprecated. Use `grunt build` to build for deployment.');
        grunt.task.run(['build']);
      });

      grunt.registerTask('default', [
        'newer:jshint',
        'test',
        'build'
      ]);
    };

And here is what is generated when I run grunt:

    tree dist/public/scripts/
    dist/public/scripts/
    ├── 434e7b5e.scripts-edit.js
    └── ad5d9b7c.vendor-edit.js

index.html:

    <!-- build:js(app) scripts/vendor-edit.js -->
    <!-- bower:js-->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="bower_components/angular/angular.js"></script>
    <script src="bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap.js"></script>
    <script src="bower_components/angular-resource/angular-resource.js"></script>
    <script src="bower_components/angular-cookies/angular-cookies.js"></script>
    <script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
    <script src="bower_components/angular-route/angular-route.js"></script>
    <script src="bower_components/angular-animate/angular-animate.js"></script>
    <script src="bower_components/angular-http-auth/src/http-auth-interceptor.js"></script>
    <script src="bower_components/angular-translate/angular-translate.js"></script>
    <script src="bower_components/angular-translate-storage-cookie/angular-translate-storage-cookie.js"></script>
    <script src="bower_components/angular-translate-storage-local/angular-translate-storage-local.js"></script>
    <script src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>
    <script src="bower_components/moment/moment.js"></script>
    <script src="bower_components/angular-moment/angular-moment.js"></script>
    <script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>
    <script src="bower_components/AngularJS-Toaster/toaster.js"></script>
    <!-- endbower -->
    <!-- endbuild -->

And finaly, here is the grunt output

        Running "compass:dist" (compass) task
        directory .tmp/styles/
           create .tmp/styles/edit.css (16.644s)
           create .tmp/styles/webicons.css (0.156s)
           create .tmp/styles/main.css (10.947s)
        Compilation took 27.77s

        Done, without errors.


        Execution Time (2014-03-19 13:47:21 UTC)
        compass:dist  29.1s  ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 100%
        Total 29.2s

        Running "htmlmin:dist" (htmlmin) task
        File dist/public/views/edit/index.html created.

        Done, without errors.


        Execution Time (2014-03-19 13:47:51 UTC)
        loading tasks  13ms  ▇▇▇▇▇▇▇▇▇▇▇▇ 25%
        htmlmin         2ms  ▇▇ 4%
        htmlmin:dist   35ms  ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 67%
        Total 52ms

    Running "autoprefixer:dist" (autoprefixer) task
    Prefixed file ".tmp/styles/edit.css" created.
    Prefixed file ".tmp/styles/main.css" created.
    Prefixed file ".tmp/styles/webicons.css" created.

    Running "concat:generated" (concat) task
    File ".tmp/concat/styles/edit.css" created.
    File ".tmp/concat/scripts/vendor-edit.js" created.
    File ".tmp/concat/scripts/scripts-edit.js" created.

    Running "ngmin:dist" (ngmin) task
    ngminifying .tmp/concat/scripts/scripts-edit.js, .tmp/concat/scripts/vendor-edit.js

    Running "copy:dist" (copy) task
    Created 125 directories, copied 907 files

    Running "cdnify:dist" (cdnify) task
    Going through dist/public/views/edit/index.html to update script refs

    Running "cssmin:generated" (cssmin) task
    File dist/public/styles/edit.css created.

    Running "uglify:generated" (uglify) task
    File "dist/public/scripts/vendor-edit.js" created.
    File "dist/public/scripts/scripts-edit.js" created.

    Running "rev:dist" (rev) task
    dist/public/scripts/scripts-edit.js >> 434e7b5e.scripts-edit.js
    dist/public/scripts/vendor-edit.js >> ad5d9b7c.vendor-edit.js
    dist/public/styles/edit.css >> 9d137efe.edit.css

    Running "usemin:html" (usemin) task

    Running "usemin:css" (usemin) task


    Execution Time (2014-03-19 13:46:43 UTC)
    concurrent:test   20.7s  ▇▇▇▇▇▇▇ 15%
    karma:unit         3.8s  ▇▇ 3%
    concurrent:dist   41.9s  ▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 31%
    ngmin:dist        44.5s  ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 33%
    copy:dist          2.2s  ▇ 2%
    uglify:generated  18.1s  ▇▇▇▇▇▇ 14%
    Total 133.9s

Any help understanding this would be appreciated.

Accolade answered 19/3, 2014 at 14:17 Comment(0)
A
10

I'll answer my own question:

I had a difference between my useminprepare configuration and my usemin configuration.

useminprepare was writing to <%= yeoman.dist %>/public/views/edit/index.html

and usemin was reading from <%= yeoman.dist %>/views/edit/index.html

Accolade answered 26/3, 2014 at 14:50 Comment(2)
Don't forget to accept your own answer if it resolved your problem! (Thanks for posting it, by the way! It was helpful!) :-)Pase
It was indeed. No warnings or errors in the default output of grunt build.Showy
D
4

For some reason, I just had the same problem. During grunt build my index.html wasn't updated (but main.css and main.js were outputted just fine). I tried grunt usemin:html AND THAT WORKED.

So I ended up moving usemin:html to the last place in my grunt build list of tasks.

No idea yet why this was, but it'll get me where I needed to be. In case someone else could find this useful.

Dionysius answered 24/6, 2014 at 1:24 Comment(0)
B
1

I have a similar problem. In my case, everything is replaced as expected except the content inside the bower:css or bower:js tags. It looks like usemin is unable to replace what is surrounded by the bower comments.

Bullion answered 19/3, 2014 at 15:12 Comment(2)
this should be a comment, not an answerOrbiculate
aren't the <!-- bower:js--> comments only used to help grunt-bower know where to add the bower installed dependencies ?Accolade
U
1

As a standard, make sure you have selected Unix as the Line Endings in sublime or in your IDE. This could occur because of the Cross platform Usage.

enter image description here

Usurer answered 27/7, 2015 at 13:18 Comment(0)
C
0

I had the same problem, grunt was creating the files vendor.js and scripts.js but it wasn't inserting them into the index.html and at the end it was not replacing the old script links. It fixed this by doing what tk120404 was suggesting and that fixed the build process.

Civilian answered 27/7, 2015 at 20:17 Comment(1)
without having link, try to describe it here.Doubleness

© 2022 - 2024 — McMap. All rights reserved.