-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
3.4 updates #2625
3.4 updates #2625
Changes from all commits
471d0ad
9ea436a
a6db832
4d45fa4
2ac7d01
040bc98
6408ea5
3755378
d0df4cf
f3eeece
c1be617
300d985
03d17cc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
--- | ||
outline: deep | ||
--- | ||
|
||
# Compile-Time Flags {#compile-time-flags} | ||
|
||
:::tip | ||
Compile-time flags only apply when using the `esm-bundler` build of Vue (i.e. `vue/dist/vue.esm-bundler.js`). | ||
::: | ||
|
||
When using Vue with a build step, it is possible to configure a number of compile-time flags to enable / disable certain features. The benefit of using compile-time flags is that features disabled this way can be removed from the final bundle via tree-shaking. | ||
|
||
Vue will work even if these flags are not explicitly configured. However, it is recommended to always configure them so that the relevant features can be properly removed when possible. | ||
|
||
See [Configuration Guides](#configuration-guides) on how to configure them depending on your build tool. | ||
|
||
## `__VUE_OPTIONS_API__` | ||
|
||
- **Default:** `true` | ||
|
||
Enable / disable Options API support. Disabling this will result in smaller bundles, but may affect compatibility with 3rd party libraries if they rely on Options API. | ||
|
||
## `__VUE_PROD_DEVTOOLS__` | ||
|
||
- **Default:** `false` | ||
|
||
Enable / disable devtools support in production builds. This will result in more code included in the bundle, so it is recommended to only enable this for debugging purposes. | ||
|
||
## `__VUE_PROD_HYDRATION_MISMATCH_DETAILS__` <sup class="vt-badge" data-text="3.4+" /> | ||
|
||
- **Default:** `false` | ||
|
||
Enable/disable detailed warnings for hydration mismatches in production builds. This will result in more code included in the bundle, so it is recommended to only enable this for debugging purposes. | ||
|
||
## Configuration Guides | ||
|
||
### Vite | ||
|
||
`@vitejs/plugin-vue` automatically provides default values for these flags. To change the default values, use Vite's [`define` config option](https://vitejs.dev/config/shared-options.html#define): | ||
|
||
```js | ||
// vite.config.js | ||
import { defineConfig } from 'vite' | ||
|
||
export default defineConfig({ | ||
define: { | ||
// enable hydration mismatch details in production build | ||
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'true' | ||
} | ||
}) | ||
``` | ||
|
||
### vue-cli | ||
|
||
`@vue/cli-service` automatically provides default values for some of these flags. To configure /change the values: | ||
|
||
```js | ||
// vue.config.js | ||
module.exports = { | ||
chainWebpack: (config) => { | ||
config.plugin('define').tap((definitions) => { | ||
Object.assign(definitions[0], { | ||
__VUE_OPTIONS_API__: 'true', | ||
__VUE_PROD_DEVTOOLS__: 'false', | ||
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false' | ||
}) | ||
return definitions | ||
}) | ||
} | ||
} | ||
``` | ||
|
||
### webpack | ||
|
||
Flags should be defined using webpack's [DefinePlugin](https://webpack.js.org/plugins/define-plugin/): | ||
|
||
```js | ||
// webpack.config.js | ||
module.exports = { | ||
// ... | ||
plugins: [ | ||
new webpack.DefinePlugin({ | ||
__VUE_OPTIONS_API__: 'true', | ||
__VUE_PROD_DEVTOOLS__: 'false', | ||
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false' | ||
}) | ||
] | ||
} | ||
``` | ||
|
||
### Rollup | ||
|
||
Flags should be defined using [@rollup/plugin-replace](https://github.com/rollup/plugins/tree/master/packages/replace): | ||
|
||
```js | ||
// rollup.config.js | ||
import replace from '@rollup/plugin-replace' | ||
|
||
export default { | ||
plugins: [ | ||
replace({ | ||
__VUE_OPTIONS_API__: 'true', | ||
__VUE_PROD_DEVTOOLS__: 'false', | ||
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false' | ||
}) | ||
] | ||
} | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -227,6 +227,77 @@ const props = withDefaults(defineProps<Props>(), { | |
|
||
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. | ||
|
||
## defineModel() <sup class="vt-badge" data-text="3.4+" /> {#definemodel} | ||
|
||
This macro can be used to declare a two-way binding prop that can be consumed via `v-model` from the parent component. Example usage is also discussed in the [Component `v-model`](/guide/components/v-model) guide. | ||
|
||
Under the hood, this macro declares a model prop and a corresponding value update event. If the first argument is a literal string, it will be used as the prop name; Otherwise the prop name will default to `"modelValue"`. In both cases, you can also pass an additional object which can include the prop's options and the model ref's value transform options. | ||
|
||
```js | ||
// declares "modelValue" prop, consumed by parent via v-model | ||
const model = defineModel() | ||
// OR: declares "modelValue" prop with options | ||
const model = defineModel({ type: String }) | ||
|
||
// emits "update:modelValue" when mutated | ||
model.value = 'hello' | ||
|
||
// declares "count" prop, consumed by parent via v-model:count | ||
const count = defineModel('count') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. some random thoughts Is it possible to declare multiple models like that? // v-model:count
const count = defineModel('count')
// v-model:x
const x = defineModel('x') Or will this result in an error? const count = defineModel('count')
const count2 = defineModel('count') Should this be handled by a linter? Will there be a Vue runtime error? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. First case is supported. Second case will throw a compile-time error. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we add docs that different There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is already shown in the component v-model guide. |
||
// OR: declares "count" prop with options | ||
const count = defineModel('count', { type: Number, default: 0 }) | ||
|
||
function inc() { | ||
// emits "update:count" when mutated | ||
count.value++ | ||
} | ||
``` | ||
|
||
### Modifiers and Transformers | ||
|
||
To access modifiers used with the `v-model` directive, we can destructure the return value of `defineModel()` like this: | ||
|
||
```js | ||
const [modelValue, modelModifiers] = defineModel() | ||
|
||
// corresponds to v-model.trim | ||
if (modelModifiers.trim) { | ||
// ... | ||
} | ||
``` | ||
|
||
When a modifier is present, we likely need to transform the value when reading or syncing it back to the parent. We can achieve this by using the `get` and `set` transformer options: | ||
|
||
```js | ||
const [modelValue, modelModifiers] = defineModel({ | ||
// get() omitted as it is not needed here | ||
set(value) { | ||
// if the .trim modifier is used, return trimmed value | ||
if (modelModifiers.trim) { | ||
return value.trim() | ||
} | ||
// otherwise, return the value as-is | ||
return value | ||
} | ||
}) | ||
``` | ||
|
||
### Usage with TypeScript <sup class="vt-badge ts" /> {#usage-with-typescript} | ||
|
||
Like `defineProps` and `defineEmits`, `defineModel` can also receive type arguments to specify the types of the model value and the modifiers: | ||
|
||
```ts | ||
const modelValue = defineModel<string>() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is it that way? It feels like it behaves the opposite of first line: when I leave out the types at so I would assume that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because it accepts parent value via a prop, so it behaves like a prop (can be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah I see 🤔 |
||
// ^? Ref<string | undefined> | ||
|
||
// default model with options, required removes possible undefined values | ||
const modelValue = defineModel<string>({ required: true }) | ||
// ^? Ref<string> | ||
|
||
const [modelValue, modifiers] = defineModel<string, 'trim' | 'uppercase'>() | ||
// ^? Record<'trim' | 'uppercase', true | undefined> | ||
``` | ||
|
||
## defineExpose() {#defineexpose} | ||
|
||
Components using `<script setup>` are **closed by default** - i.e. the public instance of the component, which is retrieved via template refs or `$parent` chains, will **not** expose any of the bindings declared inside `<script setup>`. | ||
|
@@ -249,7 +320,7 @@ defineExpose({ | |
|
||
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). | ||
|
||
## defineOptions() {#defineoptions} | ||
## defineOptions() <sup class="vt-badge" data-text="3.3+" /> {#defineoptions} | ||
|
||
This macro can be used to declare component options directly inside `<script setup>` without having to use a separate `<script>` block: | ||
|
||
|
@@ -379,5 +450,5 @@ defineProps<{ | |
|
||
## Restrictions {#restrictions} | ||
|
||
* Due to the difference in module execution semantics, code inside `<script setup>` relies on the context of an SFC. When moved into external `.js` or `.ts` files, it may lead to confusion for both developers and tools. Therefore, **`<script setup>`** cannot be used with the `src` attribute. | ||
* `<script setup>` does not support In-DOM Root Component Template.([Related Discussion](https://github.com/vuejs/core/issues/8391)) | ||
- Due to the difference in module execution semantics, code inside `<script setup>` relies on the context of an SFC. When moved into external `.js` or `.ts` files, it may lead to confusion for both developers and tools. Therefore, **`<script setup>`** cannot be used with the `src` attribute. | ||
- `<script setup>` does not support In-DOM Root Component Template.([Related Discussion](https://github.com/vuejs/core/issues/8391)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<script setup lang="ts"> | ||
defineProps<{ | ||
kind: string | ||
errors: Record<any, string> | ||
highlight?: any | ||
}>() | ||
</script> | ||
|
||
<template> | ||
<table> | ||
<thead> | ||
<tr> | ||
<th>Code</th> | ||
<th>Message</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr | ||
v-for="(msg, code) of errors" | ||
:class="{ highlight: highlight === `${kind}-${code}` }" | ||
> | ||
<td :id="`${kind}-${code}`" v-text="code" /> | ||
<td v-text="msg" /> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</template> | ||
|
||
<style scoped> | ||
.highlight { | ||
color: var(--vt-c-yellow-darker); | ||
font-weight: bold; | ||
} | ||
</style> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { defineLoader } from 'vitepress' | ||
import { errorMessages } from 'vue/compiler-sfc' | ||
// @ts-expect-error internal api | ||
import { ErrorTypeStrings } from 'vue' | ||
brc-dd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
function filterEmptyMsg(data: Record<number, string>) { | ||
return Object.fromEntries(Object.entries(data).filter(([_, msg]) => msg)) | ||
} | ||
|
||
export default defineLoader({ | ||
load() { | ||
return { | ||
compiler: filterEmptyMsg(errorMessages), | ||
runtime: filterEmptyMsg(ErrorTypeStrings) | ||
} | ||
} | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it correct that this is
: T | undefined
instead of?: T
, if I remember correctly there might be a TS compiler options so that| undefined
means that it needs to explicitly pass a variable that can be undefined, instead of not passing a variable at all.However, because this is a callback, it is not affected by this compile option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is not passed by the user but provided by the framework, so the argument will always be present.