[Free] How to radically optimize image rendering speed within repeating groups

Hello Bubble forum :sweat_smile:
Posting some content for the community.

Let me start by showing you something, on the following video, both apps are made on Bubble.
Now, can you tell what we changed to have such a performance difference?

If you had been me a few years ago, youā€™ll probably answer in a very condescending way:

This is just basic repeating group pagination :unamused:

Well, it is not, but actually, a little bit, let me explain ā€” and I promise Iā€™ll give you everything you need to implement it!

Hereā€™s what weā€™ll cover:

  1. Understanding what pre-fetching is
  2. Limitations study
  3. Building a repeating group with pagination
  4. Building our pre-fetcher system
  5. Re-integrating Imgix with custom HTML

In order words, weā€™ll upgrade our Bubble skills from this to that:

Understanding Prefetching

After seriously investigating repeating groupsā€™ behaviour last year at Flusk, and trying to implement image pre-fetching we discovered that the way Bubble processes images are not what we thought!

Pre-fet-cin what?

If you donā€™t know what pre-fetching is, thatā€™s a way to reduce the perceived loading time of a repeating group using two tweaks:

  • Firstly: using pagination (you got meā€¦) to only show a necessary amount of items in the repeating group in the first place, youā€™ve probably seen those ā€œsee moreā€ buttons, thatā€™s it. This avoids loading hundreds of database items if the user is only willing to access the first row.
  • Second: when the visible elements in the repeating group are loaded, we prepare/preload the next set of elements to be shown if the user clicks the ā€œsee moreā€ button or scrolls down.
    At this stage, there should be no loading time at all when the user interacts.

Hereā€™s how pre-fetching works on Bubble for visual learners:

Prefetching on Bubble.io

Considerable speed improvement happens when the user interacts.

Pre-fetching a repeating group can be achieved in many ways ā€” the easiest is by using another repeating group, but weā€™ll get back to that later!

The Big Discovery

We then built our Bubble pre-fetcher, butā€¦ it didnā€™t work.
Usually, when your browser downloads the RG items when the user clicks on ā€œsee moreā€ (blue bubble on the flowchart - in our case images), it knows that the items we pre-fetched are already in the cache, and can be used instead of downloading a new set of data.

But apparently, this was not the case with Bubble, and we found out why!
It all came from a specific way Bubble handles image elements.

This is the behaviour we expected to see happening:

Expected RG behaviour

Expected image load behaviour

Instead, this is what we observed:
Bubble sends a different version of the same image for each element because of its Imgix processing ā€” a.k.a something to not send 1000px images when shown into a 10x10px element.

Actual image load behaviour in RG

The actual image load behaviour

And this behaviour happens even without using the*:processed with Imgx* suffix on your image.

Try it yourself -or check this: add an image element and save the URL of the image in the editor, then preview and compare with the URL of the image on your rendered/previewed page!

See? Itā€™s different! Thereā€™s now something in front of the URL that looks like dwdwa.cloudfront.net. Thatā€™s the Imgix processing.

Now, how does that affects our pre-fetching system?
Let me get us back to my flowchart:

When Bubble pre-fetches the images in the pre-fetcher repeating group, it downloads a unique version X of the images.
But when my user interacts with the ā€œsee moreā€ button, my original repeating group looks for version Y of the images.

Since it canā€™t find it, it downloads the images again when the button is clicked, which kills the entire purpose of the pre-fetching!

The fix to The Solution

To avoid this Imgix processing required for our pre-fetching system, we, therefore, need to use this simple trick by adding this parameter to our image URLs:

?ignore_imgix=true

How to Build Pre-fetching in Bubble

We talked enough, letā€™s jump right in.

In order to be able to prefetch a repeating groupā€™s content, we need two elements as mentioned above:

  1. A repeating group with pagination, which we will call ā€œMain RGā€
  2. The pre-fetching system can be done using CSS, JS, and many other ways but for the sake of simplicity, weā€™ll just use another repeating group, which we will call ā€œFetcher RGā€.

1. Main RG with pagination

Letā€™s start with a basic repeating group Main RG which will display a list of images from the database.

Somewhere, weā€™ll create a custom state that will hold the number of images to display, with a default value of 2 images.

We can now use this value to restrict the number of items to show in our Main RG

We almost have our pagination ready! The last step is to add a button for the user to be able to display more items.
This could also be done on scroll for an advanced UX design!

Weā€™re done, you can check the result here in case you missed something.

So letā€™s first assess how fast our repeating group and images load:

2. Pre-fetching images with our Fetcher RG

The previous example was slow, right? I mean itā€™s Bubble, right?
Yes, but itā€™s Bubble for the newbies, and youā€™re about to become a pro of Bubble optimizing!

Now, we need a second repeating group, our Fetch RG, to display the same list and the same images.
Huun, why?

Because this repeating group will actually be hidden somewhere (1px/1px) and load the number of images plus the number of images to prefetch!
So in our case, it will load 2+2 images, so when the user clicks on ā€œsee moreā€, the next 2 images will be ready!

In the Fetcher RG, I add two more images to the list to fetch

Note: you can also prefetch more than 2 additional images if you expect the user to be scrolling fast

Once weā€™ve done that, we need to mind the issue we encountered earlier!

The Imgix processing is about to ruin our work because it will download different images from the Main RG and the Fetcher RG.

The same image (in yellow) is being downloaded twice because it has different URLs (version X and Y)

Remember the fix?
Simply add the following to your image elementā€™s URL in both repeating groups:

Woohoo! We improved, and now our RG is loading faster whenever we click on the ā€œsee moreā€ button.

