Grunt usemin:合并的JavaScript文件未在index.html文件中替换

10
我从yeoman生成的空项目开始,并尝试编辑Gruntfile.js以满足我的需求。
grunt构建任务读取我的index.html文件,将我的bower依赖项合并并生成.vendor.js文件。
我在工作流程中出了点问题,现在即使生成了.vendor.js文件,usemin也无法替换index.html文件中的标记。
这是我的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'
      ]);
    };

当我运行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 -->

最后,这里是 grunt 的输出

        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

任何能帮助理解这个的帮助都将不胜感激。

5个回答

10

我来回答自己的问题:

我的useminprepare配置与我的usemin配置有所不同。

useminprepare正在写入到<%= yeoman.dist %>/public/views/edit/index.html

而usemin正在从<%= yeoman.dist %>/views/edit/index.html读取


不要忘记接受自己的答案,如果它解决了你的问题!(顺便说一下,感谢你发布它!它很有帮助!) :-) - Christopher Parker
确实是这样。在“grunt build”的默认输出中没有警告或错误。 - Wolfram

4
由于某些原因,我遇到了同样的问题。在执行grunt build时,我的index.html没有更新(但是main.cssmain.js已经成功输出)。我尝试了grunt usemin:html它起作用了
所以我最终将usemin:html移动到grunt build任务列表的最后一个位置。
目前还不清楚为什么会出现这种情况,但这个方法可以帮助我达到预期的效果。如果其他人也遇到相似情况,希望这篇翻译能对你有所帮助。

1
作为一个标准,确保你在Sublime或者IDE中选择了Unix作为行结尾。这可能是由于跨平台使用所引起的。

enter image description here


1
我有一个类似的问题。在我的情况下,除了bower:css或bower:js标签内的内容之外,其他所有内容都按预期替换。看起来usemin无法替换由bower注释包围的内容。

1
这应该是一个注释,而不是一个答案。 - thescientist
“<!-- bower:js-->” 的注释不是只用来帮助 Grunt-Bower 知道在哪里添加 Bower 安装的依赖项吗? - vmontane

0

我曾经遇到过同样的问题,grunt会创建vendor.js和scripts.js文件,但它没有将它们插入index.html中,并且最终也没有替换旧的脚本链接。我按照tk120404所建议的方法解决了这个问题,这样就修复了构建过程。


请将以下与编程相关的内容从英文翻译成中文。仅返回翻译后的文本,不要包含链接,尽量描述其内容。 - Enamul Hassan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接