Server-side rendering uses blocking <script> tags having a negative impact to page load performance
See original GitHub issueDescribe the problem
Currently, SvelteKit server-side rendering puts all loaded JavaScript to <head>
section of the page. This negatively affects the user-perceived performance, as First Contentful Paint (FCP) is delayed because the browser spends time loading often heavy .js files.
This is how the JavaScript loading looks in the server-side rendered page. It is using modulepreload that is blocking:
<head>
<link rel="modulepreload" href="/_app/chunks/vendor-87f5cdbf.js">
</head>
Because the full HTML page is rendered on the server-side in any case, there is no reason for blocking the load with <script>
within <head>
.
A more detailed breakdown of <script> tags in SvelteKit can be found in this StackOverflow question.
Here is the related Vite issue.
Describe the proposed solution
The JavaScript only needs to load after the page is hydrated. For non-hydrated pages, no JavaScript is needed at all.
- When the server-side page is rendered use
<script defer async>
instead of<link rel="modulepreload">
for the JavaScript. defer attribute is documented here
Alternatives considered
Alternatively, all JavaScript can be loaded before closing </body>
- Break down
app.html
template to separatesvelte.head
andsvelte.scripts
sections. - Move all JavaScript loading to
svelte.scripts
that is placed before</body>
Importance
would make my life easier
Additional Information
SvelteKit should ship with very optimised server-side rendering settings, as this will positively affect the perceived quality of SvelteKit and teach newcomers the best way of doing server-side rendered pages.
Some client-side JavaScript may be required to be loaded in head
. However, this is more of an exception on nowadays and such JavaScript is unlikely to work with server-side rendering in any case.
For such JavaScript files and bundles, the existing client-side only JavaScript loading should be applied.
Here is someone’s workaround that he post-processes HTML and strips away modulepreload.
Issue Analytics
- State:
- Created 2 years ago
- Comments:14 (6 by maintainers)
I can confirm this is fixed. The CSS loads now first, then JS and the First Contentful Paint (FCP) happens as soon as possible.
Fixed in https://github.com/sveltejs/kit/commit/d138efe21692f5925f1e89afc0a33f42d6a1a711