【问题标题】:Ember.js - Handlebars not recognized if required via Grunt (Node.js)Ember.js - 如果通过 Grunt (Node.js) 需要,则无法识别把手
【发布时间】:2013-06-20 16:15:52
【问题描述】:

是否有其他人使用Grunt 作为Ember Web 应用程序的构建工具并且遇到与我相同的行为?目前,我使用的是RC3 版本的框架,我可以毫不费力地使用我的构建工具并导入所有必要的库,对其进行丑化和压缩,一切都像魅力一样。

无论如何,至少从Ember RC5 开始,我不能再使用Grunt 来构建我的应用程序,因为Ember 将不再识别Handlebars!。它总是抱怨Ember Handlebars requires Handlebars version 1.0.0-rc.4. Include a SCRIPT tag in the HTML HEAD linking to the Handlebars file before you link to Ember.,然后它说Cannot read property 'COMPILER_REVISION' of undefined,这让我假设Ember不识别包含的Handlebars库。

除了对 js 文件的引用(使用 Ember RC5/6 而不是 RC3 和 Handlebars RC4 而不是 RC3)之外,我没有更改我的 app.js 中的任何内容(库/框架的顺序不变)。但是从那以后似乎有什么东西破坏了Ember.Handlebars的初始化......

我这里有什么问题吗?是否有解决方案让我可以继续使用Grunt 作为构建工具?


编辑

这是我的Gruntfile.js

