sp-dev-docs icon indicating copy to clipboard operation
sp-dev-docs copied to clipboard

Lazy loading of custom web parts in modern pages

Open stchiew opened this issue 4 years ago • 41 comments

Category

  • [x] Question
  • [ ] Typo
  • [ ] Additional article idea

Question

I am observing lazy loading of custom web parts in modern pages. A web part is not loaded/rendered until it is scrolled to. This was observed in both Targeted and Standard release tenants starting Jul 18. See snapshot of elements rendered of a HelloWorld webpart upon initial page load and then after it is scrolled into view.

My question: is there a way to override this behavior (either thru PS or even within spfx code) to render all webparts on page load?

My use case for this is in using dynamic data source web parts where the data source web part is at the bottom of a large page, while my destination/receiving web part is at the top. (Example: a navigation menu of various web parts in the page). Since the source is not rendered yet at the bottom, the top web part does not have any data coming from the source web parts. Prior to Jul 18, all web parts were renderd on page load, so my consumer web part was able to get all data from the source/publisher web parts at the bottom of the page.

Upon page load image

After scrolling to web part image

Environment details (development & target environment)

  • Your Developer Environment: Windows 10
  • Target Environment: SharePoint Online (Targeted and Standard release tenants)
  • Framework: Node.js v6/v8/v10/v12]
  • Browser(s): All
  • Tooling: VS Code , SPFx v1.10.0
  • Additional details: This was not observed prior to Jul 18. After Jul 18, the web parts are being wrapped around a <div data-viewport-id tag.

stchiew avatar Jul 22 '20 06:07 stchiew

Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.

msft-github-bot avatar Jul 22 '20 06:07 msft-github-bot

Related issue in PnP Web Parts samples repo: #1375

Steps to reproduce

  1. Get the code from Page Sections Navigation sample
  2. Add Page Section Navigation web part on top of the page.
  3. Add multiple Page Sections Navigation Anchor web parts on the page: some of them visible as soon as you open the page, some - invisible until you scroll down
  4. Save the page
  5. Only visible anchors are listed in the navigation

Expected behavior

All anchors are listed in the navigation

Additional context

The connection between navigation web part and anchor web part is done using Dynamic Data capability of SPFx. Anchor web part is registered as a data source using this.context.dynamicDataSourceManager.initializeSource(this);. Navigation web part consumes dynamic data using API approach:

protected onInit(): Promise<void> {
    //...
    // getting data sources that have already been added on the page
    this._initDataSources();
    // registering for changes in available datasources
    this.context.dynamicDataProvider.registerAvailableSourcesChanged(this._availableSourcesChanged);

    //...
  }

private _initDataSources(reRender?: boolean) {
    // all data sources on the page
    const availableDataSources = this.context.dynamicDataProvider.getAvailableSources();

    for (let i = 0, len = availableDataSources.length; i < len; i++) {
      let dataSource = availableDataSources[i];
      if (!dataSource.getPropertyDefinitions().filter(pd => pd.id === 'anchor').length) {
        continue; // we don't need data sources other than anchors
      }
      if (!dataSources || !dataSources.filter(ds => ds.id === dataSource.id).length) {
        this.context.dynamicDataProvider.registerPropertyChanged(dataSource.id, 'anchor', this._onAnchorChanged);
      }
    }
  }

AJIXuMuK avatar Jul 29 '20 17:07 AJIXuMuK

Also experiencing this issue. I found that the OOTB Text webpart does not lazy load, I think due in part to allowing for headers to become anchors. If there's any way to expose that to webparts we create, that would be awesome!

tgorgdotcom avatar Sep 01 '20 17:09 tgorgdotcom

We can also confirm that the OOTB Text webpart is directly loaded on the page, independent of it's position. Is there any setting/attribute that we can pass to our webparts in order to achieve the same behaviour?

netti01 avatar Sep 02 '20 07:09 netti01

I observed it is not working for OOTB webparts too. On a large page I have added 15 ListWebparts and one custom webpart on top of those webpart in same section. Custom webpart is applying some css through jQuery on each ListWebParts, but due to this issues only few ListWebparts are having that css. So I believe this is all due to lazy loading of OOTB webparts too.

pratk30 avatar Sep 09 '20 03:09 pratk30

