DioxusLabs / dioxus

Fullstack GUI library for web, desktop, mobile, and more.
https://dioxuslabs.com
Apache License 2.0
19.37k stars 747 forks source link

Optimize initial loading of web resources #2124

Open ochrons opened 3 months ago

ochrons commented 3 months ago

Feature Request

Currently loading a web app built with Dioxus has some performance issues especially under high latency networks. Looking at the waterfall analysis of a Dioxus load (under "Fast 3G" option in Edge browser) you'll see following:

image

Disregarding the long download time for the WASM file (debug build), we can see several places that can be improved. The root cause of the unnecessary delay is the sequential loading of static resources, which slows things down even when the resources are small, due to network latency.

Implement Suggestion

There are two improvements that will have significant effect and are fairly trivial to implement.

Bundle the JS files into a single asset, avoiding the dynamic loading of six separate files.

This change alone will cut about a second of loading time in a high latency network. Under the current strategy the browser can only download additional script files once it has started executing the previous ones and encounters the import statement.

Browsers typically restrict the number of concurrent connections, so this creates additional latency when there are many files to download and it needs to wait for a connection to become available. The bundle file should have a content hash in its name.

Instruct the browser to preload assets in the HEAD section.

See https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/preload for details.

By introducing <link rel=preload href="main.js" as="script" /> preloading hint for every resource needed later, the browser will start loading these immediately, instead of waiting for the rest of the index.html to be processed. Note that for the WASM file you'll need to use crossorigin as well since it's a fetch.

For example I tested by manually editing the index.html to prove that the browser indeed starts downloading files earlier:

  <link rel="preload" href="/./assets/dioxus/Zhef_bg.wasm" as="fetch" crossorigin>
  <link rel="preload" href="/./assets/dioxus/Zhef.js" as="script">
  <link rel="preload" href="./snippets/dioxus-interpreter-js-e8d4f2300616f4bc/inline0.js" as="script">
  <link rel="preload" href="./snippets/dioxus-interpreter-js-e8d4f2300616f4bc/src/js/common.js" as="script">
  <link rel="preload" href="./snippets/dioxus-web-aa233b06656766d9/inline0.js" as="script">
  <link rel="preload" href="./snippets/dioxus-web-aa233b06656766d9/inline1.js" as="script">
  <link rel="preload" href="./snippets/dioxus-web-aa233b06656766d9/src/eval.js" as="script">

image

This is still not optimal due to the limit of concurrent downloads imposed by the browser.

The preload aspect should also be made available for the developers who might be adding resources via Dioxus.toml

Add a hash to the WASM file name

Adding a content hash to the name of the WASM file will enable efficient caching of the resource by browsers and CDNs alike. This will not help with the initial cold load, but will allow the browser (and CDN) to cache the file indefinitely. Of course the caching headers will also need to be set by the server.