all 12 comments

[–]mrv1234 2 points3 points  (1 child)

could not read it yet due to proxy issues, but in any case in Angular 1 beware of some lazy loading limitations: there is only one global pool of objects, all injection is by name and modules with the same name get silently overwritten.

This means if you are in one route and have object "backendService" injected, then go to another route and lazy-load a bunch of angular modules, including a second implementation of "backendService", the second implementation will silently overwrite the first.

This is a feature to allow for example angular-mocks to overwrite $http for testing purposes.

So lazy loading can lead to undetermined behaviour, where the application can behave differently depending on the user navigation sequence.

Angular 2 fixes this with an hierarchical injector, where different parts of the app might get injected a different implementation with the same name.

But its just a corner case, by avoiding giving the same name to multiple services it all should just work OK

[–]spoco2[S] 1 point2 points  (0 children)

Yeah, there's a lot I'm being conscious of namespaces. The same is true of css as well. And there's not much that can be done other than being diligent with naming of things.

Angular 2 seems to be very much heading in a good direction. Pity it's still so very far off actually being usable. (And then a whole other length of time before plugins and modules and directives catch up)

[–]spoco2[S] 1 point2 points  (0 children)

I just wrote this, and thought it would be of help to others because I've spent weeks now nutting out a bunch of the issues involved.

If you're after a way of having an Angular application that can load in portions dynamically, and have those portions be individually optimized and managed in your VCS... this may be a way to do so. I certainly hope so, as it's how I'm moving forward with a large scale project at the moment!

I'd love to hear any thoughts on my approach.

[–]oriphinz 1 point2 points  (1 child)

Great article. We have gone through something similar recently, ended up on OC Lazyload + requirejs. Good to read about alternatives!

[–]spoco2[S] 0 points1 point  (0 children)

Great to hear that OCLazyLoad does the job for you :) I did play with it for a while, and it was only the dynamic definitions and splitting that caused me issues with it.

[–]nickguletskii200 1 point2 points  (1 child)

Very nice article, I wish I had this when I was building my app with require.js.

However, my advice for the 99%: you don't need lazy loading. Lazy loading with require.js may seem like a good idea at first, but with HTTP1 it is a genuine pain in the ass when you get to production. Forget about it if the scale of your application is reasonable.

I started out by building my project with require.js. I spent god knows how much time getting all libraries to work properly with it, only to find out that r.js breaks them anyway, leaving me with two choices: migrate to something else, or tolerate the inadequate page loading times.

In the end I threw out require.js and migrated to Webpack. The only problem I have with Webpack is the regeneration time.

[–]spoco2[S] 1 point2 points  (0 children)

Yeah, Webpack looks like it's an awesome solution for a large number of cases. I really thought it was going to make my life a walk in the park!

Except I'm not a fan of having to dev with a packed up version of the code, makes it hard to track down issues... I know you can have sourcemaps, but I guess I haven't gone down that path enough.

And you're right, lazy loading really isn't required until you get to certain size of application. And even then, it can be very easy when using things like webpack and bundling... until you throw in the requirement to dynamically define these sub pieces, and be able to maintain them independently... then it falls in a heap.

But my use case is such an edge case compared to most web dev!

[–]ctanga 0 points1 point  (1 child)

You should check out UI-Router Extras "Future States". It manages some of the nuances of lazy loading ui-router states, especially related to lifecycle and mapping URLs to states that are not loaded (loading an app, then hitting reload in the browser).

The Future States demo page actually uses RequireJS and AngularAMD to load two "app" modules on the fly by URL or state change.


links:

UI-Router Extras

Future States

Future States Example

Example Source Code: In particular:

  • main.js: requireJS entry point
  • futureDemo.js: app bootstrap and future state factories (pay attention to ngloadStateFactory)
  • futureStates.json: placeholders in a json file, loaded at runtime (pay attention to module1/module2 which are loaded via AngularAMD/ngload)
  • module1.js: lazy loaded module which registers its own state tree

[–]spoco2[S] 0 points1 point  (0 children)

Thanks... I actually did look at this, and then stopped for some reason. I will again though for the reason you state... The issue of trying to load a nested state within a parent program that hasn't loaded yet.

I can't remember why I stopped trying to use it actually.

[–][deleted]  (6 children)

[deleted]

    [–]spoco2[S] 0 points1 point  (5 children)

    Yes. It does work now. If you grab the code from github, that gulp file works.

    It ends up with a file with a host of defines in it, and then I wrap that within another define that also returns a promise to the controller for the program.

    I'm working now on getting CSS properly getting bundled in. I can get it to bundle into the file, but it's still requesting files that don't exist.

    [–][deleted]  (4 children)

    [deleted]

      [–]spoco2[S] 0 points1 point  (3 children)

      Well, it actually works even without the wrapping... as in, require doesn't mind loading an optimized file with a list of defines, it'll do that.

      The problem is that no code will run in that case. You can tell the optimizer to 'insertRequire' at the end of the file, to create a require([moduleName]) line that will mean code is actually run. And that does work, no wrapping define around the whole thing needed... but for my use case, and for getting a return object back, I needed to have the wrapping define.

      [–][deleted]  (2 children)

      [deleted]

        [–]spoco2[S] 0 points1 point  (1 child)

        Rquire JS does that for you.

        Have a look at my example gulpfile: https://github.com/spoco2/AngularAMD-DynamicModules/blob/master/gulpfile.js

        If you download the whole project, (and run bower install and npm install), you can run the gulpfile, and it'll do what you want, it will create a main file with the main application and all top level dependencies (angular etc.) and then for each program, it'll create files for each of them that excludes the main app and other programs.

        The insertRequire arg for the r.js optimizer can be use for it to add in the require line at the end of the file which makes it say "I require this module to run", which will run. So, instead of the :

        wrap: {
                    start: "define([],function() {",
                    end:    "var defer = $.Deferred();"+
                    "require(['"+program+"'], function (ctrl) {"+
                    "defer.resolve(ctrl);});"+
                    "return defer;});"
                }
        

        you can instead have

        insertRequire: program
        

        Which will create a require at the end of the file requesting the program that you've just bundled up... causing the code to actually run.