Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug with namespace function + AMD #108

Closed
bmaland opened this issue May 14, 2014 · 26 comments
Closed

Bug with namespace function + AMD #108

bmaland opened this issue May 14, 2014 · 26 comments

Comments

@bmaland
Copy link

bmaland commented May 14, 2014

I'm using a namespace function which appends the folder name to the template namespace, resulting in the following namespaces: JST.shared/JST.module1/JST.module2. This works fine without AMD.

The problem is that when AMD is enabled, the last namespace "wins" because of the following code: output.push("return "+nsInfo.namespace+";"); nsInfo is here modified in the forEach loop, which leaves it at JST.module2 in my case. Alas, only JST.module2 is returned from the compiled template file instead of the root JST namespace.

I'm not sure how to fix this other than adding a new configuration option. Guessing the root namespace seems hard (you can't simply remove all dots), but maybe I'm missing something.

@tkellen
Copy link
Member

tkellen commented May 15, 2014

Can you post your working non-amd and amd configs?

@tkellen tkellen closed this as completed May 15, 2014
@tkellen tkellen reopened this May 15, 2014
@stephanebachelier
Copy link
Contributor

@bmaland Do you use the processName options ? I use with AMD with namespaces and it works

FYI my templates can be in app/scripts/templates or app/scripts/modules/.*/templates. By using the processName function below it works:

processName: function (filePath) {
  var matches = filePath.match(new RegExp('scripts/(modules/(\\w+)/templates|templates)\/(.*).hbs'));
  if (!matches) {
    return filePath;
  }
  return (matches[2] ? matches[2] + '/' : '') + matches[3];
}

And the full handlebars configuration:

handlebars: {
  compile: {
    options: {
        amd: true,
        namespace: 'templates',
        processName: function (filePath) {
          var matches = filePath.match(new RegExp('scripts/(modules/(\\w+)/templates|templates)\/(.*).hbs'));
          if (!matches) {
            return filePath;
          }
          return (matches[2] ? matches[2] + '/' : '') + matches[3];
        },
        processContent: function (content) {
          content = content.replace(/^[\x20\t]+/mg, '').replace(/[\x20\t]+$/mg, '');
          content = content.replace(/^[\r\n]+/, '').replace(/[\r\n]*$/, '');
          content = content.replace(/\n/g, '');
          return content;
        }
      },
      files: {
        '.tmp/scripts/templates.js': [
          '<%= yeoman.app %>/scripts/templates/**/*.hbs',
          '<%= yeoman.app %>/scripts/modules/**/templates/**/*.hbs'
        ]
      }
    }
  }
};

@bmaland
Copy link
Author

bmaland commented Jun 18, 2014

@stephanebachelier your example works because you have a static namespace ('templates'), this bug occurs when you have a namespace function in combination with AMD.

Here's a full repo showcasing the issue: https://github.com/bmaland/grunt-handlebars-sample

As you can see in the built templates.js file, only the last namespace is returned: https://raw.githubusercontent.com/bmaland/grunt-handlebars-sample/master/templates.js

The bug is actually quite obvious when you look at https://github.com/gruntjs/grunt-contrib-handlebars/blob/master/tasks/handlebars.js#L179 and https://github.com/gruntjs/grunt-contrib-handlebars/blob/master/tasks/handlebars.js#L90 (nsInfo is overwritten in the loop, last entry wins).

@stephanebachelier
Copy link
Contributor

@bmaland I'm not sure I understand what you want.

Correct me if I'm wrong, but for me this["JST"]["module1"]["foo"] is the same thing as JST.module1.

By the way I think there is something wrong at the end of the file
https://github.com/bmaland/grunt-handlebars-sample/blob/master/templates.js#L27.
It should be return this["JST"]; and not return this["JST"]["module2"];

@bmaland
Copy link
Author

bmaland commented Jun 19, 2014

@stephanebachelier The error on templates.js#L27 is the bug I'm reporting. Sorry if that wasn't clear. If you reread my previous comment, you can see that I refer to where the bug is in handlebars.js.

@stephanebachelier
Copy link
Contributor

@bmaland now it's clear :) Your first comment was indeed clear.

@bmaland
Copy link
Author

bmaland commented Jun 19, 2014

Btw the config in my sample repo works just fine with amd: false, the issue is as you can see the return statement when amd is enabled.