Hello @pratk30 Would you be able to try seeing if the OOTB Text webpart is lazy loaded on your end?

tgorgdotcom avatar Sep 11 '20 16:09 tgorgdotcom

Hello @pratk30 Would you be able to try seeing if the OOTB Text webpart is lazy loaded on your end?

@tgorgdotcom No, for this webpart this is not an issues. I mostly using document library OOTB webpart and having issues there. Only view port is created until you scrolled to webpart position.

pratk30 avatar Sep 15 '20 12:09 pratk30

We've also got this issue with attempting to implement anchor web parts with a navigation bar. The anchors that are out of the viewport will not be created and cannot be picked up by the receiving dynamic data source. If the page is scrolled to the bottom, the anchors will be picked up.

AdenKenny avatar Sep 23 '20 23:09 AdenKenny

This isn't the best forum for general issues with lazy loading. However the issue around dynamic data not registering should be fixed. Can you confirm this aspect?

patmill avatar Oct 01 '20 18:10 patmill

@patmill I can confirm that Dynamic Data is not registering data sources until you scroll to them.

AJIXuMuK avatar Oct 01 '20 19:10 AJIXuMuK

Hmn, so what is supposed to be happening is that if we detect that a webpart in the viewport depends on one outside, that the webpart outside the viewport should load (so that it can get the contextual info). Also, can you tell what build your site is running (view page source, search for "buildNumber" ). If all of the parts are outside the viewport, then neither will load. The idea being that the webparts render correctly, but they don't load unless needed.

patmill avatar Oct 01 '20 19:10 patmill

@patmill - what if I use the API approach to connect data sources and data consumers? The use case from the sample I linked here: We have a "navigation" web part and multiple "anchor" web parts. Navigation is a data consumer, anchors - data sources.

Navigation web part uses dynamicDataProvider object to get all the anchor data sources from the page (getAvailableDataSources) and registerAvailableSourcesChanged to be notified when something is changed on the page.

BUT. The navigation should know about all anchor web parts, even if they were not rendered yet. So, I would expect, getAvailableDataSources should return invisible web parts as well.

Build Number: sp-client-prod_2020-09-04.001

AJIXuMuK avatar Oct 01 '20 19:10 AJIXuMuK

I just re-estimated some of our open issues of this year, and this has been one of them. Actually our anchor webparts did not work anymore for half a year now. But I really like to share one additional finding that may workaround this issue for some cases.

If you call your page with an anchor link that does not exist, somehow the browser searches for it within the page and this causes all spfx webparts to get loaded (skips lazy loading), so your anchors should all appear. Try it out! (for us it works at least in Chrome)

/sites/yourSite/SitePages/MyAnkerPage.aspx#THISANCHORDOESNOTEXIST

netti01 avatar Dec 29 '20 15:12 netti01

I just re-estimated some of our open issues of this year, and this has been one of them. Actually our anchor webparts did not work anymore for half a year now. But I really like to share one additional finding that may workaround this issue for some cases.

If you call your page with an anchor link that does not exist, somehow the browser searches for it within the page and this causes all spfx webparts to get loaded (skips lazy loading), so your anchors should all appear. Try it out! (for us it works at least in Chrome)

/sites/yourSite/SitePages/MyAnkerPage.aspx#THISANCHORDOESNOTEXIST

I was unable to see the webparts outside the viewport even when scrolling down

adding the #XXXXX worked well for me 💯 thank you

kmarwen avatar Jan 18 '21 18:01 kmarwen

Is there any update regarding this topic? We need a stable solution for this behaviour despite the workaround #dummyanchor..

TitanRobot avatar Apr 07 '21 09:04 TitanRobot

WebPart is not initialized until brought into view-port.

Unfortunately adding the anchor tag isn't a viable solution.

Ludwixix avatar Aug 11 '21 08:08 Ludwixix

Any updates on this? Is someone from Microsoft looking at it, or considering to fix this? I can't ask all my customers to visit pages with a hash in the URL...

Although it is working - this is absurd... We need a way to be able to disable lazy loading on a page, programmatically, or better yet - disable this feature. It is causing so many issues that are very hard to trace and diagnose.

shaipetel avatar Aug 25 '21 18:08 shaipetel

