You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/guide/best-practices/performance.md
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -10,7 +10,7 @@ Vue is designed to be performant for most common use cases without much need for
10
10
11
11
First, let's discuss the two major aspects of web performance:
12
12
13
-
-**Page Load Performance**: how fast the application shows content and becomes interactive on the initial visit. This is usually measured using web vital metrics like [Largest Contentful Paint (LCP)](https://web.dev/lcp/) and [First Input Delay](https://web.dev/fid/).
13
+
-**Page Load Performance**: how fast the application shows content and becomes interactive on the initial visit. This is usually measured using web vital metrics like [Largest Contentful Paint (LCP)](https://web.dev/lcp/) and [First Input Delay (FID)](https://web.dev/fid/).
14
14
15
15
-**Update Performance**: how fast the application updates in response to user input. For example, how fast a list updates when the user types in a search box, or how fast the page switches when the user clicks a navigation link in a Single-Page Application (SPA).
Copy file name to clipboardExpand all lines: src/guide/best-practices/security.md
+11-15Lines changed: 11 additions & 15 deletions
Original file line number
Diff line number
Diff line change
@@ -72,9 +72,9 @@ In any web application, allowing unsanitized, user-provided content to be execut
72
72
73
73
For example, services like CodePen and JSFiddle allow user-provided content to be executed, but it's in a context where this is expected and sandboxed to some extent inside iframes. In the cases when an important feature inherently requires some level of vulnerability, it's up to your team to weigh the importance of the feature against the worst-case scenarios the vulnerability enables.
74
74
75
-
### Injecting HTML
75
+
### HTML Injection
76
76
77
-
As you learned earlier, Vue automatically escapes HTML content, preventing you from accidentally injecting executable HTML into your application. However, in cases where you know the HTML is safe, you can explicitly render HTML content:
77
+
As you learned earlier, Vue automatically escapes HTML content, preventing you from accidentally injecting executable HTML into your application. However, **in cases where you know the HTML is safe**, you can explicitly render HTML content:
78
78
79
79
- Using a template:
80
80
@@ -96,11 +96,11 @@ As you learned earlier, Vue automatically escapes HTML content, preventing you f
96
96
<div innerHTML={this.userProvidedHtml}></div>
97
97
```
98
98
99
-
:::tip
100
-
Note that user-provided HTML can never be considered 100% safe unless it's in a sandboxed iframe or in a part of the app where only the user who wrote that HTML can ever be exposed to it. Additionally, allowing users to write their own Vue templates brings similar dangers.
99
+
:::warning
100
+
User-provided HTML can never be considered 100% safe unless it's in a sandboxed iframe or in a part of the app where only the user who wrote that HTML can ever be exposed to it. Additionally, allowing users to write their own Vue templates brings similar dangers.
101
101
:::
102
102
103
-
### Injecting URLs
103
+
### URL Injection
104
104
105
105
In a URL like this:
106
106
@@ -110,13 +110,9 @@ In a URL like this:
110
110
</a>
111
111
```
112
112
113
-
There's a potential security issue if the URL has not been "sanitized" to prevent JavaScript execution using `javascript:`. There are libraries such as [sanitize-url](https://www.npmjs.com/package/@braintree/sanitize-url) to help with this, but note:
113
+
There's a potential security issue if the URL has not been "sanitized" to prevent JavaScript execution using `javascript:`. There are libraries such as [sanitize-url](https://www.npmjs.com/package/@braintree/sanitize-url) to help with this, but note: if you're ever doing URL sanitization on the frontend, you already have a security issue. **User-provided URLs should always be sanitized by your backend before even being saved to a database.** Then the problem is avoided for _every_ client connecting to your API, including native mobile apps. Also note that even with sanitized URLs, Vue cannot help you guarantee that they lead to safe destinations.
114
114
115
-
:::tip
116
-
If you're ever doing URL sanitization on the frontend, you already have a security issue. User-provided URLs should always be sanitized by your backend before even being saved to a database. Then the problem is avoided for _every_ client connecting to your API, including native mobile apps. Also note that even with sanitized URLs, Vue cannot help you guarantee that they lead to safe destinations.
117
-
:::
118
-
119
-
### Injecting Styles
115
+
### Style Injection
120
116
121
117
Looking at this example:
122
118
@@ -151,21 +147,21 @@ To keep your users fully safe from click jacking, we recommend only allowing ful
151
147
</a>
152
148
```
153
149
154
-
### Injecting JavaScript
150
+
### JavaScript Injection
155
151
156
152
We strongly discourage ever rendering a `<script>` element with Vue, since templates and render functions should never have side effects. However, this isn't the only way to include strings that would be evaluated as JavaScript at runtime.
157
153
158
154
Every HTML element has attributes with values accepting strings of JavaScript, such as `onclick`, `onfocus`, and `onmouseenter`. Binding user-provided JavaScript to any of these event attributes is a potential security risk, so should be avoided.
159
155
160
-
:::tip
161
-
Note that user-provided JavaScript can never be considered 100% safe unless it's in a sandboxed iframe or in a part of the app where only the user who wrote that JavaScript can ever be exposed to it.
156
+
:::warning
157
+
User-provided JavaScript can never be considered 100% safe unless it's in a sandboxed iframe or in a part of the app where only the user who wrote that JavaScript can ever be exposed to it.
162
158
:::
163
159
164
160
Sometimes we receive vulnerability reports on how it's possible to do cross-site scripting (XSS) in Vue templates. In general, we do not consider such cases to be actual vulnerabilities, because there's no practical way to protect developers from the two scenarios that would allow XSS:
165
161
166
162
1. The developer is explicitly asking Vue to render user-provided, unsanitized content as Vue templates. This is inherently unsafe and there's no way for Vue to know the origin.
167
163
168
-
2. The developer is mounting Vue to an entire HTML page which happens to contain server-rendered and user-provided content. This is fundamentally the same problem as \#1, but sometimes devs may do it without realizing. This can lead to possible vulnerabilities where the attacker provides HTML which is safe as plain HTML but unsafe as a Vue template. The best practice is to never mount Vue on nodes that may contain server-rendered and user-provided content.
164
+
2. The developer is mounting Vue to an entire HTML page which happens to contain server-rendered and user-provided content. This is fundamentally the same problem as \#1, but sometimes devs may do it without realizing. This can lead to possible vulnerabilities where the attacker provides HTML which is safe as plain HTML but unsafe as a Vue template. The best practice is to **never mount Vue on nodes that may contain server-rendered and user-provided content**.
Copy file name to clipboardExpand all lines: src/guide/built-ins/keep-alive.md
+5-1Lines changed: 5 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -14,7 +14,7 @@ In the Component Basics chapter, we introduced the syntax for [Dynamic Component
14
14
<component :is="activeComponent" />
15
15
```
16
16
17
-
By default, an active component instance will be unmounted when switched away from. This will cause any changed state it holds to be lost.
17
+
By default, an active component instance will be unmounted when switched away from. This will cause any changed state it holds to be lost. When this component is displayed again, a new instance will be created with only the initial state.
18
18
19
19
In the example below, we have two stateful components - A contains a counter, while B contains a message synced with an input via `v-model`. Try updating the state of one of them, switch away, and then switch back to it:
20
20
@@ -73,6 +73,10 @@ By default, `<KeepAlive>` will cache any component instance inside. We can custo
73
73
74
74
The match is checked against the component's [`name`](/api/options-misc.html#name) option, so components that need to be conditionally cached by `KeepAlive` must explicitly declare a `name` option.
75
75
76
+
:::tip
77
+
Since version 3.2.34, a single-file component using `<script setup>` will automatically infer its `name` option based on the filename, removing the need to manually declare the name.
78
+
:::
79
+
76
80
## Max Cached Instances
77
81
78
82
We can limit the maximum number of component instances that can be cached via the `max` prop. When `max` is specified, `<KeepAlive>` behaves like an [LRU cache](<https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)>): if the number of cached instances is about to exceed the specified max count, the least recently accessed cached instance will be destroyed to make room for the new one.
Copy file name to clipboardExpand all lines: src/guide/built-ins/transition.md
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -499,7 +499,7 @@ Now `MyTransition` can be imported and used just like the built-in version:
499
499
500
500
## Transition on Appear
501
501
502
-
If you also want to apply a transition on the initial render of a node, you can add the `appear`attribute:
502
+
If you also want to apply a transition on the initial render of a node, you can add the `appear`prop:
503
503
504
504
```vue-html
505
505
<Transition appear>
@@ -509,7 +509,7 @@ If you also want to apply a transition on the initial render of a node, you can
509
509
510
510
## Transition Between Elements
511
511
512
-
In addition to toggling an element with `v-if` / `v-show`, we can also transition between two elements using `v-if` / `v-else` / `v-else-if`:
512
+
In addition to toggling an element with `v-if` / `v-show`, we can also transition between two elements using `v-if` / `v-else` / `v-else-if`, as long as we make sure that there is only one element being shown at any given moment:
As you can see, `defineAsyncComponent` accepts a loader function that returns a Promise. The Promise's `resolve` callback should be called when you have retrieved your component definition from the server. You can also call `reject(reason)` to indicate the load has failed.
20
20
21
-
[ES module dynamic import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports) also returns a Promise, so most of the time we will use it in combination with `defineAsyncComponent`. Bundlers like Vite and webpack also support the syntax, so we can use it to import Vue SFCs:
21
+
[ES module dynamic import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports) also returns a Promise, so most of the time we will use it in combination with `defineAsyncComponent`. Bundlers like Vite and webpack also support the syntax (and will use it as bundle split points), so we can use it to import Vue SFCs:
Copy file name to clipboardExpand all lines: src/guide/components/attrs.md
+2Lines changed: 2 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -29,6 +29,8 @@ The final rendered DOM would be:
29
29
<buttonclass="large">click me</button>
30
30
```
31
31
32
+
Here, `<MyButton>` did not declare `class` as an accepted prop. Therefore, `class` is treated as a fallthrough attribute and automatically added to `<MyButton>`'s root element.
33
+
32
34
### `class` and `style` Merging
33
35
34
36
If the child component's root element already has existing `class` or `style` attributes, it will be merged with the `class` and `style` values that are inherited from the parent. Suppose we change the template of `<MyButton>` in the previous example to:
Copy file name to clipboardExpand all lines: src/guide/components/events.md
+9-9Lines changed: 9 additions & 9 deletions
Original file line number
Diff line number
Diff line change
@@ -46,7 +46,7 @@ The `.once` modifier is also supported on component event listeners:
46
46
Like components and props, event names provide an automatic case transformation. Notice we emitted a camelCase event, but can listen for it using a kebab-cased listener in the parent. As with [props casing](/guide/components/props.html#prop-name-casing), we recommend using kebab-cased event listeners in templates.
47
47
48
48
:::tip
49
-
Unlike native DOM events, component emitted events do **not** bubble. You can only listen to the events emitted by a direct child component.
49
+
Unlike native DOM events, component emitted events do **not** bubble. You can only listen to the events emitted by a direct child component. If there is a need to communicate between sibling or deeply nested components, use an external event bus or a [global state management solution](/guide/scaling-up/state-management.html).
50
50
:::
51
51
52
52
## Event Arguments
@@ -203,7 +203,7 @@ See also: [Typing Component Emits](/guide/typescript/options-api.html#typing-com
203
203
204
204
</div>
205
205
206
-
Although optional, it is recommended to define all emitted events in order to better document how a component should work. It also allows Vue to exclude known listeners from [fallthrough attributes](/guide/components/attrs.html#v-on-listener-inheritance).
206
+
Although optional, it is recommended to define all emitted events in order to better document how a component should work. It also allows Vue to exclude known listeners from [fallthrough attributes](/guide/components/attrs.html#v-on-listener-inheritance), avoiding edge cases caused by DOM events manually dispatched by 3rd party code.
207
207
208
208
:::tip
209
209
If a native event (e.g., `click`) is defined in the `emits` option, the listener will now only listen to component-emitted `click` events and no longer respond to native `click` events.
@@ -271,13 +271,13 @@ export default {
271
271
272
272
## Usage with `v-model`
273
273
274
-
Custom events can also be used to create custom inputs that work with `v-model`. Remember that:
274
+
Custom events can also be used to create custom inputs that work with `v-model`. Let's revisit how `v-model` is used on a native element:
275
275
276
276
```vue-html
277
277
<input v-model="searchText" />
278
278
```
279
279
280
-
does the same thing as:
280
+
Under the hood, the template compiler expands `v-model` to the more verbose equivalent for us. So the above code does the same as the following:
281
281
282
282
```vue-html
283
283
<input
@@ -286,7 +286,7 @@ does the same thing as:
286
286
/>
287
287
```
288
288
289
-
When used on a component, `v-model` instead does this:
289
+
When used on a component, `v-model` instead expands to this:
290
290
291
291
```vue-html
292
292
<CustomInput
@@ -295,10 +295,10 @@ When used on a component, `v-model` instead does this:
295
295
/>
296
296
```
297
297
298
-
For this to actually work though, the `<input>`inside the component must:
298
+
For this to actually work though, the `<CustomInput>` component must do two things:
299
299
300
-
- Bind the `value` attribute to the `modelValue` prop
301
-
- On `input`, emit an `update:modelValue` event with the new value
300
+
1. Bind the `value` attribute of a native `<input>` element to the `modelValue` prop
301
+
2. When a native `input` event is triggered, emit an `update:modelValue` custom event with the new value
302
302
303
303
Here's that in action:
304
304
@@ -544,7 +544,7 @@ export default {
544
544
545
545
### Handling `v-model` modifiers
546
546
547
-
When we were learning about form input bindings, we saw that `v-model` has [built-in modifiers](/guide/essentials/forms.html#modifiers) - `.trim`, `.number` and `.lazy`. In some cases, however, you might also want to add your own custom modifiers.
547
+
When we were learning about form input bindings, we saw that `v-model` has [built-in modifiers](/guide/essentials/forms.html#modifiers) - `.trim`, `.number` and `.lazy`. In some cases, you might also want the `v-model` on your custom input component to support custom modifiers.
548
548
549
549
Let's create an example custom modifier, `capitalize`, that capitalizes the first letter of the string provided by the `v-model` binding:
Copy file name to clipboardExpand all lines: src/guide/components/props.md
+3-3Lines changed: 3 additions & 3 deletions
Original file line number
Diff line number
Diff line change
@@ -483,7 +483,7 @@ Additional details:
483
483
- All props are optional by default, unless `required: true` is specified.
484
484
485
485
- An absent optional prop other than `Boolean` will have `undefined` value.
486
-
486
+
487
487
- The `Boolean` absent props will be cast to `false`. You should set a `default` value for it in order to get desired behavior.
488
488
489
489
- If a `default` value is specified, it will be used if the resolved prop value is `undefined` - this includes both when the prop is absent, or an explicit `undefined` value is passed.
@@ -492,7 +492,7 @@ When prop validation fails, Vue will produce a console warning (if using the dev
492
492
493
493
<divclass="composition-api">
494
494
495
-
If using [Type-based props declarations](/api/sfc-script-setup.html#typescript-only-features), Vue will try its best to compile the type annotations into equivalent runtime prop declarations. For example, `defineProps<{ msg: string }>` will be compiled into `{ msg: { type: String, required: true }}`.
495
+
If using [Type-based props declarations](/api/sfc-script-setup.html#typescript-only-features) <supclass="vt-badge ts" />, Vue will try its best to compile the type annotations into equivalent runtime prop declarations. For example, `defineProps<{ msg: string }>` will be compiled into `{ msg: { type: String, required: true }}`.
496
496
497
497
</div>
498
498
<divclass="options-api">
@@ -550,7 +550,7 @@ export default {
550
550
551
551
</div>
552
552
553
-
to validate that the value of the `author` prop was created with `new Person`.
553
+
Vue will use `instanceof Person`to validate whether the value of the `author` prop is indeed an instance of the `Person` class.
Copy file name to clipboardExpand all lines: src/guide/components/slots.md
+9-18Lines changed: 9 additions & 18 deletions
Original file line number
Diff line number
Diff line change
@@ -33,9 +33,7 @@ The `<slot>` element is a **slot outlet** that indicates where the parent-provid
33
33
And the final rendered DOM:
34
34
35
35
```html
36
-
<buttonclass="fancy-btn">
37
-
Click me!
38
-
</button>
36
+
<buttonclass="fancy-btn">Click me!</button>
39
37
```
40
38
41
39
<divclass="composition-api">
@@ -59,11 +57,9 @@ FancyButton('Click me!')
59
57
60
58
// FancyButton renders slot content in its own template
61
59
functionFancyButton(slotContent) {
62
-
return (
63
-
`<button class="fancy-btn">
60
+
return`<button class="fancy-btn">
64
61
${slotContent}
65
62
</button>`
66
-
)
67
63
}
68
64
```
69
65
@@ -102,9 +98,9 @@ Slot content has access to the data scope of the parent component, because it is
102
98
103
99
Here both <spanv-pre>`{{ message }}`</span> interpolations will render the same content.
104
100
105
-
Slot content does **not** have access to the child component's data. As a rule, remember that:
101
+
Slot content does **not** have access to the child component's data. Expressions in Vue templates can only access the scope it is defined in, consistent with JavaScript's lexical scoping. In other words:
106
102
107
-
> Everything in the parent template is compiled in parent scope; everything in the child template is compiled in the child scope.
103
+
> Expressions in the parent template only have access to the parent scope; expressions in the child template only have access to the child scope.
108
104
109
105
## Fallback Content
110
106
@@ -292,13 +288,11 @@ BaseLayout({
292
288
293
289
// <BaseLayout> renders them in different places
294
290
functionBaseLayout(slots) {
295
-
return (
296
-
`<div class="container">
291
+
return`<div class="container">
297
292
<header>${slots.header}</header>
298
293
<main>${slots.default}</main>
299
294
<footer>${slots.footer}</footer>
300
295
</div>`
301
-
)
302
296
}
303
297
```
304
298
@@ -373,12 +367,10 @@ MyComponent({
373
367
374
368
functionMyComponent(slots) {
375
369
constgreetingMessage='hello'
376
-
return (
377
-
`<div>${
378
-
// call the slot function with props!
379
-
slots.default({ text: greetingMessage, count:1 })
380
-
}</div>`
381
-
)
370
+
return`<div>${
371
+
// call the slot function with props!
372
+
slots.default({ text: greetingMessage, count:1 })
373
+
}</div>`
382
374
}
383
375
```
384
376
@@ -420,7 +412,6 @@ Passing props to a named slot:
420
412
421
413
Note the `name` of a slot won't be included in the props because it is reserved - so the resulting `headerProps` would be `{ message: 'hello' }`.
422
414
423
-
424
415
### Fancy List Example
425
416
426
417
You may be wondering what would be a good use case for scoped slots. Here's an example: imagine a `<FancyList>` component that renders a list of items - it may encapsulate the logic for loading remote data, using the data to display a list, or even advanced features like pagination or infinite scrolling. However, we want it to be flexible with how each item looks and leave the styling of each item to the parent component consuming it. So the desired usage may look like this:
0 commit comments