KonnorRogers / shoelace-rails-importmaps

Using Shoelace + Rails 7.0.0.alpha.2 + importmaps
4 stars 0 forks source link

Delay or flicker in loading Shoelace components #2

Closed fpsvogel closed 2 years ago

fpsvogel commented 2 years ago

Thanks for this! It helped me set it up in my app. But when I run the example app locally, I see a delay in Shoelace component loading, and in my app there is flickering during the page load for some Shoelace components. (Not sure why the difference. I haven't changed any Turbo configuration.) I'm attaching a video below showing both behaviors.

Is this to be expected? I noticed the same flickering issue before when I was loading Shoelace with a script tag instead: <script type="module" src="https://unpkg.com/@shoelace-style/shoelace@2.0.0-beta.57/dist/shoelace.js"></script>. Thanks!

https://user-images.githubusercontent.com/9300391/140349492-5bb4989e-ab52-44d4-a830-9df699a1a8ae.mp4

KonnorRogers commented 2 years ago

@fpsvogel this i believe is unfortunately expected. Because WebComponents do not currently support SSR with rails, the WC has to get loaded via JavaScript.

@claviska may be able to shed more light here, but I'm pretty sure this is expected.

fpsvogel commented 2 years ago

I see, thanks @ParamagicDev! Wanted to make sure I wasn't doing something wrong.

Looking forward to Rails SSR being possible someday, and in the meantime I may try GitHub's Primer components, though they don't look quite so user-friendly as Shoelace.

fpsvogel commented 2 years ago

On closer inspection, Primer is making frequent breaking changes these days, so maybe I'll stick with Shoelace after all, and simply not use a Shoelace component where the component flicker is distracting.

fpsvogel commented 2 years ago

I won't pester anymore after this, but I just want to be sure: is there any common workaround to this, to make the page load look smoother? Perhaps a certain Turbo/cache configuration? I'm very new to all this, so I don't know what the possibilities are, or the impossibilities.

In production it's easier to see that the components are there upon page load (from the cache?) and then the flicker happens when they are re-rendered. Here's a little video showing that:

https://user-images.githubusercontent.com/9300391/140405154-25fc49ff-067b-42bc-9699-ac700abd7fb0.mp4

claviska commented 2 years ago

The components are being rendered before they're loaded/styled. A couple things you can do to prevent FLOUC (let's call it "flash of unloaded components") with custom elements:

  1. Make sure the Shoelace stylesheet(s) are loaded in <head> (or baked into something that is)

  2. Wait for the elements you're using to be defined, e.g.

    //
    // Place all the custom elements you're using here
    //
    const tagsUsed = ['sl-button', 'sl-tag'];
    
    Promise.all(tagsUsed.map(tag => customElements.whenDefined(tag))).then(() => {
      //
      // All components have loaded now, transition in and show the UI here
      //
    });

You could also load Shoelace in the <head> as a blocking script, but that will slow down the initial page load so I wouldn't recommend it.

fpsvogel commented 2 years ago

@claviska Thank you! I've got (1) set up properly. I can't figure out how to use (2) in Rails, so I'll come back to it once I've spent some time learning the new Rails frontend tools such as Turbo, which seems like it will play a part in the solution.

claviska commented 2 years ago

@ParamagicDev I haven't looked into how you're loading Shoelace here, but are you able to obtain a list of tag names and provide a mechanism to users that tells them when they've fully resolved? (If you're loading all components, you can get the full tag list from custom-elements.json.)

Rails isn't my niche, so I'm not sure how that would fit in with users' expectations but it seems like this would be a common issue.

fpsvogel commented 2 years ago

I wanted to know for sure whether the flicker is caused by importmaps/bundling, and it seems it's not. I set up two small test apps, one in Rails 7 with ESBuild, and one in Rails 6 with Webpack. They show the same behavior as what I observed above.

I added a delay into each page, in order to simulate the processing delay in my app. (Without this artificial delay, the flicker is still there but it's less noticeable because it happens closer to the initial page load.)

In the Webpack test, I set up Shoelace according to the guide on integrating with Rails. In the ESBuild test, I tried loading Shoelace locally by copying the "dist" folder, but it seemed not to be available no matter where I saved it.

Repos: https://github.com/fpsvogel/shoelace-rails-esbuild-flicker https://github.com/fpsvogel/shoelace-rails-6-webpack-flicker

Rails 7 with ESBuild:

https://user-images.githubusercontent.com/9300391/140846999-9828dbf4-8f41-42dd-9e40-b823c03afd80.mp4

Rails 6 with Webpack:

https://user-images.githubusercontent.com/9300391/140847346-f0781b41-7c59-4220-9744-6e18ea63e331.mp4

fpsvogel commented 2 years ago

This issue is actually caused by cached page previews from Turbo. Thanks to @ParamagicDev and others in the StimulusReflex community on Discord for helping me find that out.

In case anyone stumbles on this in the future, the files below show how I fixed it in an example app. Note that I switched to ESBuild bundling because my importmap setup was not cooperating.

https://github.com/fpsvogel/shoelace-rails-esbuild-flicker/blob/main/app/javascript/application.js https://github.com/fpsvogel/shoelace-rails-esbuild-flicker/blob/main/app/javascript/controllers/hello_controller.js