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

Reloading modules breaks AngularJS HTML5 mode #225

Open
scottmcnab opened this issue Aug 21, 2015 · 4 comments
Open

Reloading modules breaks AngularJS HTML5 mode #225

scottmcnab opened this issue Aug 21, 2015 · 4 comments

Comments

@scottmcnab
Copy link

I have an AngularJS application that consists of two parts: a bootloader which loads first, and the main application that is loaded using ocLazyLoad.

The bootloader enables HTML5 mode by calling this method in the application module config block:

anguler.module("app").config( ['$locationProvider', function($locationProvider) {
    $locationProvider.html5Mode(true);
}]);

However when ocLazyLoad loads the next application modules, module 'ng' gets reloaded as part of the module dependencies (confirmed as the ocLazyLoad.moduleReloaded ng event is observed). This causes $locationProvider to be recreated, and the html5Mode configuration is lost! (confirmed with a debugger).

I am wondering: why does ozLazyLoad attempt to reinvoke already-loaded modules at all? Does it really need to do this? There is already code in place to detect and invoke addtional "run" blocks, and reload the config. Reloading the module is bound to cause all sorts of unexpected issues such as these!

FYI, I created a workaround for this situation by modifying this code in ocLazyLoad.js:

_invokeQueue(providers, moduleFn._invokeQueue, moduleName, params.reconfig);
_invokeQueue(providers, moduleFn._configBlocks, moduleName, params.reconfig); // angular 1.3+
broadcast(newModule ? 'ocLazyLoad.moduleLoaded' : 'ocLazyLoad.moduleReloaded', moduleName);
registerModules.pop();
justLoaded.push(moduleName);

replacing it with an optional parameter "reinvoke", that if set to false or left undefined prevents modules from being reinvoked:

if (newModule || params.reinvoke) {
    _invokeQueue(providers, moduleFn._invokeQueue, moduleName, params.reconfig);
    _invokeQueue(providers, moduleFn._configBlocks, moduleName, params.reconfig); // angular 1.3+
    broadcast(newModule ? 'ocLazyLoad.moduleLoaded' : 'ocLazyLoad.moduleReloaded', moduleName);
}
registerModules.pop();
justLoaded.push(moduleName);

This fixes AngularJS HTML5 mode behaviour for me.

What are your thoughts about a fix like this? This way the current "reinvoke existing modules" behaviour could be preserved if needed. Thanks.

@ocombe
Copy link
Owner

ocombe commented Aug 23, 2015

The event "moduleReloaded" doesn't really mean that the module is reloaded, it just means that it was seen as a dependency but it shouldn't call it again unless you use rerun (yeah the event name is misleading :-/).
Anyway, no "ng" module should ever be reloaded at all, if that's really the case then it's a bug.
Do you have a plunkr with an example where this happen ?

@scottmcnab
Copy link
Author

Sorry I forgot to mention - this patch is against 1.0.1, since I've being using this version instead of the latest due to #221, although the affected code in _register() has not changed between 1.0.1 and 1.0.4.

Also, I'm not sure if it makes a difference, but I'm using webpack to load the modules? So in this case, the way I load the main application looks as follows:

  function loadCore($ocLazyLoad, $q) {
    var deferred = $q.defer();

    require.ensure([], function() {
      var mod = require('../core/module');
      $ocLazyLoad.load({
        name: mod,
        rerun: true
      }).then( ()=> {
        deferred.resolve(mod);
      });
    });

    return deferred.promise;
  }

At this point, the main Angular 'ng' module is reloaded.

Looking at ocLazyLoad.core.js, it seems that for every module dependency (both new and old) the function _invokeQueue(providers, moduleFn._invokeQueue, moduleName, params.reconfig) is called - this is what causes Angular to be recreated.

Basically, I don't think that modules should be ever re-invoked right? However it may make sense for config and run blocks to be re-execute on a reload, depending on the case (e.g. loading a new module may add additional config or run blocks to an existing module - hence the rerun and reconfig params are useful in this case).

Therefore, I think the _invokeQueue method should be changed to be conditional for new modules only, e.g.

                    if (newModule) {
                        _invokeQueue(providers, moduleFn._invokeQueue, moduleName, params.reconfig);
                    }
                    _invokeQueue(providers, moduleFn._configBlocks, moduleName, params.reconfig); // angular 1.3+
                    broadcast(newModule ? 'ocLazyLoad.moduleLoaded' : 'ocLazyLoad.moduleReloaded', moduleName);

Thoughts?

@shanmugarajlingesan
Copy link

is it fixed? i also have same problem, my previous module is being so i see a performance issue in my application

jaugustin added a commit to BeneyluSchool/ocLazyLoad that referenced this issue Jan 22, 2016
jaugustin added a commit to BeneyluSchool/ocLazyLoad that referenced this issue Jan 22, 2016
@dbarnespaychex
Copy link

Hi @ocombe, any chance you can apply @jaugustin's fix to this repo and publish a new version to NPM? We're getting the same issue in our apps and tracked it down to this bug. Thank you!

boroth added a commit to LeadingReach/ocLazyLoad that referenced this issue Jul 9, 2024
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

No branches or pull requests

4 participants