/*jshint camelcase: false */
/*global module:false */
module.exports = function (grunt) {

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    meta: {
      dev: {
        buildPath: '.'
      },
      prod: {
        buildPath: '.'
      }
    },

    /*
     Task for uglifyng the application javascript file in production environment
     */
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
            '<%= grunt.template.today("yyyy-mm-dd") %> */'
      },
      prod: {
        files: [
          {
            src: '<%= meta.prod.buildPath %>/js/application.js',
            dest: '<%= meta.prod.buildPath %>/js/application.min.js'
          }
        ]

      }
    },

    /*
     Task for creating css files out of the scss files
     */
    compass: {
      prod: {
        options: {
          environment: 'production',
          noLineComments: true,
          outputStyle: 'expanded',
          cssDir: '<%= meta.prod.buildPath %>/css',
          fontsDir: '<%= meta.prod.buildPath %>/fonts',
          imagesDir: '<%= meta.prod.buildPath %>/images',
          javascriptsDir: '<%= meta.prod.buildPath %>/js'
        }
      },
      dev: {
        options: {
          environment: 'development',
          noLineComments: false,
          outputStyle: 'expanded',
          cssDir: '<%= meta.dev.buildPath %>/css',
          fontsDir: '<%= meta.dev.buildPath %>/fonts',
          imagesDir: '<%= meta.dev.buildPath %>/images',
          javascriptsDir: '<%= meta.dev.buildPath %>/js'
        }
      }
    },

    /*
     Task to minify all css files in production mode.
     All css files will end with '.min.css' instead of
     just '.css'.
     */
    cssmin: {
      minify: {
        expand: true,
        cwd: '<%= meta.prod.buildPath %>/css/',
        src: ['*.css', '!*.min.css'],
        dest: '<%= meta.prod.buildPath %>/css/',
        ext: '.min.css'
      }
    },

    /*
     Clean up the production build path
     */
    clean: {
      cssd: ['<%= meta.prod.buildPath %>/css/**/*']
    },


    /*
     A simple ordered concatenation strategy.
     This will start at app/app.js and begin
     adding dependencies in the correct order
     writing their string contents into 'application.js'

     Additionally it will wrap them in evals
     with @ sourceURL statements so errors, log
     statements and debugging will reference
     the source files by line number.

     This option is set to false for production.
     */
    neuter: {
      prod: {
        options: {
          includeSourceURL: false
        },
        files: [
          {
            src: 'app/app.js',
            dest: '<%= meta.prod.buildPath %>/js/application.js'
          }
        ]
      },
      dev: {
        options: {
          includeSourceURL: true
        },
        files: [
          {
            src: 'app/app.js',
            dest: '<%= meta.dev.buildPath %>/js/application.js'
          }
        ]
      }
    },

    /*
     Watch files for changes.

     Changes in dependencies/ember.js or application javascript
     will trigger the neuter task.

     Changes to any templates will trigger the ember_templates
     task (which writes a new compiled file into dependencies/)
     and then neuter all the files again.
     */
    watch: {
      application_code: {
        files: ['js/dependencies/ember.js', 'app/**/*.js'],
        tasks: ['neuter:dev']
      },
      compass: {
        files: [
          'styles/**/*.scss'
        ],
        tasks: ['compass:dev']
      }
    },

    /*
     Runs all .html files found in the test/ directory through PhantomJS.
     Prints the report in your terminal.
     */
    qunit: {
      all: ['test/**/*.html']
    },

    /*
     Reads the projects .jshintrc file and applies coding
     standards. Doesn't lint the dependencies or test
     support files.
     */
    jshint: {
      all: ['Gruntfile.js', 'app/**/*.js', 'test/**/*.js', '!js/dependencies/*.*', '!test/support/*.*'],
      options: {
        jshintrc: '.jshintrc'
      }
    },

    /*
     Generate the YUI Doc documentation.
     */
    yuidoc: {
      name: '<%= pkg.name %>',
      description: '<%= pkg.description %>',
      version: '<%= pkg.version %>',
      options: {
        paths: '<%= meta.dev.buildPath %>/app/',
        outdir: '<%= meta.dev.buildPath %>/yuidocs/'
      }
    },

    /*
     Find all the <whatever>_test.js files in the test folder.
     These will get loaded via script tags when the task is run.
     This gets run as part of the larger 'test' task registered
     below.
     */
    build_test_runner_file: {
      all: ['test/**/*_test.js']
    }
  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-neuter');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-yuidoc');

  /*
   A task to build the test runner html file that get place in
   /test so it will be picked up by the qunit task. Will
   place a single <script> tag into the body for every file passed to
   its coniguration above in the grunt.initConfig above.
   */
  grunt.registerMultiTask('build_test_runner_file', 'Creates a test runner file.', function () {
    var tmpl = grunt.file.read('test/support/runner.html.tmpl');
    var renderingContext = {
      data: {
        files: this.filesSrc.map(function (fileSrc) {
          return fileSrc.replace('test/', '');
        })
      }
    };
    grunt.file.write('test/runner.html', grunt.template.process(tmpl, renderingContext));
  });

  /*
   A task to run the application's unit tests via the command line.
   It will
   - convert all the handlebars templates into compile functions
   - combine these files + application files in order
   - lint the result
   - build an html file with a script tag for each test file
   - headlessy load this page and print the test runner results
   */
  grunt.registerTask('test', ['neuter', 'jshint', 'build_test_runner_file', 'qunit']);

  /*
   Configures all tasks which will be executed with production setup
   */
  grunt.registerTask('prod_tasks', ['clean', 'compass:prod', 'cssmin', 'neuter:prod', 'uglify:prod']);

  /*
   Setup for the production build. Sets the production build path.
   */
  grunt.registerTask('prod', 'Production Build', function () {
    grunt.task.run('prod_tasks');
  });

  /*
   Configures all tasks which will be executed with development setup
   */
  grunt.registerTask('dev_tasks', ['compass:dev', 'neuter:dev', 'watch']);

  /*
   Setup for the development build. Sets the development build path.
   */
  grunt.registerTask('dev', 'Development Build', function () {
    grunt.task.run('dev_tasks');
  });

  // Default task
  grunt.registerTask('default', 'dev');

  /*
   Configures all tasks which will be executed with doc setup
   */
  grunt.registerTask('doc_tasks', ['yuidoc']);

  /*
   Setup for the YUI doc generation.
   */
  grunt.registerTask('doc', 'Generate YuiDoc Documentation for the App', function () {
    grunt.task.run('doc_tasks');
  });

};

