Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I only preload modules whose parents have been activated?

I have lazy loading implemented. I'm trying to set up a custom preloading strategy.

Say I have the following url structure:

/
/fruit
/fruit/bananas
/fruit/apples
/vegetables

If I hit /, I want to preload /fruit. Following the Angular example, I simply put data: {preload: true} in my route config, and then implement a custom preloading strategy which checks that data and loads. This works fine.

However, I don't want to preload /bananas or /apples until I actually navigate to /fruit. As it is, as soon as /fruit is preloaded, the preloading strategy finds more modules with {preload: true} and preloads /bananas and /apples too.

Is there a clean way to put off preloading modules after their parent modules have been navigated to?

like image 281
adamdport Avatar asked Jul 13 '18 20:07

adamdport


People also ask

What is the purpose of the Prelodingstrategy property configuration in this router code?

The Angular router provides a configuration property called preloadingStrategy , which defines the logic for preloading and processing lazy-loaded Angular modules. We'll cover two possible strategies: PreloadAllModules , which preloads all lazy-loaded routes, as the name implies.

What is the lazy loading in Angular?

Lazy loading is the process of loading components, modules, or other assets of a website as they're required. Since Angular creates a SPA (Single Page Application), all of its components are loaded at once. This means that a lot of unnecessary libraries or modules might be loaded as well.

What is LoadChildren in Angular?

Use LoadChildren:For lazy loading. Using this property will optimize your application's performance by only loading the nested route subtree when a user navigates to a particular URL that matches the current route path. It helps in keeping the nested routes table separate.


1 Answers

I ended up doing a custom but scalable solution using the route's data property. I created 3 properties:

  • preload (boolean) - if true, preload as soon as Angular knows about it (like /fruit). This is the basic example Angular gave us in their docs
  • preloadCheckpoint (enum) - I define each app "checkpoint" in my own enum. So in my question's example, /fruit is the checkpoint, and I'd define on it data: {preloadCheckpoint: myCheckpointEnum.FRUIT}
  • preloadAfterCheckpoint (enum) - I define this to put off preloading until a certain checkpoint is reached. If I define this on /bananas, the bananas module won't load until the route with the FRUIT checkpoint is defined

I subscribe to route changes so I can keep my checkpoints list updated, and then check that list during every preload attempt.

export class CustomPreloadingStrategy implements PreloadingStrategy {
  checkpoints: Set<PreloadCheckpoints> = new Set<PreloadCheckpoints>(); 

  constructor(router: Router, route: ActivatedRoute){

    router.events.pipe(
     filter(event => event instanceof NavigationEnd),
      map(() => route),
      map(route => {
        while (route.firstChild) route = route.firstChild; //gets the deepest child
        return route;
      }),
      filter(route => route.outlet === 'primary'))
      .subscribe((route) => {
         if(route.snapshot.data['preloadCheckpoint'] !== undefined){ 
           this.checkpoints.add(route.snapshot.data['preloadCheckpoint']);
         }
    });
  }

  preload(route: Route, load: () => Observable<any>): Observable<any> {    
    if (route.data && ( route.data['preload'] || this.checkpoints.has(route.data['preloadAfterCheckpoint']) )){
      return load(); //preload this route
    } else {
      return of(null);
    }
  }
}

export enum PreloadCheckpoints {
  FRUIT
}
like image 65
adamdport Avatar answered Nov 15 '22 03:11

adamdport