From 4a95d84ad57f7a29088bb35e5423b0bd289c300b Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 2 Aug 2021 17:01:55 -0400 Subject: [PATCH 01/19] update and improve SFC documentation with 3.2 features - Updated Single File Components guide section - Added dedicated SFC spec & tooling sections in API references - Added dedicated API references for ` +``` + +The code inside are compiled as the content of the component's `setup()` function. This means unlike normal ` + + +``` + +Imports are exposed in the same fashion. This means you can directly use an imported helper function in template expressions without having to expose it via the `methods` option: + +```html + + + +``` + +## Reactivity + +Reactive state needs to be explicitly created using [Reactivity APIs](https://v3.vuejs.org/api/basic-reactivity.html). Similar to returned values from the `setup()` functions, refs are automatically unwrapped when referenced in templates: + +```html + + + +``` + +## Using Components + +Values in the scope of ` + + +``` + +Think of `MyComponent` as being referenced as a varaible. If you have used JSX before, the mental model is similar here. The kebab-case equivalent `` also works in the template - however PascalCase component tags are strongly recommended for consistency. It also helps differentiating from native custom elements. + +### Dynamic Components + +Since components are referenced as variables instead of registered under string keys, we should use dynamic `:is` binding when using dynamic components inside ` + + +``` + +Note how the components can be used as variables in a ternary expression. + +### Recursive Components + +SFCs can implicitly refer to itself via its filename. E.g. a file named `FooBar.vue` can refer to itself as `` in its template. + +Note this has lower priority than imported components. If you have a named import that conflicts with the component's inferred name, you can alias the import: + +```js +import { FooBar as FooBarChild } from './components' +``` + +## `defineProps` and `defineEmits` + +To declare options like `props` and `emits` with full type inference support, we can use the `defineProps` and `defineEmits` APIs, which are automatically available inside ` +``` + +- `defineProps` and `defineEmits` are **compiler macros** only usable inside ` +``` + +When a parent gets an instance of this component via template refs, the retrieved instance will be of the shape `{ a: number, b: number }` (refs are automatically unwrapped just like on normal instances). + +## `useSlots` and `useAttrs` + +Usage of `slots` and `attrs` inside ` +``` + +`useSlots` and `useAttrs` are actual runtime functions that return the equivalent of `setupContext.slots` and `setupContext.attrs`. They can be used in normal composition API functions as well. + +## Usage alongside normal ` + + +``` + +## Top level await + +Top level `await` can be used inside ` +``` + +In addition, the awaited expression will be automatically compiled in a format that preserves the current component instance context after the `await`. + +## TypeScript-only Features + +### Type-only props/emit declarations + +Props and emits can also be declared using pure-type syntax by passing a literal type argument to `defineProps` or `defineEmits`: + +```ts +const props = defineProps<{ + foo: string + bar?: number +}>() + +const emit = defineEmits<{ + (e: 'change', id: number): void + (e: 'update', value: string): void +}>() +``` + +- `defineProps` or `defineEmits` can only use either runtime declaration OR type declaration. Using both at the same time will result in a compile error. + +- When using type declaration, equivalent runtime declaration is automatically generated from static analysis to remove the need of double declaration and still ensure correct runtime behavior. + + - In dev mode, the compiler will try to infer corresponding runtime validation from the types. For example here `foo: String` is inferred from the `foo: string` type. If the type is a reference to an imported type, the inferred result will be `foo: null` (equal to `any` type) since the compiler does not have information of external files. + + - In prod mode, the compiler will generate the array format declaration to reduce bundle size (the props here will be compiled into `['msg']`) + + - The emitted code is still TypeScript with valid typing, which can be further processed by other tools. + +- As of now, the type declaration argument must be one of the following to ensure correct static analysis: + + - A type literal + - A reference to a an interface or a type literal in the same file + + Currently complex types and type imports from other files are not supported. It is theoretically possible to support type imports in the future. + +### Default props values when using type declaration + +One drawback of the type-only `defineProps` declaration is that it doesn't have a way to provide default values for the props. To resolve this problem, a `withDefaults` compiler macro is also provided: + +```ts +interface Props { + msg?: string +} + +const props = withDefaults(defineProps(), { + msg: 'hello' +}) +``` + +This will be compiled to equivalent runtime props `default` options. In addition, the `withDefaults` helper provides type checks for the default values, and ensures the returned `props` type has the optional flags removed for properties that do have default values declared. + +## Restriction: No Src Imports + +Due to the difference in module execution semantics, code inside ` + + + + + This could be e.g. documentation for the component. + +``` + +## Language Blocks + +### `