majgis/ngify

Should nested requires work with the file-naming syntax?

Madd0g opened this issue · 9 comments

I haven't changed anything besides using the filenaming syntax, but the inner requires stopped working, as soon as I moved them to index.js, everything started working. Have I done something wrong?

Index.js (has ui-router states)

  .state('main', {
         .....
         controller: require('./main.controller')
  })

and on top of main.controller.js:

   require('./common/thing1.directive');
   require('./common/thing2.directive');


  function mainCtrl()
  {

  }
  exports = module.exports = mainCtrl;

as soon as I move these directive requires to index.js, they work, but if they're in main.controller they don't work. Any idea why? I get no errors anywhere.

You might try the following:

var mainController = require('./main.controller')
.state('main', {
         .....
         controller: mainController
  })

Also, look in the bundled output to try and get an idea on what is happening, ie. is main.controller getting left out?

Main controller is the one that works. The directives it requires do not.

I peeked inside the generated bundle and both the directives and their inner templates are there, that's as useful as I can be (only started with browserify a couple of weeks ago).

Your suggestion works, but of course I would highly prefer not to separate it into a variable, because the states are chained - so the actual require ends up being very far from where it's used.

EDIT: Out of curiosity, I compared the bundle output when using the variable and not using it and it's exactly the same besides that. But the problem is not the file in the variable, but the inner requires. It's actually a pretty funny problem. It's cool how you just knew exactly what went wrong.

Thanks for the quick response, loving this library so far!

Ok, I'll do my best to recreate this issue, but I'll focus on getting the
other two issues resolved first.

On Wed, Sep 30, 2015 at 12:47 AM, Madd0g notifications@github.com wrote:

Main controller is the one that works. The directives it requires do not.

I peeked inside the generated bundle and both the directives and their
inner templates are there, that's as useful as I can be (only started
with browserify a couple of weeks ago).

Your suggestion works, but of course I would highly prefer not to separate
it into a variable, because the states are chained - so the actual require
ends up being very far from where it's used.

Thanks for the quick response, loving this library so far!


Reply to this email directly or view it on GitHub
#24 (comment).

So today I tested minification with ngify injections, it seems the problem with injections also happens with these nested requires. It looks like it's decorated in the bundle, but for some reason doesn't work. I spent a while on this today :(

This is just an FYI, because I tried ng-annotate today and prefer that solution for injections, which requires less typing and leaves less room for mistakes.

Well, I'm not trying to compete with anyone. I created a solution that
worked for my problem and shared it. You are using ngify differently than
I am so maybe a different solution will suit you better.

On Wed, Sep 30, 2015 at 6:04 PM, Madd0g notifications@github.com wrote:

So today I tested minification with ngify injections, it seems the problem
with injections also happens with these nested requires. It looks like it's
decorated in the bundle, but for some reason doesn't work. I spent a while
on this today :(

This is just an FYI, because I tried ng-annotate today and prefer that
solution, which requires less typing and leaves less room for mistakes.


Reply to this email directly or view it on GitHub
#24 (comment).

ngify works great for me and I'm using all features except the injections, it all works together.

So one issue I see, is that you are trying to use the output of the require statements directly in angular. Realize that requiring a file returns a generic JS object that might be used in a different framework. If you use ngify it inserts the extra angular boilerplate to register that object with Angular's dependency injection. My advice is to use Angular's DI and not try to use the objects directly. At first I thought I could support this usage, but ultimately with Angular, I think trying to bypass DI is a bad idea and will create many more problems.

For example, with the help of require-globify I use the following to bulk load all files in the project:

//Create the module
require('./app');

//Load all .js files in the modules folder
require('./modules/**/*.js', {mode: 'expand', options:{ignore:'./modules/**/*.spec.js'}});

//Load all .html files in the modules folder
require('./modules/**/*.html', {mode: 'expand'});

Inside of ./app.js, I create the module, load submodules and immediately add odds and ends to the Angular's DI:

require('angular-route');
require('../../node_modules/angular-modal/modal.min');//Unminified version requires ng-annotate
require('angular-bootstrap-npm');
require('angular-animate');
require('rx-angular');

exports = module.exports = angular.module('mactApp', [
    'ngRoute',
    'btford.modal',
    'ui.bootstrap',
    'ngAnimate',
    'rx'
])
        .value('uriTemplates', require('uri-templates'))
        .value('moment', require('moment'))
        .value('underscore', _)
        .value('jQuery', jQuery)
        .value('Sly', Sly)
        .value('api_url', os.Otags.api_url)
        .value('angular', angular)
        .value('URIS', {
            RECS: '//www.overstock.com/api/recs'
        });

Now the rest of the application is declarative with zero angular boilerplate. In very rare cases I'll use a require statement to inherit a subclass, but in all other cases I'm getting what I need from Angular's DI (Ask for what you want in the function signature).

If you try this paradigm shift, I think your experience with ngify will be even better. In fact, minification will not work with the approach you are taking now, I would have to return the angular object instead of the generic object, which would add confusion, and again we don't want to bypass the DI.

hmm... I've seen multiple angular UMD projects where the exported thing is actually the name of the module (example, example2), to support this syntax:

 angular.module('myModule', [ require('angular-moment'), require('angular-ui-router') ])

Since you're going to support this with templates, shouldn't this work the same?

It makes sense for the module to be returned, for example in ./app.js above, since that lives outside the injector, but everything else makes sense to access from Angular's DI. It was a interesting idea at first, to return the angular object, but I can see no advantage to short circuiting Angular's DI.

In regard to the templates, they are unique, since you are registering the file name in the templatecache and not with the injector. I'll give that some more thought and comment on that soon.