@lazd
Copy link
Contributor

lazd commented Aug 3, 2014

@bmaland, can you try this against master and see if it's fixed now?

@bmaland
Copy link
Author

bmaland commented Sep 27, 2014

Still seeing the same issue, only the second module is returned (last line of templates.js is still return this["JST"]["module2"];)

stephanebachelier added a commit to stephanebachelier/grunt-contrib-handlebars that referenced this issue Nov 2, 2014
@stephanebachelier
Copy link
Contributor

@bmaland I think this should fix your problem.

stephanebachelier added a commit to stephanebachelier/grunt-contrib-handlebars that referenced this issue Nov 2, 2014
@bmaland
Copy link
Author

bmaland commented Nov 9, 2014

@stephanebachelier your patch does indeed fix the problem

@stephanebachelier
Copy link
Contributor

@bmaland glad it helps. You can close this issue now.

@bmaland
Copy link
Author

bmaland commented Nov 18, 2014

@stephanebachelier can you do a pull request with your fix? :)

@stephanebachelier
Copy link
Contributor

@bmaland it's already done in #124 and available in the 0.9.1

@bmaland
Copy link
Author

bmaland commented Dec 30, 2014

@stephanebachelier I just noticed that #124 wasn't merged. The commit which fixes the problem (096b9f7078d1c19128bccbd05245091136a2ee3) is not included the master branch or the 0.9.1 release.

Your fork works fine though.

@stephanebachelier
Copy link
Contributor

@bmaland nice catch. I make a new PR.

stephanebachelier added a commit to stephanebachelier/grunt-contrib-handlebars that referenced this issue Dec 31, 2014
stephanebachelier added a commit to stephanebachelier/grunt-contrib-handlebars that referenced this issue Dec 31, 2014
@stephanebachelier
Copy link
Contributor

@bmaland maybe you should reopen this issue as it is not fixed, see #129.

@stephanebachelier
Copy link
Contributor

@bmaland it's merged in v0.9.2

@lostthetrail
Copy link

This is a backwards incompatible bug fix and may have some issues in it.

The precompile templates file now generated by a few of my projects were coded to return the specific namespace configured in options, but now it returns the lowest level namespace.

Before 0.9.2

return this["JS"]["templates"]["foo"];

After 0.9.2

return this["JS"];

All of the templates in this file belong to JS.templates.foo.

The issue being reported is valid, but I don't know that this solution is complete.

"The namespace in which the precompiled templates will be assigned."

If I assign namespace to "JS.templates.foo", the nsDeclarations will show 3 declarations, but the new 'extractGlobalNamespace' function will only get "JS", which isn't correct for the configured namespace.

@stephanebachelier
Copy link
Contributor

@lostthetrail I've added a new test to fix this issue while not changing any existing tests.

See https://github.com/stephanebachelier/grunt-contrib-handlebars/blob/9367a1660426df7f0b900dcf3640ffbcab99dc4a/test/expected/amd_namespace_as_function.js

IMHO it's normal to return return this["JST"];

If you don't agree share your configuration because I'm not sure I understand what you want.

@stephanebachelier
Copy link
Contributor

@lostthetrail if I understand you want all the precompiled templates to be under the namespace JS.templates.foo ?
If you set the namespace to JS.templates.foo it should give you this namespace for all the templates, no ?

@stephanebachelier
Copy link
Contributor

@lostthetrail sorry for the spam. I think I got it. Correct me if I am wrong, but if you set a namespace with any dots in it, you will only have the first part of the namespace.
So if I set :

  // ...
  namespace: 'a.b.c',
  // ...

The precompiled template file will ends with :

  return this["a"];

});

instead of

  return this["a"]["b"]["c"];

});

@stephanebachelier
Copy link
Contributor

@lostthetrail test my branch in #131 as it should fixes your bug.

@lostthetrail
Copy link

@stephanebachelier This looks like the correct solution. I will check out your branch and test it tomorrow morning. Thank you for responding quickly to the issue.

@lostthetrail
Copy link

@stephanebachelier
Ah drat. I noticed something that might still be problematic.

If you have a function that returns a dot based namespace, you will still have the issue.

var myVar = 'FooVar';

namespace: function() {
    return 'Foo.Templates.' + myVar;
}

@stephanebachelier
Copy link
Contributor

@lostthetrail I will try to update my fix #131 with this case

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants