+ New pages are added to the documentation all the time. This page might not be included in all of the translations yet.
+
Take me home.
@@ -13,17 +19,22 @@
@@ -519,7 +565,7 @@ export default {
```
-For more information about using CSS modules, see [Vue Loader - CSS Modules](https://vue-loader.vuejs.org/guide/css-modules.html).
+For more information about using CSS modules, see [SFC Style Features: `
+
+
+ This could be e.g. documentation for the component.
+
+```
+
+## Language Blocks
+
+### ``
+
+- Each `*.vue` file can contain at most one top-level `` block at a time.
+
+- Contents will be extracted and passed on to `@vue/compiler-dom`, pre-compiled into JavaScript render functions, and attached to the exported component as its `render` option.
+
+### `
+```
+
+`lang` can be applied to any block - for example we can use `
+```
+
+Note the intergration with pre-processors may differ based on the toolchain. Check out the respective documentations for examples:
+
+- [Vite](https://vitejs.dev/guide/features.html#css-pre-processors)
+- [Vue CLI](https://cli.vuejs.org/guide/css.html#pre-processors)
+- [webpack + vue-loader](https://vue-loader.vuejs.org/guide/pre-processors.html#using-pre-processors)
+
+## Src Imports
+
+If you prefer splitting up your `*.vue` components into multiple files, you can use the `src` attribute to import an external file for a language block:
+
+```vue
+
+
+
+```
+
+Beware that `src` imports follow the same path resolution rules as webpack module requests, which means:
+
+- Relative paths need to start with `./`
+- You can import resources from npm dependencies:
+
+```vue
+
+
+
+
+
hi
+
+```
+
+Into the following:
+
+```vue
+
+
+
+
hi
+
+```
+
+### Child Component Root Elements
+
+With `scoped`, the parent component's styles will not leak into child components. However, a child component's root node will be affected by both the parent's scoped CSS and the child's scoped CSS. This is by design so that the parent can style the child root element for layout purposes.
+
+### Deep Selectors
+
+If you want a selector in `scoped` styles to be "deep", i.e. affecting child components, you can use the `:deep()` pseudo-class:
+
+```vue
+
+```
+
+The above will be compiled into:
+
+```css
+.a[data-v-f3f3eg9] .b {
+ /* ... */
+}
+```
+
+:::tip
+DOM content created with `v-html` are not affected by scoped styles, but you can still style them using deep selectors.
+:::
+
+### Slotted Selectors
+
+By default, scoped styles do not affect contents rendered by ``, as they are considered to be owned by the parent component passing them in. To explicitly target slot content, use the `:slotted` pseudo-class:
+
+```vue
+
+```
+
+### Global Selectors
+
+If you want just one rule to apply globally, you can use the `:global` pseudo-class rather than creating another `
+```
+
+### Mixing Local and Global Styles
+
+You can also include both scoped and non-scoped styles in the same component:
+
+```vue
+
+
+
+```
+
+### Scoped Style Tips
+
+- **Scoped styles do not eliminate the need for classes**. Due to the way browsers render various CSS selectors, `p { color: red }` will be many times slower when scoped (i.e. when combined with an attribute selector). If you use classes or ids instead, such as in `.example { color: red }`, then you virtually eliminate that performance hit.
+
+- **Be careful with descendant selectors in recursive components!** For a CSS rule with the selector `.a .b`, if the element that matches `.a` contains a recursive child component, then all `.b` in that child component will be matched by the rule.
+
+## `
+```
+
+The resulting classes are hashed to avoid collision, achieving the same effect of scoping the CSS to the current component only.
+
+Refer to the [CSS Modules spec](https://github.com/css-modules/css-modules) for more details such as [global exceptions](https://github.com/css-modules/css-modules#exceptions) and [composition](https://github.com/css-modules/css-modules#composition).
+
+### Custom Inject Name
+
+You can customize the property key of the injected classes object by giving the `module` attribute a value:
+
+```vue
+
+
red
+
+
+
+```
+
+### Usage with Composition API
+
+The injected classes can be accessed in `setup()` and `
+
+
+```
+
+The syntax works with [`
+
+
+
hello
+
+
+
+```
+
+The actual value will be compiled into a hashed CSS custom property, so the CSS is still static. The custom property will be applied to the component's root element via inline styles and reactively updated if the source value changes.
diff --git a/src/api/sfc-tooling.md b/src/api/sfc-tooling.md
new file mode 100644
index 0000000000..bd5bdf7c72
--- /dev/null
+++ b/src/api/sfc-tooling.md
@@ -0,0 +1,96 @@
+# SFC Tooling
+
+## Online Playgrounds
+
+You don't need to install anything on your machine to try out Vue SFCs - there are many online playgrounds that allow you to do so right in the browser:
+
+- [Vue SFC Playground](https://sfc.vuejs.org) (official, deployed from latest commit)
+- [VueUse Playground](https://play.vueuse.org)
+- [Vue on CodeSandbox](https://codesandbox.io/s/vue-3)
+- [Vue on Repl.it](https://replit.com/@templates/VueJS-with-Vite)
+- [Vue on Codepen](https://codepen.io/pen/editor/vue)
+- [Vue on StackBlitz](https://stackblitz.com/fork/vue)
+- [Vue on Components.studio](https://components.studio/create/vue3)
+- [Vue on WebComponents.dev](https://webcomponents.dev/create/cevue)
+
+It is also recommended to use these online playgrounds to provide reproductions when reporting bugs.
+
+## Project Scaffolding
+
+### Vite
+
+[Vite](https://vitejs.dev/) is a lightweight and fast build tool with first-class Vue SFC support. It is created by Evan You, who is also the author of Vue itself! To get started with Vite + Vue, simply run:
+
+```sh
+npm init vite@latest
+```
+
+Then select the Vue template and follow the instructions.
+
+- To learn more about Vite, check out the [Vite docs](https://vitejs.dev/guide/).
+- To configure Vue-specific behavior in a Vite project, for example passing options to the Vue compiler, check out the docs for [@vitejs/plugin-vue](https://github.com/vitejs/vite/tree/main/packages/plugin-vue#readme).
+
+The [SFC Playground](https://sfc.vuejs.org/) also supports downloading the files as a Vite project.
+
+### Vue CLI
+
+[Vue CLI](https://cli.vuejs.org/) is the official webpack-based build tool for Vue projects. To get started with Vue CLI:
+
+```sh
+npm install -g @vue/cli
+vue create hello-vue
+```
+
+- To learn more about Vue CLI, check out [Vue CLI docs](https://cli.vuejs.org/guide/installation.html).
+
+### Vite or Vue CLI?
+
+We recommend starting new projects with Vite as it offers significantly better development experience in terms of dev server startup and HMR update performance ([details](https://vitejs.dev/guide/why.html)). Only go with Vue CLI if you rely on specific webpack features (e.g. Module Federation).
+
+If you are a [Rollup](https://rollupjs.org/) user, you can safely adopt Vite as it uses Rollup for production builds and supports a Rollup-compatible plugin system. [Even Rollup's maintainer recommends Vite as THE web development wrapper for Rollup](https://twitter.com/lukastaegert/status/1412119729431584774).
+
+## IDE Support
+
+The recommended IDE setup is [VSCode](https://code.visualstudio.com/) + the [Volar](https://github.com/johnsoncodehk/volar) extension. Volar provides syntax highlighting and advanced IntelliSense for template expressions, component props and even slots validation. We strongly recommend this setup if you want to get the best possible experience with Vue SFCs, especially if you are also using TypeScript.
+
+[WebStorm](https://www.jetbrains.com/webstorm/) also provides decent support for Vue SFCs. However, do note as of now its support for `
```
-
+
[Read documentation on skip link to main content](https://www.w3.org/WAI/WCAG21/Techniques/general/G1.html)
@@ -94,16 +94,16 @@ Users can navigate an application through headings. Having descriptive headings
Landmarks provide programmatic access to sections within an application. Users who rely on assistive technology can navigate to each section of the application and skip over content. You can use [ARIA roles](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles) to help you achieve this.
-| HTML | ARIA Role | Landmark Purpose |
-| --------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
-| header | role="banner" | Prime heading: title of the page |
-| nav | role="navigation" | Collection of links suitable for use when navigating the document or related documents |
-| main | role="main" | The main or central content of the document. |
-| footer | role="contentinfo" | Information about the parent document: footnotes/copyrights/links to privacy statement |
-| aside | role="complementary" | Supports the main content, yet is separated and meaningful on its own content |
-| _Not available_ | role="search" | This section contains the search functionality for the application |
-| form | role="form" | Collection of form-associated elements |
-| section | role="region" | Content that is relevant and that users will likely want to navigate to. Label must be provided for this element |
+| HTML | ARIA Role | Landmark Purpose |
+| --------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------- |
+| header | role="banner" | Prime heading: title of the page |
+| nav | role="navigation" | Collection of links suitable for use when navigating the document or related documents |
+| main | role="main" | The main or central content of the document. |
+| footer | role="contentinfo" | Information about the parent document: footnotes/copyrights/links to privacy statement |
+| aside | role="complementary" | Supports the main content, yet is separated and meaningful on its own content |
+| _Not available_ | role="search" | This section contains the search functionality for the application |
+| form | role="form" | Collection of form-associated elements |
+| section | role="region" | Content that is relevant and that users will likely want to navigate to. Label must be provided for this element |
:::tip Tip:
It is recommended to use landmark HTML elements with redundant landmark role attributes in order to maximize compatibility with legacy [browsers that don’t support HTML5 semantic elements](https://caniuse.com/#feat=html5semantic).
diff --git a/src/guide/a11y-resources.md b/src/guide/a11y-resources.md
index 23d3bb45ba..b8c5922124 100644
--- a/src/guide/a11y-resources.md
+++ b/src/guide/a11y-resources.md
@@ -40,7 +40,7 @@ The World Health Organization estimates that 15% of the world's population has s
There are a huge range of disabilities, which can be divided roughly into four categories:
- _[Visual](https://webaim.org/articles/visual/)_ - These users can benefit from the use of screen readers, screen magnification, controlling screen contrast, or braille display.
-- _[Auditory](https://webaim.org/articles/auditory/)_ - These users can benefit from captioning, transcripts or sign language video.
+- _[Auditory](https://webaim.org/articles/auditory/)_ - These users can benefit from captioning, transcripts or sign language video.
- _[Motor](https://webaim.org/articles/motor/)_ - These users can benefit from a range of [assistive technologies for motor impairments](https://webaim.org/articles/motor/assistive): voice recognition software, eye tracking, single-switch access, head wand, sip and puff switch, oversized trackball mouse, adaptive keyboard or other assistive technologies.
- _[Cognitive](https://webaim.org/articles/cognitive/)_ - These users can benefit from supplemental media, structural organization of content, clear and simple writing.
diff --git a/src/guide/a11y-semantics.md b/src/guide/a11y-semantics.md
index 255e832401..86ba1a7fa1 100644
--- a/src/guide/a11y-semantics.md
+++ b/src/guide/a11y-semantics.md
@@ -21,7 +21,7 @@ Labels are typically placed on top or to the left of the form fields:
```
-
+
Notice how you can include `autocomplete='on'` on the form element and it will apply to all inputs in your form. You can also set different [values for autocomplete attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) for each input.
@@ -34,7 +34,7 @@ Provide labels to describe the purpose of all form control; linking `for` and `i
```
-
+
If you inspect this element in your chrome developer tools and open the Accessibility tab inside the Elements tab, you will see how the input gets its name from the label:
@@ -68,7 +68,7 @@ You can also give the input an accessible name with [`aria-label`](https://devel
/>
```
-
+
Feel free to inspect this element in Chrome DevTools to see how the accessible name has changed:
@@ -76,7 +76,7 @@ Feel free to inspect this element in Chrome DevTools to see how the accessible n
#### aria-labelledby
-Using [`aria-labelledby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-labelledby_attribute) is similar to `aria-label` expect it is used if the label text is visible on screen. It is paired to other elements by their `id` and you can link multiple `id`s:
+Using [`aria-labelledby`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-labelledby_attribute) is similar to `aria-label` except it is used if the label text is visible on screen. It is paired to other elements by their `id` and you can link multiple `id`s:
```html
```
-
+
#### Functional Images
@@ -276,4 +276,4 @@ You can use this technique to create functional images.
```
-
+
diff --git a/src/guide/class-and-style.md b/src/guide/class-and-style.md
index e1fec4bcf7..dd6dbd9af9 100644
--- a/src/guide/class-and-style.md
+++ b/src/guide/class-and-style.md
@@ -3,6 +3,7 @@
A common need for data binding is manipulating an element's class list and its inline styles. Since they are both attributes, we can use `v-bind` to handle them: we only need to calculate a final string with our expressions. However, meddling with string concatenation is annoying and error-prone. For this reason, Vue provides special enhancements when `v-bind` is used with `class` and `style`. In addition to strings, the expressions can also evaluate to objects or arrays.
## Binding HTML Classes
+Watch a free video lesson on Vue School
### Object Syntax
@@ -230,7 +231,7 @@ The array syntax for `:style` allows you to apply multiple style objects to the
### Auto-prefixing
-When you use a CSS property that requires [vendor prefixes](https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix) in `:style`, for example `transform`, Vue will automatically detect and add appropriate prefixes to the applied styles.
+When you use a CSS property that requires a [vendor prefix](https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix) in `:style`, Vue will automatically add the appropriate prefix. Vue does this by checking at runtime to see which style properties are supported in the current browser. If the browser doesn't support a particular property then various prefixed variants will be tested to try to find one that is supported.
### Multiple Values
diff --git a/src/guide/component-attrs.md b/src/guide/component-attrs.md
index 3f916a04c6..691a7fa6d3 100644
--- a/src/guide/component-attrs.md
+++ b/src/guide/component-attrs.md
@@ -2,7 +2,7 @@
> This page assumes you've already read the [Components Basics](component-basics.md). Read that first if you are new to components.
-A component non-prop attribute is an attribute or event listener that is passed to a component, but does not have a corresponding property defined in [props](component-props) or [emits](component-custom-events.html#defining-custom-events). Common examples of this include `class`, `style`, and `id` attributes. You can access those attributes via `$attrs` property.
+A component non-prop attribute is an attribute or event listener that is passed to a component, but does not have a corresponding property defined in [props](component-props.html) or [emits](component-custom-events.html#defining-custom-events). Common examples of this include `class`, `style`, and `id` attributes. You can access those attributes via `$attrs` property.
## Attribute Inheritance
@@ -18,7 +18,7 @@ app.component('date-picker', {
})
```
-In the event we need to define the status of the date-picker component via a `data-status` property, it will be applied to the root node (i.e., `div.date-picker`).
+In the event we need to define the status of the date-picker component via a `data-status` attribute, it will be applied to the root node (i.e., `div.date-picker`).
```html
@@ -82,7 +82,7 @@ If you do **not** want a component to automatically inherit attributes, you can
The common scenario for disabling an attribute inheritance is when attributes need to be applied to other elements besides the root node.
-By setting the `inheritAttrs` option to `false`, you can control to apply to other elements attributes to use the component's `$attrs` property, which includes all attributes not included to component `props` and `emits` properties (e.g., `class`, `style`, `v-on` listeners, etc.).
+By setting the `inheritAttrs` option to `false`, you can then apply attributes to the element of your choice by using the component's `$attrs` property, which includes all attributes not included to component `props` and `emits` properties (e.g., `class`, `style`, `v-on` listeners, etc.).
Using our date-picker component example from the [previous section](#attribute-inheritance), in the event we need to apply all non-prop attributes to the `input` element rather than the root `div` element, this can be accomplished by using the `v-bind` shortcut.
diff --git a/src/guide/component-basics.md b/src/guide/component-basics.md
index cda0c9b5c6..9d647f4c71 100644
--- a/src/guide/component-basics.md
+++ b/src/guide/component-basics.md
@@ -1,5 +1,7 @@
# Components Basics
+Learn component basics with a free video course on Vue School
+
## Base Example
Here's an example of a Vue component:
@@ -54,7 +56,7 @@ Components can be reused as many times as you want:
```
-
+
Notice that when clicking on the buttons, each one maintains its own, separate `count`. That's because each time you use a component, a new **instance** of it is created.
@@ -111,7 +113,7 @@ Once a prop is registered, you can pass data to it as a custom attribute, like t
```
-
+
In a typical app, however, you'll likely have an array of posts in `data`:
@@ -227,7 +229,7 @@ Then the child component can emit an event on itself by calling the built-in [**
Thanks to the `@enlarge-text="postFontSize += 0.1"` listener, the parent will receive the event and update the value of `postFontSize`.
-
+
We can list emitted events in the component's `emits` option:
@@ -406,6 +408,18 @@ That's all you need to know about dynamic components for now, but once you've fi
## DOM Template Parsing Caveats
+If you are writing your Vue templates directly in the DOM, Vue will have to retrieve the template string from the DOM. This leads to some caveats due to browsers' native HTML parsing behavior.
+
+:::tip
+It should be noted that the limitations discussed below only apply if you are writing your templates directly in the DOM. They do NOT apply if you are using string templates from the following sources:
+
+- String templates (e.g. `template: '...'`)
+- [Single-file (`.vue`) components](single-file-component.html)
+- `
```
-While this seems like a convenience, it requires a custom syntax that breaks the assumption of expressions inside of curly braces being "just JavaScript," which has both learning and implementation costs.
+While this seems like a convenience, it requires a custom syntax that breaks the assumption of expressions inside curly braces being "just JavaScript," which has both learning and implementation costs.
## 3.x Update
@@ -73,13 +73,18 @@ Using the example above, here is one example of how it could be implemented.
Instead of using filters, we recommend replacing them with computed properties or methods.
+[Migration build flags:](migration-build.html#compat-configuration)
+
+- `FILTERS`
+- `COMPILER_FILTERS`
+
### Global Filters
If you are using filters that were globally registered and then used throughout your app, it's likely not convenient to replace them with computed properties or methods in each individual component.
Instead, you can make your global filters available to all components through [globalProperties](../../api/application-config.html#globalproperties):
-```javascript
+```js
// main.js
const app = createApp(App)
diff --git a/src/guide/migration/functional-components.md b/src/guide/migration/functional-components.md
index 876195dcde..f84aa94b20 100644
--- a/src/guide/migration/functional-components.md
+++ b/src/guide/migration/functional-components.md
@@ -117,3 +117,4 @@ For more information on the usage of the new functional components and the chang
- [Migration: Render Functions](/guide/migration/render-function-api.html)
- [Guide: Render Functions](/guide/render-function.html)
+- [Migration build flag: `COMPONENT_FUNCTIONAL`](migration-build.html#compat-configuration)
diff --git a/src/guide/migration/global-api-treeshaking.md b/src/guide/migration/global-api-treeshaking.md
index d730cf71e6..502a272334 100644
--- a/src/guide/migration/global-api-treeshaking.md
+++ b/src/guide/migration/global-api-treeshaking.md
@@ -107,7 +107,7 @@ export function render() {
This essentially means the `Transition` component only gets imported when the application actually makes use of it. In other words, if the application doesn’t have any `` component, the code supporting this feature will not be present in the final bundle.
-With global tree-shaking, the user only “pay” for the features they actually use. Even better, knowing that optional features won't increase the bundle size for applications not using them, framework size has become much less a concern for additional core features in the future, if at all.
+With global tree-shaking, the users only “pay” for the features they actually use. Even better, knowing that optional features won't increase the bundle size for applications not using them, framework size has become much less a concern for additional core features in the future, if at all.
::: warning Important
The above only applies to the [ES Modules builds](/guide/installation.html#explanation-of-different-builds) for use with tree-shaking capable bundlers - the UMD build still includes all features and exposes everything on the Vue global variable (and the compiler will produce appropriate output to use APIs off the global instead of importing).
diff --git a/src/guide/migration/global-api.md b/src/guide/migration/global-api.md
index 1d3a402799..564247dcb1 100644
--- a/src/guide/migration/global-api.md
+++ b/src/guide/migration/global-api.md
@@ -75,16 +75,17 @@ const app = createApp({})
An app instance exposes a subset of the Vue 2 global APIs. The rule of thumb is _any APIs that globally mutate Vue's behavior are now moved to the app instance_. Here is a table of the Vue 2 global APIs and their corresponding instance APIs:
-| 2.x Global API | 3.x Instance API (`app`) |
-| -------------------------- | ----------------------------------------------------------------------------------------------- |
-| Vue.config | app.config |
-| Vue.config.productionTip | _removed_ ([see below](#config-productiontip-removed)) |
-| Vue.config.ignoredElements | app.config.isCustomElement ([see below](#config-ignoredelements-is-now-config-iscustomelement)) |
-| Vue.component | app.component |
-| Vue.directive | app.directive |
-| Vue.mixin | app.mixin |
-| Vue.use | app.use ([see below](#a-note-for-plugin-authors)) |
-| Vue.prototype | app.config.globalProperties ([see below](#vue-prototype-replaced-by-config-globalproperties)) | |
+| 2.x Global API | 3.x Instance API (`app`) |
+| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
+| Vue.config | app.config |
+| Vue.config.productionTip | _removed_ ([see below](#config-productiontip-removed)) |
+| Vue.config.ignoredElements | app.config.compilerOptions.isCustomElement ([see below](#config-ignoredelements-is-now-config-compileroptions-iscustomelement)) |
+| Vue.component | app.component |
+| Vue.directive | app.directive |
+| Vue.mixin | app.mixin |
+| Vue.use | app.use ([see below](#a-note-for-plugin-authors)) |
+| Vue.prototype | app.config.globalProperties ([see below](#vue-prototype-replaced-by-config-globalproperties)) |
+| Vue.extend | _removed_ ([see below](#vue-extend-removed)) |
All other global APIs that do not globally mutate behavior are now named exports, as documented in [Global API Treeshaking](./global-api-treeshaking.html).
@@ -94,7 +95,9 @@ In Vue 3.x, the "use production build" tip will only show up when using the "dev
For ES modules builds, since they are used with bundlers, and in most cases a CLI or boilerplate would have configured the production env properly, this tip will no longer show up.
-### `config.ignoredElements` Is Now `config.isCustomElement`
+[Migration build flag: `CONFIG_PRODUCTION_TIP`](migration-build.html#compat-configuration)
+
+### `config.ignoredElements` Is Now `config.compilerOptions.isCustomElement`
This config option was introduced with the intention to support native custom elements, so the renaming better conveys what it does. The new option also expects a function which provides more flexibility than the old string / RegExp approach:
@@ -104,17 +107,19 @@ Vue.config.ignoredElements = ['my-el', /^ion-/]
// after
const app = createApp({})
-app.config.isCustomElement = tag => tag.startsWith('ion-')
+app.config.compilerOptions.isCustomElement = tag => tag.startsWith('ion-')
```
::: tip Important
In Vue 3, the check of whether an element is a component or not has been moved to the template compilation phase, therefore this config option is only respected when using the runtime compiler. If you are using the runtime-only build, `isCustomElement` must be passed to `@vue/compiler-dom` in the build setup instead - for example, via the [`compilerOptions` option in vue-loader](https://vue-loader.vuejs.org/options.html#compileroptions).
-- If `config.isCustomElement` is assigned to when using a runtime-only build, a warning will be emitted instructing the user to pass the option in the build setup instead;
+- If `config.compilerOptions.isCustomElement` is assigned to when using a runtime-only build, a warning will be emitted instructing the user to pass the option in the build setup instead;
- This will be a new top-level option in the Vue CLI config.
:::
+[Migration build flag: `CONFIG_IGNORED_ELEMENTS`](migration-build.html#compat-configuration)
+
### `Vue.prototype` Replaced by `config.globalProperties`
In Vue 2, `Vue.prototype` was commonly used to add properties that would be accessible in all components.
@@ -134,6 +139,58 @@ app.config.globalProperties.$http = () => {}
Using `provide` (discussed [below](#provide-inject)) should also be considered as an alternative to `globalProperties`.
+[Migration build flag: `GLOBAL_PROTOTYPE`](migration-build.html#compat-configuration)
+
+### `Vue.extend` Removed
+
+In Vue 2.x, `Vue.extend` was used to create a "subclass" of the base Vue constructor with the argument that should be an object containing component options. In Vue 3.x, we don't have the concept of component constructors anymore. Mounting a component should always use the `createApp` global API:
+
+```js
+// before - Vue 2
+
+// create constructor
+const Profile = Vue.extend({
+ template: '
{{firstName}} {{lastName}} aka {{alias}}
',
+ data() {
+ return {
+ firstName: 'Walter',
+ lastName: 'White',
+ alias: 'Heisenberg'
+ }
+ }
+})
+// create an instance of Profile and mount it on an element
+new Profile().$mount('#mount-point')
+```
+
+```js
+// after - Vue 3
+const Profile = {
+ template: '
{{firstName}} {{lastName}} aka {{alias}}
',
+ data() {
+ return {
+ firstName: 'Walter',
+ lastName: 'White',
+ alias: 'Heisenberg'
+ }
+ }
+}
+
+Vue.createApp(Profile).mount('#mount-point')
+```
+
+#### Type Inference
+
+In Vue 2, `Vue.extend` was also used for providing TypeScript type inference for the component options. In Vue 3, the `defineComponent` global API can be used in place of `Vue.extend` for the same purpose.
+
+Note that although the return type of `defineComponent` is a constructor-like type, it is only used for TSX inference. At runtime `defineComponent` is largely a noop and will return the options object as-is.
+
+#### Component Inheritance
+
+In Vue 3, we strongly recommend favoring composition via [Composition API](/api/composition-api.html) over inheritance and mixins. If for some reason you still need component inheritance, you can use the [`extends` option](/api/options-composition.html#extends) instead of `Vue.extend`.
+
+[Migration build flag: `GLOBAL_EXTEND`](migration-build.html#compat-configuration)
+
### A Note for Plugin Authors
It is a common practice for plugin authors to install the plugins automatically in their UMD builds using `Vue.use`. For instance, this is how the official `vue-router` plugin installs itself in a browser environment:
@@ -187,6 +244,8 @@ app.directive('focus', {
app.mount('#app')
```
+[Migration build flag: `GLOBAL_MOUNT`](migration-build.html#compat-configuration)
+
## Provide / Inject
Similar to using the `provide` option in a 2.x root instance, a Vue 3 app instance can also provide dependencies that can be injected by any component inside the app:
@@ -219,7 +278,7 @@ import Bar from './Bar.vue'
const createMyApp = options => {
const app = createApp(options)
- app.directive('focus', /* ... */)
+ app.directive('focus' /* ... */)
return app
}
diff --git a/src/guide/migration/inline-template-attribute.md b/src/guide/migration/inline-template-attribute.md
index faa79067e4..05cf6f126c 100644
--- a/src/guide/migration/inline-template-attribute.md
+++ b/src/guide/migration/inline-template-attribute.md
@@ -30,6 +30,8 @@ This feature will no longer be supported.
Most of the use cases for `inline-template` assumes a no-build-tool setup, where all templates are written directly inside the HTML page.
+[Migration build flag: `COMPILER_INLINE_TEMPLATE`](migration-build.html#compat-configuration)
+
### Option #1: Use ``
- In-browser playground on [Codepen](https://codepen.io/yyx990803/pen/OJNoaZL)
- In-browser Sandbox on [CodeSandbox](https://v3.vue.new)
- Scaffold via [Vite](https://github.com/vitejs/vite):
```bash
- npm init @vitejs/app hello-vue3 # OR yarn create @vitejs/app hello-vue3
+ npm init vite hello-vue3 -- --template vue # OR yarn create vite hello-vue3 --template vue
```
- Scaffold via [vue-cli](https://cli.vuejs.org/):
@@ -37,6 +40,10 @@ Start learning Vue 3 at [Vue Mastery](https://www.vuemastery.com/courses-path/vu
# select vue 3 preset
```
+## Migration Build
+
+If you have an existing Vue 2 project or library that you intend to upgrade to Vue 3, we provide a build of Vue 3 that offers Vue 2 compatible APIs. Check out the [Migration Build](./migration-build.html) page for more details.
+
## Notable New Features
Some of the new features to keep an eye on in Vue 3 include:
@@ -46,17 +53,13 @@ Some of the new features to keep an eye on in Vue 3 include:
- [Fragments](/guide/migration/fragments.html)
- [Emits Component Option](/guide/component-custom-events.html)
- [`createRenderer` API from `@vue/runtime-core`](https://github.com/vuejs/vue-next/tree/master/packages/runtime-core) to create custom renderers
-- [SFC Composition API Syntax Sugar (`
+```
+
+```html
+
+hello
+```
+
+## See also
+
+- [Some transition classes got a rename](/guide/migration/transition.html)
+- [`` now renders no wrapper element by default](/guide/migration/transition-group.html)
diff --git a/src/guide/migration/transition-group.md b/src/guide/migration/transition-group.md
index 86509dedc5..4137ae4d5f 100644
--- a/src/guide/migration/transition-group.md
+++ b/src/guide/migration/transition-group.md
@@ -8,11 +8,11 @@ badges:
## Overview
-`` no longer renders a root element by default, but can still create one with the `tag` prop.
+`` no longer renders a root element by default, but can still create one with the `tag` attribute.
## 2.x Syntax
-In Vue 2, ``, like other custom components, needed a root element, which by default was a `` but was customizable via the `tag` prop.
+In Vue 2, ``, like other custom components, needed a root element, which by default was a `` but was customizable via the `tag` attribute.
```html
@@ -26,7 +26,7 @@ In Vue 2, ``, like other custom components, needed a root elem
In Vue 3, we have [fragment support](/guide/migration/fragments.html), so components no longer _need_ a root node. Consequently, `` no longer renders one by default.
-- If you already have the `tag` prop defined in your Vue 2 code, like in the example above, everything will work as before
+- If you already have the `tag` attribute defined in your Vue 2 code, like in the example above, everything will work as before
- If you didn't have one defined _and_ your styling or other behaviors relied on the presence of the `` root element to work properly, simply add `tag="span"` to the ``:
```html
@@ -35,6 +35,11 @@ In Vue 3, we have [fragment support](/guide/migration/fragments.html), so compon
```
+## Migration Strategy
+
+[Migration build flag: `TRANSITION_GROUP_ROOT`](migration-build.html#compat-configuration)
+
## See also
- [Some transition classes got a rename](/guide/migration/transition.html)
+- [`` as a root can no longer be toggled from the outside](/guide/migration/transition-as-root.html)
diff --git a/src/guide/migration/transition.md b/src/guide/migration/transition.md
index 645c5697fa..1261c208b8 100644
--- a/src/guide/migration/transition.md
+++ b/src/guide/migration/transition.md
@@ -63,4 +63,5 @@ The `` component's related prop names are also changed:
## See also
+- [`` as a root can no longer be toggled from the outside](/guide/migration/transition-as-root.html)
- [`` now renders no wrapper element by default](/guide/migration/transition-group.html)
diff --git a/src/guide/migration/v-bind.md b/src/guide/migration/v-bind.md
index b5d97fa7ec..902e2ce4cb 100644
--- a/src/guide/migration/v-bind.md
+++ b/src/guide/migration/v-bind.md
@@ -12,11 +12,11 @@ badges:
## Introduction
-When dynamically binding attributes on an element, a common scenario involves using both the `v-bind="object"` syntax as well as individual properties in the same element. However, this raises questions as far as the priority of merging.
+When dynamically binding attributes on an element, a common scenario involves using both the `v-bind="object"` syntax as well as individual attributes in the same element. However, this raises questions as far as the priority of merging.
## 2.x Syntax
-In 2.x, if an element has both `v-bind="object"` and an identical individual property defined, the individual property would always overwrite bindings in the `object`.
+In 2.x, if an element has both `v-bind="object"` and an identical individual attribute defined, the individual attribute would always overwrite bindings in the `object`.
```html
@@ -27,7 +27,7 @@ In 2.x, if an element has both `v-bind="object"` and an identical individual pro
## 3.x Syntax
-In 3x, if an element has both `v-bind="object"` and an identical individual property defined, the order of how the bindings are declared determines how they are merged. In other words, rather than assuming developers want the individual property to always override what is defined in the `object`, developers now have more control over the desired merging behavior.
+In 3x, if an element has both `v-bind="object"` and an identical individual attribute defined, the order of how the bindings are declared determines how they are merged. In other words, rather than assuming developers want the individual attribute to always override what is defined in the `object`, developers now have more control over the desired merging behavior.
```html
@@ -43,4 +43,6 @@ In 3x, if an element has both `v-bind="object"` and an identical individual prop
## Migration Strategy
-If you are relying on this override functionality for `v-bind`, we currently recommend ensuring that your `v-bind` attribute is defined before individual properties.
+If you are relying on this override functionality for `v-bind`, we currently recommend ensuring that your `v-bind` attribute is defined before individual attributes.
+
+[Migration build flag: `COMPILER_V_BIND_OBJECT_ORDER`](migration-build.html#compat-configuration)
diff --git a/src/guide/migration/v-if-v-for.md b/src/guide/migration/v-if-v-for.md
index 75f52016cf..8908083771 100644
--- a/src/guide/migration/v-if-v-for.md
+++ b/src/guide/migration/v-if-v-for.md
@@ -28,6 +28,8 @@ It is recommended to avoid using both on the same element due to the syntax ambi
Rather than managing this at the template level, one method for accomplishing this is to create a computed property that filters out a list for the visible elements.
+[Migration build flag: `COMPILER_V_IF_V_FOR_PRECEDENCE`](migration-build.html#compat-configuration)
+
## See also
- [List Rendering - Displaying Filtered/Sorted Results](/guide/list.html#displaying-filtered-sorted-results)
diff --git a/src/guide/migration/v-model.md b/src/guide/migration/v-model.md
index c27a95d1bc..928a2b3169 100644
--- a/src/guide/migration/v-model.md
+++ b/src/guide/migration/v-model.md
@@ -86,7 +86,7 @@ Then the parent could listen to that event and update a local data property, if
```
-For convenience, we had a shorthand for this pattern with the .sync modifier:
+For convenience, we had a shorthand for this pattern with the `.sync` modifier:
```html
@@ -182,6 +182,11 @@ We recommend:
}
```
+[Migration build flags:](migration-build.html#compat-configuration)
+
+- `COMPONENT_V_MODEL`
+- `COMPILER_V_BIND_SYNC`
+
## Next Steps
For more information on the new `v-model` syntax, see:
diff --git a/src/guide/migration/v-on-native-modifier-removed.md b/src/guide/migration/v-on-native-modifier-removed.md
index fcaffe0870..fd9c153b49 100644
--- a/src/guide/migration/v-on-native-modifier-removed.md
+++ b/src/guide/migration/v-on-native-modifier-removed.md
@@ -49,6 +49,8 @@ Consequently, Vue will now add all event listeners that are _not_ defined as com
- remove all instances of the `.native` modifier.
- ensure that all your components document their events with the `emits` option.
+[Migration build flag: `COMPILER_V_ON_NATIVE`](migration-build.html#compat-configuration)
+
## See also
- [Relevant RFC](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0031-attr-fallthrough.md#v-on-listener-fallthrough)
diff --git a/src/guide/migration/vnode-lifecycle-events.md b/src/guide/migration/vnode-lifecycle-events.md
index 6642f63adf..8ad0b231b9 100644
--- a/src/guide/migration/vnode-lifecycle-events.md
+++ b/src/guide/migration/vnode-lifecycle-events.md
@@ -31,7 +31,7 @@ In Vue 3, the event name is prefixed with `vnode-`:
```
-Or just `vnode` if you're using camel case:
+Or just `vnode` if you're using camelCase:
```html
@@ -43,6 +43,8 @@ Or just `vnode` if you're using camel case:
In most cases it should just require changing the prefix. The lifecycle hooks `beforeDestroy` and `destroyed` have been renamed to `beforeUnmount` and `unmounted` respectively, so the corresponding event names will also need to be updated.
-## See also
+[Migration build flags: `INSTANCE_EVENT_HOOKS`](migration-build.html#compat-configuration)
+
+## See Also
- [Migration guide - Events API](/guide/migration/events-api.html)
diff --git a/src/guide/migration/watch.md b/src/guide/migration/watch.md
index 3a6f579518..56d93be663 100644
--- a/src/guide/migration/watch.md
+++ b/src/guide/migration/watch.md
@@ -27,4 +27,6 @@ watch: {
## Migration Strategy
-If you rely on watching array mutations, add the `deep` property to ensure that your callback is triggered correctly.
+If you rely on watching array mutations, add the `deep` option to ensure that your callback is triggered correctly.
+
+[Migration build flag: `WATCH_ARRAY`](migration-build.html#compat-configuration)
diff --git a/src/guide/mixins.md b/src/guide/mixins.md
index 8d21cf11be..8103c019b2 100644
--- a/src/guide/mixins.md
+++ b/src/guide/mixins.md
@@ -31,7 +31,7 @@ app.mount('#mixins-basic') // => "hello from mixin!"
When a mixin and the component itself contain overlapping options, they will be "merged" using appropriate strategies.
-For example, data objects undergo a recursive merge, with the component's data taking priority in cases of conflicts.
+For example, each mixin can have its own `data` function. Each of them will be called, with the returned objects being merged. Properties from the component's own data will take priority in cases of conflicts.
```js
const myMixin = {
@@ -213,12 +213,14 @@ app.mixin({
})
```
-## Precautions
+## Drawbacks
In Vue 2, mixins were the primary tool to abstract parts of component logic into reusable chunks. However, they have a few issues:
-- Mixins are conflict-prone: Since properties from each feature are merged into the same component, you still have to know about every other feature to avoid property name conflicts and for debugging.
+- Mixins are conflict-prone: Since properties from each mixin are merged into the same component, you still have to know about every other mixin to avoid property name conflicts.
-- Reusability is limited: we cannot pass any parameters to the mixin to change its logic which reduces their flexibility in terms of abstracting logic
+- Properties seem to appear from nowhere: If a component uses multiple mixins it isn't necessarily obvious which properties came from which mixin.
+
+- Reusability is limited: we cannot pass any parameters to the mixin to change its logic, which reduces their flexibility in terms of abstracting logic.
To address these issues, we added a new way to organize code by logical concerns: the [Composition API](composition-api-introduction.html).
diff --git a/src/guide/mobile.md b/src/guide/mobile.md
index b9b1188c16..8ed7e3e34c 100644
--- a/src/guide/mobile.md
+++ b/src/guide/mobile.md
@@ -20,4 +20,4 @@ While Vue.js does not natively support mobile app development, there are a numbe
**Resources**
-- [NativeScript + Vue.js Guide](https://nativescript.org/vue/)
+- [NativeScript + Vue.js Guide](https://nativescript-vue.org/)
diff --git a/src/guide/plugins.md b/src/guide/plugins.md
index 48481a9587..aa3b44f847 100644
--- a/src/guide/plugins.md
+++ b/src/guide/plugins.md
@@ -6,7 +6,7 @@ There is no strictly defined scope for a plugin, but common scenarios where plug
1. Add some global methods or properties, e.g. [vue-custom-element](https://github.com/karol-f/vue-custom-element).
-2. Add one or more global assets: directives/filters/transitions etc. (e.g. [vue-touch](https://github.com/vuejs/vue-touch)).
+2. Add one or more global assets: directives/transitions etc. (e.g. [vue-touch](https://github.com/vuejs/vue-touch)).
3. Add some component options by global mixin (e.g. [vue-router](https://github.com/vuejs/vue-router)).
diff --git a/src/guide/reactivity-computed-watchers.md b/src/guide/reactivity-computed-watchers.md
index 97f48ae241..b1860b03ef 100644
--- a/src/guide/reactivity-computed-watchers.md
+++ b/src/guide/reactivity-computed-watchers.md
@@ -4,7 +4,7 @@
## Computed values
-Sometimes we need state that depends on other state - in Vue this is handled with component [computed properties](computed.html#computed-properties). To directly create a computed value, we can use the `computed` method: it takes a getter function and returns an immutable reactive [ref](reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs) object for the returned value from the getter.
+Sometimes we need state that depends on other state - in Vue this is handled with component [computed properties](computed.html#computed-properties). To directly create a computed value, we can use the `computed` function: it takes a getter function and returns an immutable reactive [ref](reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs) object for the returned value from the getter.
```js
const count = ref(1)
@@ -30,9 +30,39 @@ plusOne.value = 1
console.log(count.value) // 0
```
+### Computed Debugging
+
+`computed` accepts a second argument with `onTrack` and `onTrigger` options:
+
+- `onTrack` will be called when a reactive property or ref is tracked as a dependency.
+- `onTrigger` will be called when the watcher callback is triggered by the mutation of a dependency.
+
+Both callbacks will receive a debugger event which contains information on the dependency in question. It is recommended to place a `debugger` statement in these callbacks to interactively inspect the dependency:
+
+```js
+const plusOne = computed(() => count.value + 1, {
+ onTrack(e) {
+ // triggered when count.value is tracked as a dependency
+ debugger
+ },
+ onTrigger(e) {
+ // triggered when count.value is mutated
+ debugger
+ }
+})
+
+// access plusOne, should trigger onTrack
+console.log(plusOne.value)
+
+// mutate count.value, should trigger onTrigger
+count.value++
+```
+
+`onTrack` and `onTrigger` only work in development mode.
+
## `watchEffect`
-To apply and _automatically re-apply_ a side effect based on reactive state, we can use the `watchEffect` method. It runs a function immediately while reactively tracking its dependencies and re-runs it whenever the dependencies are changed.
+To apply and _automatically re-apply_ a side effect based on reactive state, we can use the `watchEffect` function. It runs a function immediately while reactively tracking its dependencies and re-runs it whenever the dependencies are changed.
```js
const count = ref(0)
@@ -83,8 +113,10 @@ We are registering the invalidation callback via a passed-in function instead of
```js
const data = ref(null)
-watchEffect(async (onInvalidate) => {
- onInvalidate(() => { /* ... */ }) // we register cleanup function before Promise resolves
+watchEffect(async onInvalidate => {
+ onInvalidate(() => {
+ /* ... */
+ }) // we register cleanup function before Promise resolves
data.value = await fetchData(props.id)
})
```
@@ -95,26 +127,25 @@ An async function implicitly returns a Promise, but the cleanup function needs t
Vue's reactivity system buffers invalidated effects and flushes them asynchronously to avoid unnecessary duplicate invocation when there are many state mutations happening in the same "tick". Internally, a component's `update` function is also a watched effect. When a user effect is queued, it is by default invoked **before** all component `update` effects:
-```html
-
+```vue
{{ count }}
```
@@ -141,6 +172,8 @@ watchEffect(
The `flush` option also accepts `'sync'`, which forces the effect to always trigger synchronously. This is however inefficient and should be rarely needed.
+In Vue >= 3.2.0, `watchPostEffect` and `watchSyncEffect` aliases can also be used to make the code intention more obvious.
+
### Watcher Debugging
The `onTrack` and `onTrigger` options can be used to debug a watcher's behavior.
@@ -201,15 +234,48 @@ watch(count, (count, prevCount) => {
A watcher can also watch multiple sources at the same time using an array:
```js
-const firstName = ref('');
-const lastName = ref('');
+const firstName = ref('')
+const lastName = ref('')
watch([firstName, lastName], (newValues, prevValues) => {
- console.log(newValues, prevValues);
+ console.log(newValues, prevValues)
})
-firstName.value = "John"; // logs: ["John",""] ["", ""]
-lastName.value = "Smith"; // logs: ["John", "Smith"] ["John", ""]
+firstName.value = 'John' // logs: ["John", ""] ["", ""]
+lastName.value = 'Smith' // logs: ["John", "Smith"] ["John", ""]
+```
+
+However, if you are changing both watched sources simultaneously in the same function, the watcher will be executed only once:
+
+```js{9-13}
+setup() {
+ const firstName = ref('')
+ const lastName = ref('')
+
+ watch([firstName, lastName], (newValues, prevValues) => {
+ console.log(newValues, prevValues)
+ })
+
+ const changeValues = () => {
+ firstName.value = 'John'
+ lastName.value = 'Smith'
+ // logs: ["John", "Smith"] ["", ""]
+ }
+
+ return { changeValues }
+}
+```
+
+Note that multiple synchronous changes will only trigger the watcher once.
+
+It is possible to force the watcher to trigger after every change by using the setting `flush: 'sync'`, though that isn't usually recommended. Alternatively, [nextTick](/api/global-api.html#nexttick) can be used to wait for the watcher to run before making further changes. e.g.:
+
+```js
+const changeValues = async () => {
+ firstName.value = 'John' // logs: ["John", ""] ["", ""]
+ await nextTick()
+ lastName.value = 'Smith' // logs: ["John", "Smith"] ["John", ""]
+}
```
### Watching Reactive Objects
@@ -222,8 +288,9 @@ const numbers = reactive([1, 2, 3, 4])
watch(
() => [...numbers],
(numbers, prevNumbers) => {
- console.log(numbers, prevNumbers);
- })
+ console.log(numbers, prevNumbers)
+ }
+)
numbers.push(5) // logs: [1,2,3,4,5] [1,2,3,4]
```
@@ -231,62 +298,51 @@ numbers.push(5) // logs: [1,2,3,4,5] [1,2,3,4]
Attempting to check for changes of properties in a deeply nested object or array will still require the `deep` option to be true:
```js
-const state = reactive({
- id: 1,
- attributes: {
- name: "",
- },
-});
+const state = reactive({
+ id: 1,
+ attributes: {
+ name: ''
+ }
+})
watch(
() => state,
(state, prevState) => {
- console.log(
- "not deep ",
- state.attributes.name,
- prevState.attributes.name
- );
+ console.log('not deep', state.attributes.name, prevState.attributes.name)
}
-);
+)
watch(
() => state,
(state, prevState) => {
- console.log(
- "deep ",
- state.attributes.name,
- prevState.attributes.name
- );
+ console.log('deep', state.attributes.name, prevState.attributes.name)
},
{ deep: true }
-);
+)
-state.attributes.name = "Alex"; // Logs: "deep " "Alex" "Alex"
+state.attributes.name = 'Alex' // Logs: "deep" "Alex" "Alex"
```
However, watching a reactive object or array will always return a reference to the current value of that object for both the current and previous value of the state. To fully watch deeply nested objects and arrays, a deep copy of values may be required. This can be achieved with a utility such as [lodash.cloneDeep](https://lodash.com/docs/4.17.15#cloneDeep)
```js
-import _ from 'lodash';
+import _ from 'lodash'
const state = reactive({
id: 1,
attributes: {
- name: "",
- },
-});
+ name: ''
+ }
+})
watch(
() => _.cloneDeep(state),
(state, prevState) => {
- console.log(
- state.attributes.name,
- prevState.attributes.name
- );
+ console.log(state.attributes.name, prevState.attributes.name)
}
-);
+)
-state.attributes.name = "Alex"; // Logs: "Alex" ""
+state.attributes.name = 'Alex' // Logs: "Alex" ""
```
### Shared Behavior with `watchEffect`
diff --git a/src/guide/reactivity-fundamentals.md b/src/guide/reactivity-fundamentals.md
index 49caf3256f..bbaef88a95 100644
--- a/src/guide/reactivity-fundamentals.md
+++ b/src/guide/reactivity-fundamentals.md
@@ -1,5 +1,7 @@
# Reactivity Fundamentals
+> This section uses [single-file component](single-file-component.html) syntax for code examples
+
## Declaring Reactive State
To create a reactive state from a JavaScript object, we can use a `reactive` method:
@@ -74,7 +76,7 @@ When a ref is returned as a property on the render context (the object returned
```
:::tip
-If you don't need to access the actual object instance, you can wrap it in a `reactive`:
+If you don't want to access the actual object instance, you can wrap it in a `reactive`:
```js
nested: reactive({
diff --git a/src/guide/reactivity.md b/src/guide/reactivity.md
index 4f686402e0..ba6ce6c3ee 100644
--- a/src/guide/reactivity.md
+++ b/src/guide/reactivity.md
@@ -98,7 +98,7 @@ But knowing what code is running is just one part of the puzzle. How does Vue kn
We can't track reassignments of local variables like those in our earlier examples, there's just no mechanism for doing that in JavaScript. What we can track are changes to object properties.
-When we return a plain JavaScript object from a component's `data` function, Vue will wrap that object in a [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) with handlers for `get` and `set`. Proxies were introduced in ES6 and allow Vue 3 to avoid some of the reactivity caveats that existed in earlier versions of Vue.
+When we return a plain JavaScript object from a component's `data` function, Vue will wrap that object in a [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) with handlers for `get` and `set`. Proxies were introduced in ES6 and allow Vue 3 to avoid some of the reactivity caveats that existed in earlier versions of Vue.
@@ -305,7 +305,7 @@ The template for a component is compiled down into a [`render`](/guide/render-fu
A `render` function is conceptually very similar to a `computed` property. Vue doesn't track exactly how dependencies are used, it only knows that they were used at some point while the function was running. If any of those properties subsequently changes, it will trigger the effect to run again, re-running the `render` function to generate new VNodes. These are then used to make the necessary changes to the DOM.
-
+
> If you are using Vue 2.x and below, you may be interested in some of the change detection caveats that exist for those versions, [explored in more detail here](change-detection.md).
diff --git a/src/guide/render-function.md b/src/guide/render-function.md
index adfd00b9e8..902f229421 100644
--- a/src/guide/render-function.md
+++ b/src/guide/render-function.md
@@ -136,9 +136,9 @@ The `h()` function is a utility to create VNodes. It could perhaps more accurate
```js
// @returns {VNode}
h(
- // {String | Object | Function } tag
- // An HTML tag name, a component or an async component.
- // Using function returning null would render a comment.
+ // {String | Object | Function} tag
+ // An HTML tag name, a component, an async component, or a
+ // functional component.
//
// Required.
'div',
@@ -350,11 +350,11 @@ render() {
#### Event Modifiers
-For the `.passive`, `.capture`, and `.once` event modifiers, they can be concatenated after the event name using camel case.
+For the `.passive`, `.capture`, and `.once` event modifiers, they can be concatenated after the event name using camelCase.
For example:
-```javascript
+```js
render() {
return h('input', {
onClickCapture: this.doThisInCapturingMode,
@@ -551,6 +551,49 @@ render () {
[`resolveDirective`](/api/global-api.html#resolvedirective) is the same function that templates use internally to resolve directives by name. That is only necessary if you don't already have direct access to the directive's definition object.
+### Built-in Components
+
+[Built-in components](/api/built-in-components.html) such as ``, ``, ``, and `` are not registered globally by default. This allows bundlers to perform tree-shaking, so that the components are only included in the build if they are used. However, that also means we can't access them using `resolveComponent` or `resolveDynamicComponent`.
+
+Templates have special handling for those components, automatically importing them when they are used. When we're writing our own `render` functions, we need to import them ourselves:
+
+```js
+const { h, KeepAlive, Teleport, Transition, TransitionGroup } = Vue
+
+// ...
+
+render () {
+ return h(Transition, { mode: 'out-in' }, /* ... */)
+}
+```
+
+## Return Values for Render Functions
+
+In all of the examples we've seen so far, the `render` function has returned a single root VNode. However, there are alternatives.
+
+Returning a string will create a text VNode, without any wrapping element:
+
+```js
+render() {
+ return 'Hello world!'
+}
+```
+
+We can also return an array of children, without wrapping them in a root node. This creates a fragment:
+
+```js
+// Equivalent to a template of `Hello world!`
+render() {
+ return [
+ 'Hello',
+ h('br'),
+ 'world!'
+ ]
+}
+```
+
+If a component needs to render nothing, perhaps because data is still loading, it can just return `null`. This will be rendered as a comment node in the DOM.
+
## JSX
If we're writing a lot of `render` functions, it might feel painful to write something like this:
@@ -593,6 +636,31 @@ app.mount('#demo')
For more on how JSX maps to JavaScript, see the [usage docs](https://github.com/vuejs/jsx-next#installation).
+## Functional Components
+
+Functional components are an alternative form of component that don't have any state of their own. They are rendered without creating a component instance, bypassing the usual component lifecycle.
+
+To create a functional component we use a plain function, rather than an options object. The function is effectively the `render` function for the component. As there is no `this` reference for a functional component, Vue will pass in the `props` as the first argument:
+
+```js
+const FunctionalComponent = (props, context) => {
+ // ...
+}
+```
+
+The second argument, `context`, contains three properties: `attrs`, `emit`, and `slots`. These are equivalent to the instance properties [`$attrs`](/api/instance-properties.html#attrs), [`$emit`](/api/instance-methods.html#emit), and [`$slots`](/api/instance-properties.html#slots) respectively.
+
+Most of the usual configuration options for components are not available for functional components. However, it is possible to define [`props`](/api/options-data.html#props) and [`emits`](/api/options-data.html#emits) by adding them as properties:
+
+```js
+FunctionalComponent.props = ['value']
+FunctionalComponent.emits = ['click']
+```
+
+If the `props` option is not specified, then the `props` object passed to the function will contain all attributes, the same as `attrs`. The prop names will not be normalized to camelCase unless the `props` option is specified.
+
+Functional components can be registered and consumed just like normal components. If you pass a function as the first argument to `h`, it will be treated as a functional component.
+
## Template Compilation
You may be interested to know that Vue's templates actually compile to render functions. This is an implementation detail you usually don't need to know about, but if you'd like to see how specific template features are compiled, you may find it interesting. Below is a little demo using `Vue.compile` to live-compile a template string:
diff --git a/src/guide/security.md b/src/guide/security.md
new file mode 100644
index 0000000000..5f7813e00a
--- /dev/null
+++ b/src/guide/security.md
@@ -0,0 +1,187 @@
+# Security
+
+## Reporting Vulnerabilities
+
+When a vulnerability is reported, it immediately becomes our top concern, with a full-time contributor dropping everything to work on it. To report a vulnerability, please email [security@vuejs.org](mailto:security@vuejs.org).
+
+While the discovery of new vulnerabilities is rare, we also recommend always using the latest versions of Vue and its official companion libraries to ensure your application remains as secure as possible.
+
+## Rule No.1: Never Use Non-trusted Templates
+
+The most fundamental security rule when using Vue is **never use non-trusted content as your component template**. Doing so is equivalent to allowing arbitrary JavaScript execution in your application - and worse, could lead to server breaches if the code is executed during server-side rendering. An example of such usage:
+
+```js
+Vue.createApp({
+ template: `
` + userProvidedString + `
` // NEVER DO THIS
+}).mount('#app')
+```
+
+Vue templates are compiled into JavaScript, and expressions inside templates will be executed as part of the rendering process. Although the expressions are evaluated against a specific rendering context, due to the complexity of potential global execution environments, it is impractical for a framework like Vue to completely shield you from potential malicious code execution without incurring unrealistic performance overhead. The most straightforward way to avoid this category of problems altogether is to make sure the contents of your Vue templates are always trusted and entirely controlled by you.
+
+## What Vue Does to Protect You
+
+### HTML content
+
+Whether using templates or render functions, content is automatically escaped. That means in this template:
+
+```html
+
{{ userProvidedString }}
+```
+
+if `userProvidedString` contained:
+
+```js
+''
+```
+
+then it would be escaped to the following HTML:
+
+```html
+<script>alert("hi")</script>
+```
+
+thus preventing the script injection. This escaping is done using native browser APIs, like `textContent`, so a vulnerability can only exist if the browser itself is vulnerable.
+
+### Attribute bindings
+
+Similarly, dynamic attribute bindings are also automatically escaped. That means in this template:
+
+```html
+
+ hello
+
+```
+
+if `userProvidedString` contained:
+
+```js
+'" onclick="alert(\'hi\')'
+```
+
+then it would be escaped to the following HTML:
+
+```html
+" onclick="alert('hi')
+```
+
+thus preventing the close of the `title` attribute to inject new, arbitrary HTML. This escaping is done using native browser APIs, like `setAttribute`, so a vulnerability can only exist if the browser itself is vulnerable.
+
+## Potential Dangers
+
+In any web application, allowing unsanitized, user-provided content to be executed as HTML, CSS, or JavaScript is potentially dangerous, so should be avoided wherever possible. There are times when some risk may be acceptable though.
+
+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.
+
+### Injecting HTML
+
+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:
+
+- Using a template:
+
+ ```html
+
+ ```
+
+- Using a render function:
+
+ ```js
+ h('div', {
+ innerHTML: this.userProvidedHtml
+ })
+ ```
+
+- Using a render function with JSX:
+
+ ```jsx
+
+ ```
+
+:::tip
+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.
+:::
+
+### Injecting URLs
+
+In a URL like this:
+
+```html
+
+ click me
+
+```
+
+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:
+
+:::tip
+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.
+:::
+
+### Injecting Styles
+
+Looking at this example:
+
+```html
+
+ click me
+
+```
+
+let's assume that `sanitizedUrl` has been sanitized, so that it's definitely a real URL and not JavaScript. With the `userProvidedStyles`, malicious users could still provide CSS to "click jack", e.g. styling the link into a transparent box over the "Log in" button. Then if `https://user-controlled-website.com/` is built to resemble the login page of your application, they might have just captured a user's real login information.
+
+You may be able to imagine how allowing user-provided content for a `
+```
+
+To keep your users fully safe from click jacking, we recommend only allowing full control over CSS inside a sandboxed iframe. Alternatively, when providing user control through a style binding, we recommend using its [object syntax](class-and-style.html#object-syntax-2) and only allowing users to provide values for specific properties it's safe for them to control, like this:
+
+```html
+
+ click me
+
+```
+
+### Injecting JavaScript
+
+We strongly discourage ever rendering a `
-```html
-
-
This will be pre-compiled
+
{{ greeting }}
-
-
-```
-
-## Getting Started
-### Example Sandbox
-
-If you want to dive right in and start playing with single-file components, check out [this simple todo app](https://codesandbox.io/s/vue-todo-list-app-with-single-file-component-vzkl3?file=/src/App.vue) on CodeSandbox.
+
+```
-### For Users New to Module Build Systems in JavaScript
+As we can see, Vue SFC is a natural extension of the classic trio of HTML, CSS and JavaScript. Each `*.vue` file consists of three types of top-level language blocks: ``, `
+```
+
+### `entry-client.js`
+
+The client entry creates the application using the `App.vue` component and mounts it to the DOM:
+
+```js
+import { createSSRApp } from 'vue'
+import App from './App.vue'
+
+// client-specific bootstrapping logic...
+
+const app = createSSRApp(App)
+
+// this assumes App.vue template root element has `id="app"`
+app.mount('#app')
+```
+
+### `entry-server.js`
+
+The server entry uses a default export which is a function that can be called repeatedly for each render. At this moment, it doesn't do much other than returning the app instance - but later we will perform server-side route matching and data pre-fetching logic here.
+
+```js
+import { createSSRApp } from 'vue'
+import App from './App.vue'
+
+export default function () {
+ const app = createSSRApp(App)
+
+ return {
+ app
+ }
+}
+```
diff --git a/src/guide/ssr/universal.md b/src/guide/ssr/universal.md
new file mode 100644
index 0000000000..3aa552700f
--- /dev/null
+++ b/src/guide/ssr/universal.md
@@ -0,0 +1,29 @@
+# Writing Universal Code
+
+Before going further, let's take a moment to discuss the constraints when writing "universal" code - that is, code that runs on both the server and the client. Due to use case and platform API differences, the behavior of our code will not be exactly the same when running in different environments. Here we will go over the key things you need to be aware of.
+
+## Data Reactivity on the Server
+
+In a client-only app, every user will be using a fresh instance of the app in their browser. For server-side rendering we want the same: each request should have a fresh, isolated app instance so that there is no cross-request state pollution.
+
+Because the actual rendering process needs to be deterministic, we will also be "pre-fetching" data on the server - this means our application state will be already resolved when we start rendering. This means data reactivity is unnecessary on the server, so it is disabled by default. Disabling data reactivity also avoids the performance cost of converting data into reactive objects.
+
+## Component Lifecycle Hooks
+
+Since there are no dynamic updates, the only [lifecycle hooks](/guide/instance.html#lifecycle-hooks) that will be called during SSR are `beforeCreate` and `created`. This means any code inside other lifecycle hooks such as `beforeMount` or `mounted` will only be executed on the client.
+
+Another thing to note is that you should avoid code that produces global side effects in `beforeCreate` and `created`, for example setting up timers with `setInterval`. In client-side only code we may setup a timer and then tear it down in `beforeUnmount` or `unmounted`. However, because the destroy hooks will not be called during SSR, the timers will stay around forever. To avoid this, move your side-effect code into `beforeMount` or `mounted` instead.
+
+## Access to Platform-Specific APIs
+
+Universal code cannot assume access to platform-specific APIs, so if your code directly uses browser-only globals like `window` or `document`, they will throw errors when executed in Node.js, and vice-versa.
+
+For tasks shared between server and client but using different platform APIs, it's recommended to wrap the platform-specific implementations inside a universal API, or use libraries that do this for you. For example, [axios](https://github.com/axios/axios) is an HTTP client that exposes the same API for both server and client.
+
+For browser-only APIs, the common approach is to lazily access them inside client-only lifecycle hooks.
+
+Note that if a 3rd party library is not written with universal usage in mind, it could be tricky to integrate it into an server-rendered app. You _might_ be able to get it working by mocking some of the globals, but it would be hacky and may interfere with the environment detection code of other libraries.
+
+## Custom Directives
+
+Most [custom directives](/guide/custom-directive.html#custom-directives) directly manipulate the DOM, which will cause errors during SSR. We recommend to prefer using components as the abstraction mechanism instead of directives.
diff --git a/src/guide/state-management.md b/src/guide/state-management.md
index 366df48ca2..a67491ec6a 100644
--- a/src/guide/state-management.md
+++ b/src/guide/state-management.md
@@ -2,7 +2,7 @@
## Official Flux-Like Implementation
-Large applications can often grow in complexity, due to multiple pieces of state scattered across many components and the interactions between them. To solve this problem, Vue offers [Vuex](https://next.vuex.vuejs.org/), our own Elm-inspired state management library. It even integrates into [vue-devtools](https://github.com/vuejs/vue-devtools), providing zero-setup access to [time travel debugging](https://raw.githubusercontent.com/vuejs/vue-devtools/master/media/demo.gif).
+Large applications can often grow in complexity, due to multiple pieces of state scattered across many components and the interactions between them. To solve this problem, Vue offers [Vuex](https://next.vuex.vuejs.org/), our own Elm-inspired state management library. It even integrates into [vue-devtools](https://github.com/vuejs/vue-devtools), providing zero-setup access to [time travel debugging](https://raw.githubusercontent.com/vuejs/vue-devtools/legacy/media/demo.gif).
### Information for React Developers
diff --git a/src/guide/teleport.md b/src/guide/teleport.md
index 5e65865271..c47ff0c571 100644
--- a/src/guide/teleport.md
+++ b/src/guide/teleport.md
@@ -4,7 +4,7 @@
Vue encourages us to build our UIs by encapsulating UI and related behavior into components. We can nest them inside one another to build a tree that makes up an application UI.
-However, sometimes a part of a component's template belongs to this component logically, while from a technical point of view, it would be preferable to move this part of the template somewhere else in the DOM, outside of the Vue app.
+However, sometimes a part of a component's template belongs to this component logically, while from a technical point of view, it would be preferable to move this part of the template somewhere else in the DOM, outside of the Vue app.
A common scenario for this is creating a component that includes a full-screen modal. In most cases, you'd want the modal's logic to live within the component, but the positioning of the modal quickly becomes difficult to solve through CSS, or requires a change in component composition.
@@ -21,7 +21,7 @@ Consider the following HTML structure.