question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Async script output

See original GitHub issue

Clear and concise description of the problem

Currently Vite outputs <script type="module"> scripts which are executed in deferred mode. Although this is a lot better than the blocking default of standard <script> tags, it does have an issue with streaming.

Specifically defer does not execute any scripts until DOMContentLoaded has fired. This means that if you are using SSR + streaming (or even if your document is sufficiently large to be parsed by the browser in multiple segments) that no scripts execute until the browser receives the final byte of html.

This is especially bad with streaming + partial hydration, where you are intentionally are sending down sections of interactive html and would like for it to hydrate ASAP. Instead right now in Vite hydration will be blocked until streaming has finished.

Simply adding async to these scripts causes them to download asynchronously without blocking the rest of the document (as the name implies) similar to defer, however it also allows the scripts to execute as soon as they are downloaded.

Adding async blindly to Vite’s output scripts as it stands would cause a race condition for common setups though, since they could be relying on the document being complete by the time initialization code runs, for example:

import { hydrate } from "popular-library";
hydrate(document.getElementById("my-app"), ...);

This does not account for the case where the script has downloaded and is ready, but the #my-app content has not yet been sent by the server.

It would be nice if there was some way to preserve the simple behavior of Vite to support the above without much complexity, while also allowing a way to opt into the async style hydration.

Suggested solution

One potential option could be to support a special handling of <script async type="module" src="..."/> in the .html files. We could perhaps use this to indicate that the chunk being loaded is capable of initializing immediately. I think this might be a bit tricky though since technically you can have multiple scripts in your .html file that would get merged into the same chunk and loaded together.

Alternative

One not so great option would be to have a dynamic import in the .html file like:

<script type="module">
  import("./my-actual-entry");
</script>

This is a bit verbose though and currently does not seem to actually work. A naive compilation of this might also introduce an additional network waterfall, which trades one perf issue with another.

Additional context

I’m not clear on the solution here but wanted to get the discussion started. Happy to create a PR if we can decide on a direction.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:2
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
DylanPierceycommented, Jul 27, 2021

I’d be happy to work on it but I’ve got several other things on my plate for the moment. Probably won’t be able to put up a PR for a couple weeks.

1reaction
ryansolidcommented, Apr 26, 2021

Yeah I hit this while working Solid plugin a few weeks back as well. We ended up doing an inline plugin like:

{
      name: "html-async",
      enforce: "post",
      transformIndexHtml(html) {
        return html.replace('type="module"', 'type="module" async');
     }
}

But really any library that wants to take advantage of progressive rendering would want this feature so that scripts can start loading and executing before the document is finished streaming in. Without it progressive rendering(streaming) loses its primary benefit.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Script result: Async - StackState Docs
Multiple asynchronous script results can be chained together. This is useful for combining for example the results of topology with telemetry.
Read more >
HTML script async Attribute - W3Schools
The async attribute is a boolean attribute. If the async attribute is set, the script is downloaded in parallel to parsing the page,...
Read more >
async function - JavaScript - MDN Web Docs - Mozilla
The async function declaration declares an async function where the await keyword is permitted within the function body. The async and await ......
Read more >
Efficiently load JavaScript with defer and async - Flavio Copes
The script is fetched asynchronously, and when it's ready the HTML parsing is paused to execute the script, then it's resumed. With defer,...
Read more >
bash how to get async command output to variable
2 · it have output , svcrack is python script · I said no output on stdout. · As an aside, variables are...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found