Agree to @shaipetel - it causes a lot of trouble and it should be possible to be deactivated on demand

TitanRobot avatar Aug 26 '21 08:08 TitanRobot

It's unlikely that we will disable lazy-load. From the thread, it's hard to see if this is all scoped to dynamic data components, or if there is some other problem. Can you let me know what the problems you are facing are?

patmill avatar Aug 26 '21 16:08 patmill

My issue is that our customers may add the same component several time to the page and each component needs to be aware of other instances for some internal display logic.

Another issue was if I want to have a TOC web part that will jump into content from another web part using the anchor/hash navigation. This doesn't work now since it only disables the lazy-load if the initial page load had a hash in it, not when you add a hash on a button click for example.

I'm sure there are many, many other examples/issues/reasons why this may cause problems.

And I'm not saying disable it always for everyone. I'm saying allow the web part on the page to set if it allows to be lazy-loaded or if it is required to load every time.

A simple web part property would do just fine, or any other way.

You guys can't break functionality without documenting it and just say "its unlikely we will disable it"... people are building solutions based on this framework... if that's the attitude, their solutions won't be reliable and people will move to more stable platforms. That's just my opinion.

I'm hoping this is addressed soon.

shaipetel avatar Aug 26 '21 18:08 shaipetel

Sorry if my answer came across as flippant. The problem with loading and executing all webparts on a page is that it can have a very bad impact on page perf, and that makes end users unhappy. So - looking at options here - do you need knowledge of the parts, or do you need them executing? Would visibility into which webparts (but not running them through their life cycle) help unblock your scenarios?

patmill avatar Aug 26 '21 20:08 patmill

If I have a “pre-init” event where they just get their properties but don’t render it’s good enough!

shaipetel avatar Aug 26 '21 20:08 shaipetel

At first I hoped the constructor is called. But it’s not... and even if it did - it doesn’t have the properties so it’s not good enough sadly.

shaipetel avatar Aug 26 '21 20:08 shaipetel

Unfortunately, pre-init / init can cause grief as well, particularly in the case of a) very large bundles or b) a lot of logic in the pre-init. However (thinking out loud), would seeing the list of webparts that are in the canvas and their config help? I don't know if a manifest level per-webpart-type setting would be a) possible or b) solve issues on things like anchors, etc. (again - brainstorming here)

patmill avatar Aug 26 '21 20:08 patmill

Being able to query for all instances of a web part by ID, and get their saved properties is all I would need.

shaipetel avatar Aug 26 '21 20:08 shaipetel

OK, thanks @shaipetel - what about @TitanRobot / @kmarwen ?

patmill avatar Aug 26 '21 20:08 patmill

One more test case - printing.

We have a component that suppose to print the page with all content in it. Having this lazy loading was a huge pain, since web parts were just not loaded to the page.

So, again, in some cases we would just need the entire page to be rendered.

shaipetel avatar Aug 26 '21 20:08 shaipetel

@patmill our main issue is the page section navigation (https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-page-sections-navigation)

On large sites we use the page section navigation to structure the site. Each area gets a heading with an anchor and then we use the anchor tags for navigation.

Unfortunatelly due to lazy loading not all anchors are present at the beginning. So the header navigation webpart cannot render all headings/anchors.

For us the solution would be, that all anchors are always known. As a workaround we are linking to these sites like: test.aspx#k but this is not working in all scenarios (search result, normal user sends link to site etc.)

TitanRobot avatar Aug 27 '21 05:08 TitanRobot

OK, thanks @shaipetel - what about @TitanRobot / @kmarwen ?

Hi The issue for us was only about custom webparts. They were not loaded if we arrive to the page from a new tab or new session. The anchor with '#' at the end of the link worked for us and that what we deployed because we had only couple of links. I agree it's not a viable solution and Microsoft may provide a better workaround. Thank you

kmarwen avatar Aug 27 '21 08:08 kmarwen

Hi @kmarwen, can you confirm the proposed workaround with '#' is working on your site?

We are facing the same issue with anchors to WebPart that was not rendered on the page yet (Anchors are included in 3rd party "Modern Script Editor" WebPart).

Thanks

salascz avatar Sep 17 '21 07:09 salascz