Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazy load BCD table #96

Closed
7 tasks
peterbe opened this issue Sep 4, 2019 · 6 comments · Fixed by #1416
Closed
7 tasks

Lazy load BCD table #96

peterbe opened this issue Sep 4, 2019 · 6 comments · Fixed by #1416
Labels
p3 We don't have visibility when this will be addressed.

Comments

@peterbe
Copy link
Contributor

peterbe commented Sep 4, 2019

The BCD table is always far down. So it shouldn't block the rendering path.
Also, we should totally consider to use an intersection observer so that we only bother to load it if the user scrolls it into view.

Goal: Smaller HTML, smaller index.json, less CSS, less JS CPU work; still perfectly fine looking BCD table for those who scroll down.

  • On SSR render, figure out a way to put a placeholder only.
  • Lazy load its .css bundle
  • Lazy load the component
  • Trigger loading with an intersection observer
  • All the __compat stuff in the index.json files should be omitted.
  • We might want to preload things in case the user eventually scrolls the BCD table into view.
  • If the user is clearly on a fast connection (using the few Web APIs that exists for that), could we just go ahead and load the BCD table anyway. If it's done in a non-main-thread blocking kinda way, what's the harm if the user never scrolls down later?
@peterbe
Copy link
Contributor Author

peterbe commented Oct 17, 2019

I made a rough branch that started implementing this. First, the cli needs to break the packaged JSON apart into index.json and bcd.json. How I did that wasn't particularly important but now some important changes took place:

  1. The rendered HTML file didn't have the full BCD table. It just has this: https://gist.github.com/peterbe/900567790e7025181e2c811fc0c111f4

  2. The serialized state, instead of {"type":"browser_compatibility","value":{"__compat":{ ... it now had {"type":"browser_compatibility","value":{"uri":"bcd.json"}}

  3. Once the browser React mounts the <BrowserCompatibilityTable/> component, instead of displaying the provided data from a prop, it used that provided uri as a prop and did fetch(uri) to get the "meat".

  4. The final HTML file rendered by the cli has less HTML and less serialized JSON.

  5. The same amount of data needs to travel from the server to the client. Instead of one big index.html (or index.json) it now has a note and a separate bcd.json file. So, less data up-front but a necessary XHR request.

You can see the result here: https://stumptown-peterbe-lazy-load-bcd-tables.s3-us-west-1.amazonaws.com/en-US/docs/Web/HTML/Element/video/index.html
(compare to this which might change by the time you read this)

That index.html size difference was as follows:

  • Before: 140K (19K gzip)
  • After: 70K (15K gzip) + bcd.json 15K (1.0K gzip)

So, before the browser had to download 19K, now it has to download 15K + 1K = 16K.

If this wasn't a direct hit but that the user client-side navigated to the page, the index.json size difference was as follows:

  • Before: 60K (9.0K gzip)
  • After: 40K (8.0K gzip) + bcd.json 15K (1.0K gzip)

So, before the browser had to download 9K, now it has to download 8K + 1K = 9K.

Basically, there's a small win here in terms of amount of data that needs to be shipped from the CDN to the client. But the browser's JS now has to do more, which is to start an XHR request and once that comes back execute the React component and update the DOM. That's potentially additional load on the main thread but in principle it's work that can start after the page has been fully rendered and considered complete.

Smaller data up-front means the browser can get started displaying useful above-the-fold content sooner. But more CPU work is needed by the browser, although it's reasonably nicely staggered.

@peterbe
Copy link
Contributor Author

peterbe commented Oct 17, 2019

The next step is to not just lazy-load the data but also fully lazy load the JavaScript and maybe also the CSS. That follows the same principle as above but just more extreme. The initial doc's CSS and JS will be smaller but that JS and CSS still needs to be transmitted from the server to the browser.

@peterbe
Copy link
Contributor Author

peterbe commented Oct 17, 2019

Perhaps the next step now is to wrap the browser BrowserCompatibilityTable in an IntersectionObserver so that only when you actually scroll down does the extra XHR needs to be downloaded and processed.

This feels somewhat orthogonal to the idea of code splitting but perhaps safest to do one thing at a time.

peterbe added a commit to peterbe/yari that referenced this issue Oct 17, 2019
peterbe added a commit to peterbe/yari that referenced this issue Oct 24, 2019
@peterbe
Copy link
Contributor Author

peterbe commented Jun 5, 2020

I just wanted to drop a note so I don't lose the research.
See this page:
https://d24on6m5y27ek3.cloudfront.net/en-us/docs/web/html/element/canvas/index.html
It contains all the data you need, serialized as JSON, in the HTML document.
If you look careful enough you'll notice a LOT of that data comes from the browser-compat-data which exists there to help the browser-compatability-table ingredient be able to build the table.

If you remove that data, from the serialized JSON, how does that affect the HTML? Here's the answer:

▶ ls -ltrh index.html*
-rw-r--r--  1 peterbe  staff   234K Jun  5 15:17 index.html
-rw-r--r--  1 peterbe  staff    37K Jun  5 15:17 index.html.gz
-rw-r--r--  1 peterbe  staff    26K Jun  5 15:24 index.html.nobcd.gz
-rw-r--r--  1 peterbe  staff   126K Jun  5 15:24 index.html.nobcd

Basically, we can make the document 11KB smaller by not having the BCD table server-side rendered in the document.

@peterbe
Copy link
Contributor Author

peterbe commented Jul 9, 2020

#187 is now rotten. Also that PR solved it by creating one bcd.json table per occurence of a BCD table in the page. And if a page had 3 BCD tables, it would have created bcd.json, bcd-2.json, and bcd-3.json. That sucked. It should have just created a bcds.json file that is key'ed by the query ID instead.

@peterbe
Copy link
Contributor Author

peterbe commented Jul 9, 2020

Important note-to-self; a great test page is this one: http://localhost:5000/en-US/docs/Mozilla/Add-ons/WebExtensions/Browser_support_for_JavaScript_APIs/

@tobinmori tobinmori added the p3 We don't have visibility when this will be addressed. label Jul 21, 2020
peterbe added a commit to peterbe/yari that referenced this issue Oct 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p3 We don't have visibility when this will be addressed.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants