Skip to content

Commit c7a03fd

Browse files
authored
chore: add new performance-oriented docs (vuestorefront#6636)
1 parent 0215c5b commit c7a03fd

File tree

8 files changed

+563
-50
lines changed

8 files changed

+563
-50
lines changed

packages/core/docs/.vuepress/config.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,12 @@ module.exports = {
174174
title: 'Performance',
175175
collapsable: true,
176176
children: [
177-
['/performance/performance', 'Performance basics'],
177+
['/performance/intro', 'Introduction'],
178+
['/performance/improving-core-web-vitals', 'Improving Core Web Vitals'],
179+
['/performance/optimizing-html-and-css', 'Optimizing HTML and CSS'],
180+
['/performance/optimizing-images', 'Optimizing images'],
181+
['/performance/optimizing-javascript', 'Optimizing JavaScript'],
182+
['/performance/other-optimizations', 'Other optimizations'],
178183
['/performance/ssr-cache', 'SSR cache']
179184
]
180185
},
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Improving Core Web Vitals
2+
3+
Web Vitals are unified and simplified metrics created by Google to help site owners understand the quality of experience they are delivering to their users. Core Web Vitals are the subset of Web Vitals focused on three aspects of the user experience - loading (LCP), interactivity (FID), and visual stability (CLS).
4+
5+
[Read more about Web Vitals](https://web.dev/vitals/).
6+
7+
## Largest Contentful Paint (LCP) :orange_book:
8+
9+
The Largest Contentful Paint (LCP) represents the time needed to display the biggest element visible to the user within the initial viewport. To improve the LCP metric, you need to start loading that element as fast as possible. If it needs an asset like JavaScript, CSS, image, or font, use the "preloading". It's a technique for telling a browser to download a resource before it discovers it's needed.
10+
11+
For example, you might have a font that the browser can discover late (because it first needs to download and parse the CSS file), but you know that it's critical to your website. You can preload it, so once the browser parses the CSS and finds out that the font is needed, it will already have it downloaded.
12+
13+
[Read more about preloading critical assets](https://web.dev/preload-critical-assets/).
14+
15+
Below we describe two ways of preloading resources in Nuxt.js, depending on your needs.
16+
17+
::: warning Be careful
18+
Preloading too many resources can have the opposite effect and impact the performance.
19+
20+
Try to limit the number of resources preloaded to just those visible on the initial viewport. **If you prioritize everything, you don't prioritize anything**.
21+
:::
22+
23+
### Preloading resource on every page
24+
25+
If you want to preload a resource on every page, e.g., the font used across the whole website, use the `head` property in the `nuxt.config.js` file.
26+
27+
:::tip
28+
If you are using Google Fonts, we recommend loading them using the [@nuxtjs/google-fonts](https://google-fonts.nuxtjs.org/) package. It offers reasonable defaults and performance-oriented options.
29+
:::
30+
31+
```javascript
32+
// nuxt.config.js
33+
34+
export default {
35+
head: {
36+
link: [
37+
{
38+
rel: 'preload',
39+
as: 'style',
40+
href: '.../stylesheet.css'
41+
}
42+
]
43+
}
44+
};
45+
```
46+
47+
### Preloading resource on a specific page
48+
49+
If you want to preload a resource on a specific page, e.g., a hero image used only on the homepage, use the `head` method in the Vue.js component.
50+
51+
::: tip
52+
If you use the [@nuxt/image](https://image.nuxtjs.org/) package, you don't have to use the `head` method. Instead you can add ["preload" attribute](https://image.nuxtjs.org/components/nuxt-img#preload) to the `<nuxt-img>` component.
53+
:::
54+
55+
```vue
56+
<script>
57+
export default {
58+
head() {
59+
return {
60+
link: [
61+
{
62+
rel: 'preload',
63+
as: 'image',
64+
href: '...',
65+
}
66+
]
67+
}
68+
}
69+
};
70+
</script>
71+
```
72+
73+
### How to identify what is the Largest Contentful Paint
74+
75+
The easiest way to learn which element is the Largest Contentful Paint is to use the Core Web Vital test on the [WebPageTest](https://www.webpagetest.org/webvitals) page. Enter the website URL, select one of the recommended locations and browsers, and click the `Start Test` button.
76+
77+
Another option is to run Lighthouse in Chrome DevTools, described on [Google Developers](https://developers.google.com/web/tools/lighthouse#devtools) website.
78+
79+
## Cumulative Layout Shift (CLS) :orange_book:
80+
81+
Cumulate Layout Shift is an important user-centric metric for measuring visual stability, which shows if page had any unexpected movement.
82+
83+
[Read more about CLS](https://web.dev/cls/)
84+
85+
When the browser parses the HTML, it will reserve the space for images based on their `width` and `height` attributes. When they are not defined, the browser will not do that, and when the image is loaded, it will have to make space for it by moving all other content causing layout shift.
86+
87+
### Always declare image width and height
88+
89+
To prevent layout shifts, always use the image `width` and `height` attributes to let the browser know how much space it needs to save. Remember to do it for all images, including header logos.
90+
91+
::: tip
92+
If you are using the [@nuxt/image](https://image.nuxtjs.org/) package, you can use the same attributes in the `<nuxt-img>` component.
93+
:::
94+
95+
```html
96+
<img
97+
src="..."
98+
width="128"
99+
height="128"
100+
>
101+
```
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Introduction to Web Performance
2+
3+
Web performance is important subject in modern web. Google study over millions of page impressions found that when a site meets the recommended thresholds for the Core Web Vitals metrics, users are at least 24% less likely to abandon a page before it finishes loading. You can read more [on Chromium blog](https://blog.chromium.org/2020/05/the-science-behind-web-vitals.html).
4+
5+
On the following pages you will find list of good practices that will help you optimize your website performance.
6+
7+
## The indicators
8+
9+
We marked some sections with the indicator below to show how impactful each problem can be:
10+
11+
:orange_book: - Most important. When fixed, the usability of your website should noticeably improve.
12+
13+
:ledger: - Nice to have. Fixing them could improve the performance.
14+
15+
:blue_book: - Optional fixes, which might help in some cases.
16+
17+
## Additional resources
18+
19+
Other great resources that helped us in writing these suggestions:
20+
21+
* [web.dev](https://web.dev/)
22+
* [sitesped.io](https://www.sitespeed.io/)
23+
* [Jakub Andrzejewski blog post](https://dev.to/theandrewsky/performance-checklist-for-vue-and-nuxt-cog)
24+
* [wpostats.com/](https://wpostats.com/)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Optimizing HTML and CSS
2+
3+
Large render-blocking CSS files and extensive DOM can significantly impact page performance. Below we share some tips on how to prevent that.
4+
5+
## Remove unused styles :ledger:
6+
7+
Removing unused styles reduces the amount of data needed to be sent through the network and the rendering time because the browser has fewer styles to process.
8+
9+
The `@vue-storefront/nuxt` package present in every Vue Storefront project has a `purgeCSS` option that does this exact thing.
10+
11+
```javascript{6-13}
12+
// nuxt.config.js
13+
14+
export default {
15+
buildModules: [
16+
['@vue-storefront/nuxt', {
17+
performance: {
18+
purgeCSS: {
19+
enabled: true,
20+
paths: [
21+
'**/*.vue'
22+
]
23+
}
24+
}
25+
}]
26+
]
27+
};
28+
```
29+
30+
`purgeCSS` option (_disabled by default_) uses [nuxt-purgecss](https://github.com/Developmint/nuxt-purgecss) plugin to remove unused CSS and accepts the same options, with two differences:
31+
32+
* with `enabled: false`, the plugin will not be registered at all, not only be disabled
33+
34+
* `**/*.vue` is added to `paths` array to detect all `.vue` files in your project, including those from `_theme` directory. Without this, the plugin would also remove some styles used on the page.
35+
36+
If you decide to enable this plugin, we recommend using `enabled: process.env.NODE_ENV === 'production'`, to keep development mode as fast as possible.
37+
38+
::: warning
39+
Because PurgeCSS looks for whole class names in files, it may remove styles for dynamic classes. If you're using a dynamic class, make sure you use whole names instead of concatinating variables (eg. `isDev ? 'some-style-dev' : 'some-style-prod'` instead of `some-style-${ isDev ? 'dev' : 'prod' }`. If this can't be avoided, add them to `whitelist` array.
40+
:::
41+
42+
## Use HTTP2 Push :blue_book:
43+
44+
HTTP2 Push is a performance technique to reduce latency by loading resources even before the browser knows it will need them.
45+
46+
Consider a website with three resources:
47+
48+
* index.html,
49+
* styles.css,
50+
* scripts.js.
51+
52+
First, the browser will load and parse index.html. While parsing, it will find information about styles.css and script.js, sending a request to the server to get them. Because we know that the page needs those two files, we can use HTTP2 Push to send them to the client immediately without waiting for the client to request them.
53+
54+
```javascript{6-8}
55+
// nuxt.config.js
56+
57+
export default {
58+
buildModules: [
59+
['@vue-storefront/nuxt', {
60+
performance: {
61+
httpPush: true
62+
}
63+
}]
64+
]
65+
};
66+
```
67+
68+
The `httpPush` option (_enabled by default_) leverages [http2](https://nuxtjs.org/docs/2.x/configuration-glossary/configuration-render#http2) option in Nuxt.js. It's configured to automatically push all JavaScript files needed for the current page. If you want to override this behavior, you can disable this option and use the Nuxt.js configuration instead.
69+
70+
If you can't use HTTP2, you can disable this option. In this case, Nuxt.js will still `preload` these scripts, which is only slightly slower than the HTTP2 push.
71+
72+
## Avoid extensive DOM size :ledger:
73+
74+
Large DOM will increase memory usage, cause longer style calculations, and produce costly layout reflows. In your components, try to make as flat structure as possible and avoid nesting HTML elements. Check if the library you use doesn't create complex HTML structures. There are cases when a simple button generates 1000 lines of code.
75+
76+
## Don't load print stylesheets :blue_book:
77+
78+
Loading a specific stylesheet for printing slows down the page, even when not used. You can include the print styles inside your other CSS file(s) by using an `@media` query targeting type print.
79+
80+
81+
```css
82+
@import url("fineprint.css") print;
83+
```
84+
85+
## Don't import SCSS files from StorefrontUI :ledger:
86+
87+
`@vue-storefront/nuxt` module automatically detects if you have the `@storefront-ui/vue` package installed and, registers [@nuxtjs/style-resources](https://github.com/nuxt-community/style-resources-module) module. It automatically registers all variables, mixins, and functions from StorefrontUI, which means you don't have to import them. Importing SCSS files from StorefrontUI might duplicate some styles, significantly increasing your bundle size and impacting performance.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Optimizing images
2+
3+
Images are likely the most straightforward resource to optimize. Yet if you forget to do it for at least one of them, your website might become a few megabytes heavier.
4+
5+
On this page, we will share some tips on how you can prevent that.
6+
7+
## Use the `@nuxt/image` package :orange_book:
8+
9+
Using the [`<nuxt-img>`](https://image.nuxtjs.org/components/nuxt-img) component from the [@nuxt/image](https://image.nuxtjs.org/) package is likely the single best thing you can do to stop worrying about images. It offers features for most of the things mentioned in the following sections. Using most of them only requires you to pass a single attribute.
10+
11+
It offers image resizing, converting formats, preloading, and integrations with the most popular image transformation services.
12+
13+
```html
14+
<nuxt-img
15+
src="/hero-image.png"
16+
format="webp"
17+
quality="80"
18+
width="200"
19+
height="100"
20+
loading="lazy"
21+
/>
22+
```
23+
24+
## Compress images using next-generation formats :orange_book:
25+
26+
The most common performance bottlenecks are images that are not compressed and weigh multiple times more than they should. For this reason, you should always compress images, and luckily nowadays, there are plenty of lossless and lossy file types supported in modern browsers.
27+
28+
If you have just a few static images on your website, you can manually compress them using a website like [Squoosh.app](https://squoosh.app/). However, if you have more images or want it to happen automatically, you can use the `@nuxt/image` package mentioned above.
29+
30+
## Don't declare images in CSS :ledger:
31+
32+
Images declared in the CSS files are often downloaded much later than those in HTML because the browser has to download and parse the CSS file before knowing that it has to load and display an image.
33+
34+
If the image is also the biggest element visible to the user within the initial viewport, it will also negatively impact the [Largest Contentful Paint](/performance/improving-core-web-vitals.html#largest-contentful-paint-lcp) time.
35+
36+
```diff
37+
- <style>
38+
- .hero {
39+
- background-image: url("/hero-image.png")
40+
- }
41+
- </style>
42+
43+
+ <div class="hero">
44+
+ <img src="/hero-image.png">
45+
+ </div>
46+
```
47+
48+
## Lazy load offscreen images :orange_book:
49+
50+
Lazy loading is a technique used to prevent or delay the loading of non-critical resources until they are needed. You can use this mechanism for different types of resources, but in the case of images, our goal is to lazily load everything that is not visible to the user within the initial viewport. All other images can be loaded when the user scrolls down the page.
51+
52+
Use the `loading="lazy"` attribute to load an image lazily. It also works for the `<nuxt-img>` component.
53+
54+
```html
55+
<img src="..." loading="lazy">
56+
<nuxt-image src="..." loading="lazy" />
57+
```
58+
59+
If you want to load resources other than images lazily, check out the [vue-lazyload](https://www.npmjs.com/package/vue-lazyload) package.
60+
61+
## Scale images on the server, not browser :orange_book:
62+
63+
Don't download big images to scale them down in the browser because it results in downloading data and processing that you could have avoided. Instead, use a tool or service that creates multiple versions of the same image server-side and serves the appropriate one depending on the size.
64+
65+
Here's the example using the `<nuxt-img>` component that will handle this automatically.
66+
67+
```html
68+
<nuxt-img
69+
src="/hero-image.png"
70+
width="300"
71+
height="300"
72+
sizes="sm:100vw md:50vw lg:400px"
73+
/>
74+
```

0 commit comments

Comments
 (0)