Angular Lazy Loading: Lighthouse reports "Remove unused JavaScript" on scripts that should be not loaded yet

Viewed 4109

I have a problem regarding lighthouse issue on my angular app with lazy loading. Basically my app contains 3 big chunks of feature that should be lazy loaded. So when you open the feature A, I expect the app not to load the scripts for feature B and C at all, and vice versa.

But somehow, when I check with lighthouse, it reports back that I can "remove unused JavaScript" on the other JS files that contains the whole functionality of the other features. Even worse, one of the feature depends on ngx-quill for rich-text editor, and this also got loaded although I open a feature that does not need it.

Am I missing something here?

EDIT:

I have these following *-routing.modules.ts:

  • app-routing
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  { path: '', loadChildren: () => import('./feature-a/feature-a.module').then(m => m.FeatureAModule) },
  { path: 'feature-b', loadChildren: () => import('./feature-b/feature-b.module').then(m => m.FeatureBModule) },
  { path: '**', redirectTo: '', pathMatch: 'full' }
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }
  • feature-a: nothing of interest, no lazy loading here.

  • feature-b:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LandingPageComponent } from './pages/landing-page/landing-page';
import { FeatureBPage } from './feature-b.page';

const routes: Routes = [
  {
    path: '',
    component: FeatureBPage,
    children: [
      { path: '', redirectTo: 'home', pathMatch: 'full' },
      { path: 'home', component: LandingPageComponent },
      {
        path: 'feature-c',
        loadChildren: () =>
          import('./feature-c/feature-c.module').then(
            (m) => m.FeatureCModule
          ),
      },
      { path: '**', redirectTo: '', pathMatch: 'full' }
    ],
  },
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class FeatureBRoutingModule {}
  • feature-c: contains multiple other lazy loaded features (feature-c1, -c2, -c3, etc), but none of those are being referenced by Feature A and/or Feature B.
1 Answers

Looks like the issue is not so much with the unused JavaScript from bundles (scripts) that should not be loaded, but the fact that those bundles are being loaded in the first place.

It's hard to say without further details, but it could be for any of the following reasons:

  1. PreloadAllModules strategy loads all lazy-loaded modules regardless of their lazy-loading status.
  2. "Accidentally" importing something from one lazy-loaded feature module into another module loads that entier lazy-loaded module at run-time.
  3. Verify through the Network tab that the unrelated lazy-loaded features are indeed being loaded (and you are not confusing other files for them).
  4. In case the unused JavaScript is in the bundles that should, in fact, be loaded, Lighthouse reports any piece of code that wasn't executed (e.g. if conditions that didn't run, *ngIf directives that didn't execute) as unused. There isn't much one can do about that.
Related