-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
docs: further clarify and reinforce the performance impacts of single page apps (SPAs) #11637
base: main
Are you sure you want to change the base?
Conversation
|
Co-authored-by: Willow (GHOST) <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gotta push back on the language of these changes and some of these changes in general - it sounds like we're on a crusade against SPA mode now. This creates FUD ("omg SPA mode always bad", which isn't true because it depends on your site) and may turn people off from using SvelteKit ("ok so they hate SPA I'll look for another framework that supports it better") which helps neither web vitals nor us.
I think there are other avenues to explore:
- some kind of SvelteKit dev tools which somehow analyzes your page and gives you some tips what you can improve, where this plays a part
- partial prerendering which will improve perceived performance and probably web vitals
- understanding why people opt for SPA mode in the first place and solve the roadblocks towards leaving SSR enabled
@@ -46,6 +46,6 @@ In SvelteKit, you can do static site generation by using [`adapter-static`](adap | |||
|
|||
## SSR | |||
|
|||
Server-side rendering (SSR) is the generation of the page contents on the server. SSR is generally preferred for SEO. While some search engines can index content that is dynamically generated on the client-side it may take longer even in these cases. It also tends to improve perceived performance and makes your app accessible to users if JavaScript fails or is disabled (which happens [more often than you probably think](https://kryogenix.org/code/browser/everyonehasjs.html)). | |||
Server-side rendering (SSR) is the generation of the page contents on the server. Returning the page contents from the server via SSR (including with prerendering) is highly preferred for performance and SEO. It drastically improves performance by avoiding the introduction of an extra round trip necessary in a SPA and makes your app accessible to users if JavaScript fails or is disabled (which happens [more often than you probably think](https://kryogenix.org/code/browser/everyonehasjs.html)). While some search engines can index content that is dynamically generated on the client-side it is likely to take longer even in these cases. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't really true - it's more about the perceived performance. The HTML is already there, but you still have the second roundtrip of fetching the JS which hydrates your stuff and then it's interactive. If your page doesn't work without JS it might feel just as bad.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'roundtrip' refers to the data that is inlined into the page (whether in the form of serialised server data or inlined event.fetch
responses)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And if your site is content to be read, it's much more than perceived performance - it's actual performance
Co-authored-by: Simon H <[email protected]>
Co-authored-by: Simon H <[email protected]>
…conflicting with prerendering
I pushed an update to the docs to recommend using a name other than |
Co-authored-by: Tee Ming <[email protected]>
Co-authored-by: Tee Ming <[email protected]>
@@ -70,7 +72,7 @@ The directory to write static assets (the contents of `static`, plus client-side | |||
|
|||
### fallback | |||
|
|||
Specify a fallback page for [SPA mode](single-page-apps), e.g. `index.html` or `200.html` or `404.html`. | |||
To create a [single page app (SPA)](single-page-apps) you must specify the name of the fallback page to be generated by SvelteKit, which is used as the entry point for URLs that have not been prerendered. This is commonly `200.html`, but can vary depending on your deployment platform. You should avoid `index.html` where possible to avoid conflicting with a prerendered homepage. Note that this option has large negative performance and SEO impacts and is recommended only in very limited circumstances such as when being wrapped in a mobile app. See the [single page apps](single-page-apps) documentation for more details and alternatives. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To create a [single page app (SPA)](single-page-apps) you must specify the name of the fallback page to be generated by SvelteKit, which is used as the entry point for URLs that have not been prerendered. This is commonly `200.html`, but can vary depending on your deployment platform. You should avoid `index.html` where possible to avoid conflicting with a prerendered homepage. Note that this option has large negative performance and SEO impacts and is recommended only in very limited circumstances such as when being wrapped in a mobile app. See the [single page apps](single-page-apps) documentation for more details and alternatives. | |
To create a [single page app (SPA)](single-page-apps) you must specify the name of the fallback page to be generated by SvelteKit, which is used as the entry point for URLs that have not been prerendered. This is commonly `200.html`, but can vary depending on your deployment platform. You should avoid `index.html` where possible to avoid conflicting with a prerendered homepage. | |
> This option has large negative performance and SEO impacts. It is only recommended in certain circumstances such as wrapping the site in a mobile app. See the [single page apps](single-page-apps) documentation for more details and alternatives. |
@@ -2,20 +2,21 @@ | |||
title: Single-page apps | |||
--- | |||
|
|||
You can turn any SvelteKit app, using any adapter, into a fully client-rendered single-page app (SPA) by disabling SSR at the root layout: | |||
You can turn a SvelteKit app into a fully client-rendered single-page app (SPA) by specifying a _fallback page_ that will be served for any URLs that can't be served via another means such as by returning a prerendered page. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can turn a SvelteKit app into a fully client-rendered single-page app (SPA) by specifying a _fallback page_ that will be served for any URLs that can't be served via another means such as by returning a prerendered page. | |
You can turn a SvelteKit app into a fully client-rendered single-page app (SPA) by specifying a _fallback page_. This page will be served for any URLs that can't be served by other means such as returning a prerendered page. |
|
||
> SPA mode has a large negative performance impact by forcing two network round trips before rendering can begin. This may be acceptable if you are serving an application from the local network (e.g. a mobile app that wraps a locally-served SPA), but probably is not for most websites on the internet especially when considering the latency of mobile devices. It also harms SEO by often causing sites to be downranked for performance (SPAs are much more likely to fail core web vitals), excluding search engines that don't render JS, and causing your site to receive less frequent updates from those that do. And finally, it makes your app inaccessible to users if JavaScript fails or is disabled (which happens [more often than you probably think](https://kryogenix.org/code/browser/everyonehasjs.html)). | ||
> | ||
> You can avoid these drawbacks on a given page by [prerendering it](#prerendering-individual-pages). You should thus prerender as many pages as possible when using SPA mode — especially your homepage. If you can prerender all pages, you can simply use [static site generation](adapter-static) rather than a SPA. If you cannot, you should strongly consider using an adapter which supports server side rendering — SvelteKit offers officially supported adapters for multiple different providers that offer free SSR hosting for sites below a certain threshold. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
> You can avoid these drawbacks on a given page by [prerendering it](#prerendering-individual-pages). You should thus prerender as many pages as possible when using SPA mode — especially your homepage. If you can prerender all pages, you can simply use [static site generation](adapter-static) rather than a SPA. If you cannot, you should strongly consider using an adapter which supports server side rendering — SvelteKit offers officially supported adapters for multiple different providers that offer free SSR hosting for sites below a certain threshold. | |
> You can avoid these drawbacks on a given page by [prerendering it](#prerendering-individual-pages). You should thus prerender as many pages as possible when using SPA mode — especially your homepage. If you can prerender all pages, you can simply use [static site generation](adapter-static) rather than a SPA. Otherwise, you should strongly consider using an adapter which supports server side rendering — SvelteKit has officially supported adapters for various providers that offer free SSR hosting for sites below a certain threshold. |
|
||
## Usage | ||
|
||
First, disable SSR for the pages you don't want to prerender. These pages will be seved via a fallback page. E.g. to serve all pages via the fallback by default, you can update the root layout as shown below. You should [opt back into prerendering individual pages and directories](#prerendering-individual-pages) where possible. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, disable SSR for the pages you don't want to prerender. These pages will be seved via a fallback page. E.g. to serve all pages via the fallback by default, you can update the root layout as shown below. You should [opt back into prerendering individual pages and directories](#prerendering-individual-pages) where possible. | |
First, disable SSR for the pages you don't want to prerender. These pages will be served via the fallback page. E.g. to serve all pages via the fallback by default, you can update the root layout as shown below. You should [opt back into prerendering individual pages and directories](#prerendering-individual-pages) where possible. |
- Enabling [single page app (SPA) mode](single-page-apps) will cause such waterfalls. With SPA mode, an empty page is generated, which fetches JavaScript, which ultimately loads and renders the page. This results in an extra network roundtrip before a single pixel can be displayed. | ||
|
||
Waterfalls can also occur on calls to the backend whether made from the browser or server. E.g. if a universal `load` function makes an API call to fetch the current user, then uses the details from that response to fetch a list of saved items, and then uses _that_ response to fetch the details for each item, the browser will end up making multiple sequential requests. This is deadly for performance, especially for users that are physically located far from your backend. | ||
- Avoid this issue by using [server `load` functions](/docs/load#universal-vs-server) to make requests to backend services that are dependencies from the server rather than from the browser. Note, however, that server `load` functions are also not immune to waterfalls (though they are much less costly since they rarely involve roundtrips with high latency). For example if you query a database to get the current user and then use that data to make a second query for a list of saved items, it will typically be more performant to issue a single query with a database join. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Avoid this issue by using [server `load` functions](/docs/load#universal-vs-server) to make requests to backend services that are dependencies from the server rather than from the browser. Note, however, that server `load` functions are also not immune to waterfalls (though they are much less costly since they rarely involve roundtrips with high latency). For example if you query a database to get the current user and then use that data to make a second query for a list of saved items, it will typically be more performant to issue a single query with a database join. | |
- Avoid this issue by using [server `load` functions](/docs/load#universal-vs-server) to make requests to backend services that are dependencies from the server rather than from the browser. Note, however, that server `load` functions are also not immune to waterfalls (though they are much less costly since they rarely involve roundtrips with high latency). For example, if you query a database to get the current user and then use that data to make a second query for a list of saved items, it will typically be more performant to issue a single query with a database join. |
@@ -10,6 +10,10 @@ Client-side rendering (CSR) is the generation of the page contents in the web br | |||
|
|||
In SvelteKit, client-side rendering will be used by default, but you can turn off JavaScript with [the `csr = false` page option](page-options#csr). | |||
|
|||
## Hybrid app | |||
|
|||
SvelteKit uses a hybrid rendering mode by default where it loads the initial HTML from the server (SSR) and the updates the page contents on subsequent navigations via client-side rendering (CSR). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SvelteKit uses a hybrid rendering mode by default where it loads the initial HTML from the server (SSR) and the updates the page contents on subsequent navigations via client-side rendering (CSR). | |
SvelteKit uses a hybrid rendering mode by default where it loads the initial HTML from the server (SSR), then updates the page contents on subsequent navigations via client-side rendering (CSR). |
@@ -34,9 +38,9 @@ In SvelteKit, client-side routing will be used by default, but you can skip it w | |||
|
|||
## SPA | |||
|
|||
A single-page app (SPA) is an application in which all requests to the server load a single HTML file which then does client-side rendering of the requested contents based on the requested URL. All navigation is handled on the client-side in a process called client-side routing with per-page contents being updated and common layout elements remaining largely unchanged. SPAs do not provide SSR, which has the shortcoming described above. However, some applications are not greatly impacted by these shortcomings such as a complex business application behind a login where SEO would not be important and it is known that users will be accessing the application from a consistent computing environment. | |||
A single-page app (SPA) is an application in which all requests to the server load a single HTML file which then does client-side rendering based on the requested URL. All navigation is handled on the client-side in a process called client-side routing with per-page contents being updated and common layout elements remaining largely unchanged. Throughout this site, when we refer to a SPA we use this definition where a SPA simply serves an empty shell on the initial request. It should not be confused with a [hybrid app](#hybrid-app), which serves HTML on the initial request. It has a large performance impact by forcing two network round trips before rendering can begin. Because SPA mode has large negative performance and SEO impacts, it is recommended only in very limited circumstances such as when being wrapped in a mobile app. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A single-page app (SPA) is an application in which all requests to the server load a single HTML file which then does client-side rendering based on the requested URL. All navigation is handled on the client-side in a process called client-side routing with per-page contents being updated and common layout elements remaining largely unchanged. Throughout this site, when we refer to a SPA we use this definition where a SPA simply serves an empty shell on the initial request. It should not be confused with a [hybrid app](#hybrid-app), which serves HTML on the initial request. It has a large performance impact by forcing two network round trips before rendering can begin. Because SPA mode has large negative performance and SEO impacts, it is recommended only in very limited circumstances such as when being wrapped in a mobile app. | |
A single-page app (SPA) is an application in which all requests to the server load a single HTML file which then does client-side rendering based on the requested URL. All navigation is handled on the client-side in a process called client-side routing with per-page contents being updated and common layout elements remaining largely unchanged. Throughout this site, when we refer to a SPA, we use this definition where a SPA simply serves an empty shell on the initial request. It should not be confused with a [hybrid app](#hybrid-app), which serves HTML on the initial request. It has a large performance impact by forcing two network round trips before rendering can begin. Because SPA mode has large negative performance and SEO impacts, it is recommended only in very limited circumstances such as when being wrapped in a mobile app. |
@@ -46,6 +50,6 @@ In SvelteKit, you can do static site generation by using [`adapter-static`](adap | |||
|
|||
## SSR | |||
|
|||
Server-side rendering (SSR) is the generation of the page contents on the server. SSR is generally preferred for SEO. While some search engines can index content that is dynamically generated on the client-side it may take longer even in these cases. It also tends to improve perceived performance and makes your app accessible to users if JavaScript fails or is disabled (which happens [more often than you probably think](https://kryogenix.org/code/browser/everyonehasjs.html)). | |||
Server-side rendering (SSR) is the generation of the page contents on the server. Returning the page contents from the server via SSR (including with prerendering) is highly preferred for performance and SEO. It drastically improves performance by avoiding the introduction of an extra round trip necessary in a SPA and makes your app accessible to users if JavaScript fails or is disabled (which happens [more often than you probably think](https://kryogenix.org/code/browser/everyonehasjs.html)). While some search engines can index content that is dynamically generated on the client-side it is likely to take longer even in these cases. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Server-side rendering (SSR) is the generation of the page contents on the server. Returning the page contents from the server via SSR (including with prerendering) is highly preferred for performance and SEO. It drastically improves performance by avoiding the introduction of an extra round trip necessary in a SPA and makes your app accessible to users if JavaScript fails or is disabled (which happens [more often than you probably think](https://kryogenix.org/code/browser/everyonehasjs.html)). While some search engines can index content that is dynamically generated on the client-side it is likely to take longer even in these cases. | |
Server-side rendering (SSR) is the generation of the page contents on the server. Returning the page contents from the server via SSR or prerendering is highly preferred for performance and SEO. It drastically improves performance by avoiding the introduction of an extra round trip necessary in a SPA and makes your app accessible to users if JavaScript fails or is disabled (which happens [more often than you probably think](https://kryogenix.org/code/browser/everyonehasjs.html)). While some search engines can index content that is dynamically generated on the client-side, it is likely to take longer even in these cases. |
A huge portion of SvelteKit apps in the wild that are failing core web vitals are single page apps. The percentage of SvelteKit apps which pass/fail are tracked on cwvtech.report leveraging data from HTTP Archive. Some folks at Google were able to supply me with a random sample of SvelteKit sites from this dataset. While investigating the failing sites, I saw that the most common cause of failure was extra round trips due to deployment as a SPA.