+ 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 +567,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 `` 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..f38bc59292
--- /dev/null
+++ b/src/api/sfc-tooling.md
@@ -0,0 +1,94 @@
+# 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)
+
+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 `
```
@@ -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..baddc43a41 100644
--- a/src/guide/reactivity-fundamentals.md
+++ b/src/guide/reactivity-fundamentals.md
@@ -74,7 +74,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/single-file-component.md b/src/guide/single-file-component.md
index df5927be3a..5078f7823a 100644
--- a/src/guide/single-file-component.md
+++ b/src/guide/single-file-component.md
@@ -2,173 +2,85 @@
## Introduction
-In many Vue projects, global components will be defined using `app.component()`, followed by `app.mount('#app')` to target a container element in the body of every page.
+Vue Single File Components (aka `*.vue` files, abbreviated as **SFC**) is a special file format that allows us to encapsulate the template, logic, **and** styling of a Vue component in a single file. Here's an example SFC:
-This can work very well for small to medium-sized projects, where JavaScript is only used to enhance certain views. In more complex projects however, or when your frontend is entirely driven by JavaScript, these disadvantages become apparent:
-
-- **Global definitions** force unique names for every component
-- **String templates** lack syntax highlighting and require ugly slashes for multiline HTML
-- **No CSS support** means that while HTML and JavaScript are modularized into components, CSS is conspicuously left out
-- **No build step** restricts us to HTML and ES5 JavaScript, rather than preprocessors like Pug (formerly Jade) and Babel
-
-All of these are solved by **single-file components** with a `.vue` extension, made possible with build tools such as Webpack or Browserify.
-
-Here's an example of a file we'll call `Hello.vue`:
-
-
-
-Now we get:
-
-- [Complete syntax highlighting](https://github.com/vuejs/awesome-vue#source-code-editing)
-- [CommonJS modules](https://webpack.js.org/concepts/modules/#what-is-a-webpack-module)
-- [Component-scoped CSS](https://vue-loader.vuejs.org/en/features/scoped-css.html)
-
-As promised, we can also use preprocessors such as Pug, Babel (with ES2015 modules), and Stylus for cleaner and more feature-rich components.
-
-
-
-These specific languages are only examples. You could as easily use TypeScript, SCSS, PostCSS, or whatever other preprocessors that help you be productive. If using Webpack with `vue-loader`, it also has first-class support for CSS Modules.
-
-### What About Separation of Concerns?
-
-One important thing to note is that **separation of concerns is not equal to separation of file types.** In modern UI development, we have found that instead of dividing the codebase into three huge layers that interweave with one another, it makes much more sense to divide them into loosely-coupled components and compose them. Inside a component, its template, logic and styles are inherently coupled, and collocating them actually makes the component more cohesive and maintainable.
-
-Even if you don't like the idea of Single-File Components, you can still leverage its hot-reloading and pre-compilation features by separating your JavaScript and CSS into separate files:
+```vue
+
-```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
-
-With `.vue` components, we're entering the realm of advanced JavaScript applications. That means learning to use a few additional tools if you haven't already:
-- **Node Package Manager (npm)**: Read the [Getting Started guide](https://docs.npmjs.com/packages-and-modules/getting-packages-from-the-registry) section about how to get packages from the registry.
-
-- **Modern JavaScript with ES2015/16**: Read through Babel's [Learn ES2015 guide](https://babeljs.io/docs/en/learn). You don't have to memorize every feature right now, but keep this page as a reference you can come back to.
-
-After you've taken a day to dive into these resources, we recommend checking out [Vue CLI](https://cli.vuejs.org/). Follow the instructions and you should have a Vue project with `.vue` components, ES2015, webpack and hot-reloading in no time!
-
-### For Advanced Users
-
-The CLI takes care of most of the tooling configurations for you, but also allows fine-grained customization through its own [config options](https://cli.vuejs.org/config/).
-
-In case you prefer setting up your own build setup from scratch, you will need to manually configure webpack with [vue-loader](https://vue-loader.vuejs.org). To learn more about webpack itself, check out [their official docs](https://webpack.js.org/configuration/) and [webpack learning academy](https://webpack.academy/p/the-core-concepts).
-
-### Building with rollup
-
-Most of the time when developing a third-party library we want to build it in a way that allows the consumers of the library to [tree shake](https://webpack.js.org/guides/tree-shaking/) it. To enable tree-shaking we need to build `esm` modules. Since webpack and, in turn, vue-cli do not support building `esm` modules we need to rely on [rollup](https://rollupjs.org/).
-
-#### Installing Rollup
-
-We will need to install Rollup and a few dependencies:
-
-```bash
-npm install --save-dev rollup @rollup/plugin-commonjs rollup-plugin-vue
+
```
-These are the minimal amount of rollup plugins that we need to use to compile the code in an `esm` module. We may want to also add [rollup-plugin-babel](https://github.com/rollup/plugins/tree/master/packages/babel) to transpile their code and [node-resolve](https://github.com/rollup/plugins/tree/master/packages/node-resolve) if we use dependencies that we want to bundle with our library.
+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: ``, `
+```
+
+As you can see, without annotating the `evt` argument correctly, TypeScript will throw an error when we try to access the value of the `` element. The solution is to cast the event target with a correct type:
+
+```ts
+const handleChange = (evt: Event) => {
+ console.log((evt.target as HTMLInputElement).value)
+}
+```
diff --git a/src/guide/web-components.md b/src/guide/web-components.md
new file mode 100644
index 0000000000..20436165be
--- /dev/null
+++ b/src/guide/web-components.md
@@ -0,0 +1,243 @@
+# Vue and Web Components
+
+[Web Components](https://developer.mozilla.org/en-US/docs/Web/Web_Components) is an umbrella term for a set of web native APIs that allows developers to create reusable custom elements.
+
+We consider Vue and Web Components to be primarily complementary technologies. Vue has excellent support for both consuming and creating custom elements. Whether you are integrating custom elements into an existing Vue application, or using Vue to build and distribute custom elements, you are in good company.
+
+## Using Custom Elements in Vue
+
+Vue [scores a perfect 100% in the Custom Elements Everywhere tests](https://custom-elements-everywhere.com/libraries/vue/results/results.html). Consuming custom elements inside a Vue application largely works the same as using native HTML elements, with a few things to keep in mind:
+
+### Skipping Component Resolution
+
+By default, Vue will attempt to resolve a non-native HTML tag as a registered Vue component before falling back to rendering it as a custom element. This will cause Vue to emit a "failed to resolve component" warning during development. To let Vue know that certain elements should be treated as custom elements and skip component resolution, we can specify the [`compilerOptions.isCustomElement` option](/api/application-config.html#compileroptions).
+
+If you are using Vue with a build setup, the option should be passed via build configs since it is a compile-time option.
+
+#### Example Vite Config
+
+```js
+// vite.config.js
+import vue from '@vitejs/plugin-vue'
+
+export default {
+ plugins: [
+ vue({
+ template: {
+ compilerOptions: {
+ // treat all tags with a dash as custom elements
+ isCustomElement: tag => tag.includes('-')
+ }
+ }
+ })
+ ]
+}
+```
+
+#### Example Vue CLI Config
+
+```js
+// vue.config.js
+module.exports = {
+ chainWebpack: config => {
+ config.module
+ .rule('vue')
+ .use('vue-loader')
+ .tap(options => ({
+ ...options,
+ compilerOptions: {
+ // treat any tag that starts with ion- as custom elements
+ isCustomElement: tag => tag.startsWith('ion-')
+ }
+ }))
+ }
+}
+```
+
+### Passing DOM Properties
+
+Since DOM attributes can only be strings, we need to pass complex data to custom elements as DOM properties. When setting props on a custom element, Vue 3 automatically checks DOM-property presence using the `in` operator and will prefer setting the value as a DOM property if the key is present. This means that, in most cases, you won't need to think about this if the custom element follows the [recommended best practices](https://developers.google.com/web/fundamentals/web-components/best-practices#aim-to-keep-primitive-data-attributes-and-properties-in-sync,-reflecting-from-property-to-attribute,-and-vice-versa.).
+
+However, there could be rare cases where the data must be passed as a DOM property, but the custom element does not properly define/reflect the property (causing the `in` check to fail). In this case, you can force a `v-bind` binding to be set as a DOM property using the `.prop` modifier:
+
+```html
+
+
+
+
+```
+
+## Building Custom Elements with Vue
+
+The primary benefit of custom elements is that they can be used with any framework, or even without a framework. This makes them ideal for distributing components where the end consumer may not be using the same frontend stack, or when you want to insulate the end application from the implementation details of the components it uses.
+
+### defineCustomElement
+
+Vue supports creating custom elements using exactly the same Vue component APIs via the [`defineCustomElement`](/api/global-api.html#definecustomelement) method. The method accepts the same argument as [`defineComponent`](/api/global-api.html#definecomponent), but instead returns a custom element constructor that extends `HTMLElement`:
+
+```html
+
+```
+
+```js
+import { defineCustomElement } from 'vue'
+
+const MyVueElement = defineCustomElement({
+ // normal Vue component options here
+ props: {},
+ emits: {},
+ template: `...`,
+
+ // defineCustomElement only: CSS to be injected into shadow root
+ styles: [`/* inlined css */`]
+})
+
+// Register the custom element.
+// After registration, all `` tags
+// on the page will be upgraded.
+customElements.define('my-vue-element', MyVueElement)
+
+// You can also programmatically instantiate the element:
+// (can only be done after registration)
+document.body.appendChild(
+ new MyVueElement({
+ // initial props (optional)
+ })
+)
+```
+
+#### Lifecycle
+
+- A Vue custom element will mount an internal Vue component instance inside its shadow root when the element's [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks) is called for the first time.
+
+- When the element's `disconnectedCallback` is invoked, Vue will check whether the element is detached from the document after a microtask tick.
+
+ - If the element is still in the document, it's a move and the component instance will be perserved;
+
+ - If the element is detached from the document, it's a removal and the component instance will be unmounted.
+
+#### Props
+
+- All props declared using the `props` option will be defined on the custom element as properties. Vue will automatically handle the reflection between attributes / properties where appropriate.
+
+ - Attributes are always reflected to corresponding properties.
+
+ - Properties with primitive values (`string`, `boolean` or `number`) are reflected as attributes.
+
+- Vue also automatically casts props declared with `Boolean` or `Number` types into the desired type when they are set as attributes (which are always strings). For example given the following props declaration:
+
+ ```js
+ props: {
+ selected: Boolean,
+ index: Number
+ }
+ ```
+
+ And the custom element usage:
+
+ ```html
+
+ ```
+
+ In the component, `selected` will be cast to `true` (boolean) and `index` will be cast to `1` (number).
+
+#### Events
+
+Events emitted via `this.$emit` or setup `emit` are dispatched as native [CustomEvents](https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events#adding_custom_data_%E2%80%93_customevent) on the custom element. Additional event arguments (payload) will be exposed as an array on the CustomEvent object as its `details` property.
+
+#### Slots
+
+Inside the component, slots can be rendered using the `` element as usual. However when consuming the resulting element, it only accepts [native slots syntax](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots):
+
+- [Scoped slots](/guide/component-slots.html#scoped-slots) are not supported.
+
+- When passing named slots, use the `slot` attribute instead of the `v-slot` directive:
+
+ ```html
+
+
hello
+
+ ```
+
+#### Provide / Inject
+
+The [Provide / Inject API](/guide/component-provide-inject.html#provide-inject) and its [Composition API equivalent](/api/composition-api.html#provide-inject) also work between Vue-defined custom elements. However, note that this works **only between custom elements**. i.e. a Vue-defined custom element won't be able to inject properties provided by a non-custom-element Vue component.
+
+### SFC as Custom Element
+
+`defineCustomElement` also works with Vue Single File Components (SFCs). However, with the default tooling setup, the `