shoelace-style / shoelace

A collection of professionally designed, every day UI components built on Web standards. SHOELACE IS BECOMING WEB AWESOME 👇👇👇
https://webawesome.com
MIT License
12.95k stars 831 forks source link

CDN: many requests and too much data transferred over the network to use just a few components #2190

Closed BinaryIgor closed 1 month ago

BinaryIgor commented 1 month ago

First of all, thank you for this amazing library!

Describe the bug

By using CDN and cherry picking components, I still see rather significant network load; dozens of requests are made and hundreds of kilobytes are being fetched.

To Reproduce

Create empty HTML page with shoelace css and a few CDN components like this:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Shoelace Data Size</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn/themes/light.css">
</head>
<body>
  <h1>Empty Shoelace Page To Show Data Size</h1>     
  <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn/components/button/button.js"
        data-shoelace="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn"></script>
  <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn/components/icon/icon.js"
        data-shoelace="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn"></script>
  <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn/components/qr-code/qr-code.js"
        data-shoelace="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn"></script>
  <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn/components/input/input.js"
        data-shoelace="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn"></script>
  <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn/components/select/select.js"
        data-shoelace="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn"></script>
  <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn/components/option/option.js"
        data-shoelace="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn"></script>
        <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn/components/divider/divider.js"
        data-shoelace="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn"></script>
   <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn/components/dialog/dialog.js"
        data-shoelace="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn"></script>
   <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn/components/checkbox/checkbox.js"
        data-shoelace="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn"></script>
   <script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn/components/textarea/textarea.js"
        data-shoelace="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.17.0/cdn"></script>
</body>
</html>   

Expose it on the local HTTP server and check out network tab in the browser to see network activity.

Screenshots

I've exposed the above HTML on HTTP server locally; here's definitely too high network activity I'm talking about (lots of requests, lots of data for just a few components): Screenshot from 2024-09-28 09-45-06 Screenshot from 2024-09-28 09-47-54

Mian-Ahmed-Raza commented 1 month ago

It seems like you're encountering a significant amount of network load when using Shoelace components via CDN. Even though you're cherry-picking individual components, the number of requests and the size of data being fetched remain substantial. This is a common issue when using CDN-hosted web components like Shoelace, especially if the components have many dependencies or include polyfills for browser compatibility.

  1. Bundle the components: Instead of loading each component separately from the CDN, consider bundling them into a single file using a module bundler like Webpack or Rollup. This can significantly reduce the number of requests.

  2. Use a Local Copy: Instead of loading the Shoelace components from a CDN, you could download the necessary components and host them locally. This allows more control over what's being loaded and reduces the need for repeated requests to the CDN.

`<!DOCTYPE html>

Shoelace Optimized

Optimized Shoelace Page

`

  1. I've added the defer attribute to ensure that the scripts are loaded only after the HTML content is fully parsed. This helps improve page loading speed.
  2. Components like qr-code, select, and option are lazy-loaded via dynamic imports. This means they'll only be fetched when needed, reducing the initial network load.
  3. Fewer components: I removed some components to focus on the ones that you specifically mentioned. Make sure that the page only loads what it needs.
claviska commented 1 month ago

The advice above is sound. The CDN + autoloader is the quickest and easiest way to get started. For advanced usage and the most compact bundle size/low requests possible, use a bundled and self host it.

closing as this is by design

BinaryIgor commented 1 month ago

Got you, but unfortunately with bundler size is also rather significant - still a few hundred kilobytes. I just think that something is bundled/minified in the Sholeace itself incorrectly.

Using similar setup to the official example:

import '@shoelace-style/shoelace/dist/themes/light.css';
// import '@shoelace-style/shoelace/dist/themes/dark.css';
import SlButton from '@shoelace-style/shoelace/dist/components/button/button.js';
import SlIcon from '@shoelace-style/shoelace/dist/components/icon/icon.js';
import SlInput from '@shoelace-style/shoelace/dist/components/input/input.js';
import SlRating from '@shoelace-style/shoelace/dist/components/rating/rating.js';
import SlSelect from '@shoelace-style/shoelace/dist/components/select/select.js';
import SlOption from '@shoelace-style/shoelace/dist/components/option/option.js';
import SlTextarea from '@shoelace-style/shoelace/dist/components/textarea/textarea.js';
import SlDialog from '@shoelace-style/shoelace/dist/components/dialog/dialog.js';
import { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path.js';

// Set the base path to the folder you copied Shoelace's assets to
setBasePath('/dist/shoelace');

My bundle size is almost 300 KB: image

I understand that the smallest possible bundle size might not by a priority of the Web Components library but a few hundred kilobytes, for just a few components suggests to me that something went wrong while bundling them - it's way too much, I would expect 1/4 or 1/5 of this size.

KonnorRogers commented 1 month ago

@BinaryIgor you have a repository you can share? There's a few things that can be causing this, but I need a reproduction to be able to know for sure.

BinaryIgor commented 1 month ago

Yes, it's a little intermingled with other things but you should be able to reproduce it by following from here: https://github.com/BinaryIgor/code-examples/tree/web-components-experiments/htmx-shoelace-app/static

BinaryIgor commented 1 month ago

@KonnorRogers were you able to take a look?

KonnorRogers commented 1 month ago

@BinaryIgor yes.

So your example isn't Gzipping the components which is probably inflating the number more than you would expect.

With gzip enabled that size goes from 288kb uncompressed down to 63kb compressed with gzip, probably even smaller with Brotli.

Screenshot 2024-09-30 at 12 35 56 PM
BinaryIgor commented 1 month ago

Got you; I am aware of this and was just thinking that they should be smaller even without compression. Thanks!

KonnorRogers commented 1 month ago

@BinaryIgor part of it is that <sl-select> is probably the biggest component because it's composed of many other shoelace components , used floating UI, etc.

iirc when I removed the select it accounted for almost half the size of the JS you see.