编辑 2

我从 Ember.js 网站的入门工具包中获取了 ember-1.0.0-rc.6.jshandlebars-1.0.0-rc.4.js 文件,并尝试在其上运行 Grunt 任务。这是 Chrome 告诉我的:


编辑 3

以防万一有人关心,这里是 Ember.js Github 页面上提出的问题的链接:https://github.com/emberjs/ember.js/issues/2894


编辑 4

最后,问题被确定为Handlebars 在处理全球出口时不一致,就像@Tao 在他的回答中报告的那样。如果你想关注,这里是 GitHub 上问题的链接:https://github.com/wycats/handlebars.js/issues/539

【问题讨论】:

    标签: node.js ember.js handlebars.js gruntjs


    【解决方案1】:

    下一个版本的 Handlebars 似乎正在解决这个问题:https://github.com/wycats/handlebars.js/issues/539 请继续关注。

    【讨论】:

    • 非常感谢,这似乎是问题所在。我现在在 GitHub 上关注 Handlebars 问题,希望很快能看到解决方法:)
    【解决方案2】:

    用于编译Handlebars 模板的版本与通过脚本标记包含的版本不匹配。

    如果您使用grunt-contrib-handlebars,它使用 npm 模块把手来编译模板。车把模块/项目独立于 Ember,并且有自己的修订版,可能与 Ember 兼容或不兼容。

    为了保持与把手的兼容性,Ember 需要特定版本的把手,它会警告您。

    这里的棘手部分是您需要确保grunt-contrib-handlebars 被强制使用该特定版本的车把。

    解决方案1:使用shrinkwrap 更改grunt-contrib-handlebars 的handlebars 依赖版本。

    解决方案 2:这是我目前正在使用的。我已切换到Emblem。标志 grunt 任务明确要求您的车把文件,因此您不必下拉到节点子依赖管理。并且您的构建将相同的文件包含到您的脚本标签中,从而避免了未来修订的重复/不匹配。

    编辑:在 Gruntfile 编辑之后

    查看 Gruntfile 我没有发现任何问题。看起来像一个标准的构建过程,js -&gt; neuter -&gt; (if prod) -&gt; uglify 等。

    我认为您需要尝试刷新 emberjs 和 handlebars js 文件。尝试使用入门工具包本身的文件,它们肯定可以一起使用。

    并通过查看 Chrome/Inspector 中的未压缩源来验证您的 index.html。 Handlebars 在横幅下方有修订号,例如 Handlebars.VERSIONHandlebars.COMPILER_REVISION。将这些与您在 ember.js 文件中看到的内容相匹配,位于 Ember.assert@submodule ember-handlebars-compiler 下方的某处。

    【讨论】:

    • 感谢您的回答,但我没有使用grunt-contrib-handlebars 插件,因为我没有在构建步骤中预编译我的模板。所以我可以说grunt-contrib-handlebars 中不同的Handlebars 版本对我的问题没有影响。
    • 除了版本不匹配之外,我想不出任何其他可能导致此问题的原因。也许您可以发布您的 Gruntfile,可能会澄清一些事情。
    • 我在第一篇文章中添加了我的Gruntfile.js ;)
    • 请查看我的第二次编辑,我附上了 Chrome 开发工具输出的屏幕截图...
    • 检查脚本包含的顺序。正确的顺序是 jQuery,Handlebars,然后是 Ember。也许订单在构建时搞砸了。您目前如何管理依赖项的排序?
    猜你喜欢
    • 1970-01-01
    • 2014-07-18
    • 2013-05-14
    • 2016-07-29
    • 1970-01-01
    • 2013-03-26
    • 2012-03-11
    • 2016-11-25
    • 2013-10-15
    相关资源
    最近更新 更多