VoilĆ , this is what it looks like, and hereā€™s a record for you:

3. But what about our friend Imgix

Yes, you may have noticed, but weā€™re now completely skipping the native Imgix processing!
But thatā€™s not a victory, because Imgix is actually our friend.
It allows fast image compression and resizing on the server side, and this must be part of our optimization strategy!

The following part is a little more complex and irritating

So how do we keep pre-fetching knowing that:

  • Bubble automatically adds Imgix processing to image elements
  • We canā€™t use Imagix because it breaks the pre-fetcher

Well, we donā€™t use image elements anymore :partying_face:

For the last example, weā€™re using HTML elements instead of image elements.

So letā€™s go ahead and replace our old image elements with freshly-designed HTML elements.
Inside, we still want to display an image, so we use the following code snippet:

<img src="[IMAGE]" width="100%" height="100%">

From there, we can then apply Imgix processing manually, by adding the Imgix server prefix, and the desired processing parameters at the end.
It looks like that:

<img src="https://d1muf25xaso8hp.cloudfront.net/https:[IMAGE_URL_ENCODED]?w=384&h=384&auto=compress&dpr=2&fit=max&q=50" width="100%" height="100%">

You just need to take care of formatting the URL as URL Encoded to ensure everything runs smoothly.

Hereā€™s what it looks like for an image with dimensions provided, and quality to be set to 35%. The full list of Imgix parameters can be found here- and there are way more than in the native Bubble editor!

We then apply the same settings to our Fetcher RG to ensure they both download the same images while forcing the Imgix processing.

Hooray :partying_face: We made it. The repeating group is now much faster.

See the result here or there:

Conclusion

Bubble isnā€™t slow, and we need to get this idea out of peopleā€™s minds, itā€™s just built to be accessible to everyone, and while this presents limitations, we can always overcome them! :raised_hands:

The technique used above can be applied for different use cases, not only images!
If youā€™re interested in another in-depth tutorial about pre-fetching any data type, feel free to comment the post and Iā€™ll send it to you as soon as itā€™s released!

In the meantime, here are some sweet options:

Extras:


Victor from Flusk

Black_512x512 Flusk - a hub of tools and services for Bubble makers and businesses

78 Likes

very instructive Thanks for sharing.

Thanks :+1:

Absolutely on point for my current project which is an image rich app for tourismā€¦I will be implementing thisā€¦and subscribing as wellā€¦well done and thanks

Happy it helps, feel free to share the difference if you get a chance to!

Thank you so much, this is great!

I had tried to implement prefetching using a hidden RG in the past, however it wasnā€™t working and i didnā€™t know why. Thanks for the explanation and solution!

Hey @vnihoul77 If I wanted to go with on scroll rather than having a ā€˜see moreā€™ button, what would be required to implement that? Just canā€™t quite get my head around it!

2 Likes

This is great! Iā€™m interested in another in-depth tutorial about pre-fetching any data type.

5 Likes

Sure, hereā€™s how you can do that:

I am using the following plugin to detect the scroll position of the RG:

Then, when the position is more than 70%, I add the same workflow to display more items in my repeating group.


Hereā€™s the demo:

6 Likes

@vnihoul77 super helpfulā€¦thank you again!

BTW I went to sub to your Blog but could not find itā€¦do you just have the Medium or another?

Thank you for a brilliant concept and so clearly explained. :muscle:t2:

Iā€™ve tinkered with Image RGs a bit and for some use case I preload the entire data set.

I also had a challenge. Even if preloading the entire dataset there was a lag when I re-populated the RG (think going down into sub categories with new images). The old images were still there and were swapped out in ā€œone by oneā€. So, my problem was the rendering of the ā€œnewā€ images in the RG. Maybe my workaround was along your suggestion of not gettings caught up by Imgix processing, without me knowing about that, since I instead of an image element used a picture uploader element.

Cheers, Peter

thank you @vnihoul77!

Yes, we had this issue too!
Iā€™m not sure which part made the fix but Iā€™m pretty sure itā€™s the HTML element that repopulates quicker.
Hereā€™s an example:

ezgif-1-d75fd66021

4 Likes

Deffo makes sense.

This is such useful content, thank you very much for the explanation and your time. Not complex, well explained. I would recommend rereading the post once again when one has played around with the optimization, that made me understand better each of the diagrams.

I would definitely read the next tutorial, looking forward!

I guess itā€™s time to learn the power of Imgix.

Just updated the links that were dead, thanks @ranganathd

1 Like

Fantastic write-up. As a guy with a social media app, vertical feed, etc, this is very interesting. Iā€™m currently using pagination because we know bubble does not like to load hundreds of rg items whether it be at once, or even over time.

My question is, is there any merit to using a trick like this, if Iā€™m not using native image elements in my RG?

I use a plugin called Unite Gallery which handles Photos, Videos, etc. Iā€™m not sure if itā€™s possible to pre-fetch that stuff

1 Like

Secondly, is there any way we can pre-fetch other types of content?

Iā€™m going to reread your post again, but if I have social media posts on the next page, is there a way to prefetch that as the user scrolls the page?

I wouldnā€™t just be prefetching images anymore, but text & groups and stuff along with icons and buttons.

Thanks for the comment @drixxon

This is indeed possible as well! We use the same method it to prefetch repeating groups that will be displayed, or other tabs for single pages so that the switch is instant.
Hereā€™s what it looks like with a tab switch with different data (text + images) within a RG also:

Iā€™ll write another tutorial soon! :smiley:

4 Likes

Good heavens that is bonkers. I am very much looking forward to your next tutorial as this is exactly what I need!!!