Skip to content

[labs/virtualizer] Simplify initialization, more complete fix for #3481#3624

Merged
usergenic merged 11 commits intolit:mainfrom
graynorton:simplify-virtualizer-init
Feb 2, 2023
Merged

[labs/virtualizer] Simplify initialization, more complete fix for #3481#3624
usergenic merged 11 commits intolit:mainfrom
graynorton:simplify-virtualizer-init

Conversation

@graynorton
Copy link
Copy Markdown
Contributor

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Jan 31, 2023

🦋 Changeset detected

Latest commit: 6438670

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@lit-labs/virtualizer Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@augustjk augustjk requested a review from usergenic February 1, 2023 01:05
@usergenic
Copy link
Copy Markdown
Contributor

@graynorton I'll look at publishing the ResizeObserver polyfill and removing the included loader and version entirely in a future version, but I like the steps this takes towards that. And there's ResizeObserver polyfill+native behavior tests to boot! Nice!

I think I understand the move away from CustomEvents being dispatched by the layouts to an explicit Layout Message channel too as it is more intention-revealing. Makes it clearer where they're coming from and why.

Copy link
Copy Markdown
Contributor

@usergenic usergenic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!


async function load() {
await loadPolyfillIfNeeded();
await import('@lit-labs/virtualizer');
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be instructive to show this happening at the app level, like before dynamic importing the main app code in a bootstrap script. You could use top-level await there.

Copy link
Copy Markdown
Contributor Author

@graynorton graynorton Feb 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered that briefly, but was struggling to do so in a way that didn't seem overly precise / prescriptive or make too many assumptions about typical app structure, so I ended up falling back to this minimal, more conceptual sketch. Feel free to propose (or just go ahead and make) a better example.

private _pendingLayoutComplete: number | null = null;

/**
* Layout initialization is async because we dynamically load
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How big is the default layout? Could we just statically import it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can dig into the size numbers and reconsider the tradeoffs here, but the default flow layout is non-trivial in size, and previous thinking was that it was definitely worth not forcing folks to pay that cost if they were using an alternative layout.

Another option, which we actually briefly tried out at some point in the 0.x history, is to always require a layout to be explicitly loaded and provided by the app. The DevEx hit for the 80% case was unfortunate, though, so we reverted to dynamically auto-loading.

At this point, with all of the async polyfill stuff out of the picture and some kinks worked out, I think we've converged on a dynamic loading scheme that isn't too heavy and shouldn't cause much trouble going forward, so my inclination is to keep this as-is for now.

@graynorton
Copy link
Copy Markdown
Contributor Author

I think I understand the move away from CustomEvents being dispatched by the layouts to an explicit Layout Message channel too as it is more intention-revealing. Makes it clearer where they're coming from and why.

@usergenic Yeah, I think it is clearer and more direct (and we weren't really benefiting from the indirection), but the main reason I did it as part of this particular PR was to eliminate the use of EventTarget and the associated polyfill. In doing this at the same time as we stop auto-loading the ResizeObserver polyfill, we get rid of all of the async initialization code except for the default layout loading.

@usergenic
Copy link
Copy Markdown
Contributor

I'm not certain why the tests-local and benchmarks checks are failing. The failures are in the localize examples /home/runner/work/lit/lit/packages/localize/examples/transform-js/rollup.config.mjs is importing @rollup/plugin-typescript which "can't be found".

I don't get that error running any builds/tests locally. As soon as I can get the check passing I'll get this merged in.

scrollSize: {
[this._sizeDim]: this._scrollSize,
[this._secondarySizeDim]: null,
} as Size,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tiny nit: it seems the virtualiser actually handles nullish dimensions. is it worth updating Size to reflect that and drop the cast here?

in the virtualiser it already checks size.width !== null etc even though the type says it can't ever be null

near enough a non-issue but maybe still worth me pointing out

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good observation; however, I think it might be a longer thread than we want to pull on as part of this PR. The Size type is used in quite a few places in the Virtualizer code base, and I am quite certain that in some of them the logic doesn't anticipate or guard against null values. My inclination is to take care of this independently of this PR, perhaps as part of a more systematic review of internally used types. @usergenic, thoughts?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@graynorton @43081j I'm all for considering making Size nullable as separate PR. It will give time to fully vet the change; there's enough going on here already.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup of course. Didn't mean to distract at all. Was mostly an observation 👍

@usergenic
Copy link
Copy Markdown
Contributor

This test failure is persistent now on CI but is not happening on my local machine which indicates a possible issue hidden by environment characteristics. I'll look to see if test can be adjusted or will add a .skip and comment until such adjustment possible

test/scenarios/element-and-directive-parity.test.js:

 ❌ lit-virtualizer and virtualize directive > both render changes based on non-item data changes
      AssertionError: expected 2 to equal 1
      + expected - actual
      
      -2
      +1
      
      at o.<anonymous> (test/scenarios/element-and-directive-parity.test.js:[156](https://github.com/lit/lit/actions/runs/4070763955/jobs/7012246645#step:8:157):50)

…event to adjust to inconsistent behavior in different runs/environments.
@usergenic
Copy link
Copy Markdown
Contributor

Have adjusted the expectation in the test from an equal to a greaterThanOrEqual as it was been expecting a number of events that may not be completely deterministic since RangeChangedEvents are emitted in reaction to environmental factors like resize observers etc and timing differences may play a role. Check is passing now :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants