Skip to content

Lazy load of modules don't work when using barrel file #9862

@alan-agius4

Description

@alan-agius4

This is a follow up of angular/angular#22490

Versions

CLI 1.7.1

Repro steps

https://github.com/Lydon/lazy-loading

  • ng serve
  • Click on the login button
  • Check console error

Observed behavior

I am getting a error Error: Cannot find 'LoginModule' in './common/index' when having lazy routes with barrels.

After doing some debugging I tracked the issue to this function here which is creating the $$_lazy_route_resource file.
https://github.com/angular/angular-cli/blob/master/packages/@ngtools/webpack/src/angular_compiler_plugin.ts#L591

What I noticed was the while the call to ContextElementDependency was being done with the correct module names. Because of https://github.com/angular/angular-cli/blob/master/packages/@ngtools/webpack/src/angular_compiler_plugin.ts#L596 it only takes the path before the # as a module name, which in case you use a barrel file, you'll end up with the same module path for different import path.

If you take the below routes:

const routes: Routes = [
  {
    path: 'admin',
    loadChildren: './common/index#AdminModule'
  },
  {
    path: 'login',
    loadChildren: './common/index#LoginModule'
  },
  {
    path: 'register',
    loadChildren: './common/index#RegisterModule'
  }
];

The dependencies returned when calling ContextElementDependency would be:

[
 ContextElementDependency {
    module: null,
    request: '/Users/alan/lazy-loading/src/app/common/admin/admin.module.ts',
    userRequest: './common/index' },
  ContextElementDependency {
    module: null,
    request: '/Users/alan/lazy-loading/src/app/common/login/login.module.ts',
    userRequest: './common/index' },
  ContextElementDependency {
    module: null,
    request: '/Users/alan/lazy-loading/src/app/common/register/register.module.ts',
    userRequest: './common/index' } 
]

However it looks like webpack is deduping modules that share the same name when creating the $$_lazy_route_resource file and eventually the output map would be:

var map = {
	"./common/index": [
		"./src/app/common/register/register.module.ts",
		"register.module"
	]
};

Desired behavior

No errors, and I can use lazy loading with barrel files.

Mention any other details that might be useful

  1. I am not aware of the reason why it was decided to ignore the ngModule name part into from the module path that is passed to webpack. My Idea would be tp take it into consideration as well ie, not to take only the contents of the string before the #. That said, I know it would be that easy and need to make it backward compatible, as it effects changes in https://github.com/angular/angular/blob/c8a1a14b87e5907458e8e87021e47f9796cb3257/packages/core/src/linker/system_js_ng_module_factory_loader.ts as well.

  2. Not sure if webpack provides as way to not dedupe or some other dependency mechanism to overcome this. And in all fairness, I am not sure if this is by webpack design.

//cc @TheLarkInn

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions