Deferrable Views not working when used in library repo

237 Views Asked by At

We are trying to implement deferrable views for a component in angular. This component is present in a component which is used by a parent in another repo. While defer seems to be working when we implemented it inside component of the same project, its not working when imported and used in a library. Two issue here actually:

  1. code is not split into a new bundle but loaded along with the main library bundle
  2. placeholder element appears for a split second and then the view disappears. on checking the html i found that I cannot see the child elements of the deferred component, its just like a dummy element enter image description here

Here are the things which I have followed as a requirement:

  1. Using angular 17 in both the main project and library project
  2. Using on viewport condition to defer the block
  3. the component inside the defer block is a standalone component
  4. component is not used anywhere outside the defer block and also not referenced using viewchild

Is there anything I'm doing wrong or any additional requirement I need to follow ?

2

There are 2 best solutions below

2
Yuri Blanc On

I have also tried to lazy load components using the deferred blocks in ng-packagr libraries but ATM doesn't seems to work. Also by adding sub-roots for your library doesn't seems to work either.

You can easily lazy-load sub-roots using import() and create component instances by using ViewContainerRef.createComponent, createComponent or the legacy ComponentFactoryResolver.

When using the deferred block your component is resolved as html string and not parsed to produce a new chunk for the bundle. You can easily verify that by looking at the cli output files.

Given the following example:

import { Component, ViewContainerRef, createComponent } from '@angular/core';

import { SecondaryLazyCmpComponent } from "test-defer-lib/secondary-entry";

@Component({
    selector: 'lib-root',
    standalone: true,
    template: `
    @defer (on timer(5s)) {
      <h3>SomeText</h3>
      <secondary-lazy-cmp [from]="'@defer'"/>
    }

    @placeholder {
      <div>loading...</div>
    }
  `,
    styles: ``,
    imports: [SecondaryLazyCmpComponent]
})
export class TestDeferLibComponent {


  constructor(private viewRef: ViewContainerRef) {
    import('test-defer-lib/secondary-entry').then(c => {
      setTimeout(() => {
        const cmp = viewRef.createComponent(c.SecondaryLazyCmpComponent);
        cmp.instance.from = "import()"
      }, 5000);
    })
  }

}

The output will contain the h3 element with its content, the deferred block as an html element with the component empty and lastly the actual lazy loaded component in this case using the viewRef.createComponent function.

I think that should be considered a bug, also if Angular team usually doesn't favour lazy loading in libraries, i consider this broken.

It doesn't even produce an error.

Read this:

https://github.com/angular/angular/issues/53936

I'm gonna analyse whats involved and participate to this issue, hoping for the Angular team to address this.

0
Mau On

As already mentioned, check the following thread: https://github.com/angular/angular/issues/53936

Angular Deferrable Views not working when used in libs:

This is currently expected; libraries are compiled differently to applications and do not currently account for defer loading of views.