Вышел Vue 3.5

в 10:04, , рубрики: javascript, TypeScript, vue, vue3

Эта статья — перевод оригинальной статьи «Announcing Vue 3.5».

Также я веду телеграм канал «Frontend по‑флотски», где рассказываю про интересные вещи из мира разработки интерфейсов.

Вступление

Сегодня мы рады сообщить о выходе Vue 3.5 "Tengen Toppa Gurren Lagann"!

Этот минорный релиз не содержит кардинальных изменений и включает в себя как внутренние улучшения, так и новые полезные функции. Мы расскажем о некоторых основных моментах в этом блоге - полный список изменений и новых возможностей можно найти в полном журнале изменений на GitHub.

Оптимизация системы реактивности

В версии 3.5 система реактивности Vue подверглась очередному масштабному рефакторингу, который позволил добиться более высокой производительности и значительно улучшить использование памяти (-56 %) без каких-либо изменений в поведении. Рефакторинг также решает проблемы с устаревшими computed и памятью, вызванные зависанием computed во время SSR.

Кроме того, в 3.5 оптимизировано отслеживание реактивности для больших, глубоко реактивных массивов, что в некоторых случаях ускоряет такие операции до 10 раз.

Подробности: PR#10397, PR#9511

Реактивная деструктуризация props

Реактиваная деструктуризация props была стабилизирована в 3.5. Теперь эта функция включена по умолчанию, и переменные, деструктурированные в результате вызова defineProps в <script setup>, теперь являются реактивными. Примечательно, что эта функция значительно упрощает объявление props со значениями по умолчанию, используя нативный JavaScript синтаксис значений по умолчанию:

До:

const props = withDefaults(
  defineProps<{
    count?: number
    msg?: string
  }>(),
  {
    count: 0,
    msg: 'hello'
  }
)

После:

const { count = 0, msg = 'hello' } = defineProps<{
  count?: number
  message?: string
}>()

Доступ к деструктурированной переменной, например count, автоматически компилируется компилятором в props.count, поэтому они отслеживаются при доступе. Как и в случае с props.count, просмотр деструктурированной переменной prop или передача ее в composable  функцию с сохранением реактивности требует обернуть ее в геттер:

watch(count /* ... */)
//    ^ приводит к ошибке compile-time error

watch(() => count /* ... */)
//    ^ обернув в геттер, работает как ожидалось

// composable должны нормализовать входные данные с помощью `toValue()`
useDynamicCount(() => count)

Для тех, кто предпочитает лучше отличать деструктурированные реквизиты от обычных переменных, в @vuelanguage-tools 2.1 появилась опциональная настройка, позволяющая включать для них подсказки:

Вышел Vue 3.5 - 1

Подробности:

См. документацию по использованию и предостережения. См. RFC#502 для истории и обоснования дизайна этой функции.

Улучшения SSR

В версии 3.5 реализовано несколько давно ожидаемых улучшений в рендеринге на стороне сервера (SSR).

Ленивая гидратация

Теперь асинхронные компоненты могут контролировать время гидратации, указывая стратегию с помощью опции hydrate в API defineAsyncComponent(). Например, чтобы компонент гидратировался только тогда, когда он становится видимым:

import { defineAsyncComponent, hydrateOnVisible } from 'vue'

const AsyncComp = defineAsyncComponent({
  loader: () => import('./Comp.vue'),
  hydrate: hydrateOnVisible()
})

Основной API намеренно более низкого уровня, и команда Nuxt уже создает синтаксический сахар более высокого уровня на основе этой функции.

Подробности: PR#11458

useId()

useId() - это API, который можно использовать для генерации уникальных идентификаторов для каждого приложения, которые гарантированно будут стабильными при рендеринге на сервере и клиенте. Они могут использоваться для генерации идентификаторов элементов форм и атрибутов доступности, а также могут применяться в SSR-приложениях, не приводя к несоответствию гидратации:

<script setup>
import { useId } from 'vue'

const id = useId()
</script>

<template>
  <form>
    <label :for="id">Name:</label>
    <input :id="id" type="text" />
  </form>
</template>

Подробнее: PR#11404

data-allow-mismatch

В случаях, когда клиентское значение неизбежно отличается от своего серверного аналога (например, даты), мы теперь можем подавлять возникающие предупреждения о несоответствии гидратации с помощью атрибутов data-allow-mismatch:

<span data-allow-mismatch>{{ data.toLocaleString() }}</span>

Вы также можете ограничить допустимые типы несоответствий, указав значение атрибута, где возможными значениями являются textchildrenclassstyle иattribute .

Улучшения пользовательских элементов

В версии 3.5 исправлено множество давних проблем, связанных с API defineCustomElement(), и добавлен ряд новых возможностей для создания пользовательских элементов с помощью Vue:

  • Поддержка конфигураций приложений для пользовательских элементов с помощью опции configureApp.

  • Добавьте useHost(), useShadowRoot() и this.$host для доступа к элементу host и shadow root пользовательского элемента.

  • Поддержка установки пользовательских элементов без Shadow DOM путем передачи shadowRoot: false.

  • Поддержка предоставления опции nonce, которая будет прикрепляться к тегам <style>, вводимым пользовательскими элементами.

Эти новые опции, предназначенные только для пользовательских элементов, могут быть переданы в defineCustomElement через второй аргумент:

import MyElement from './MyElement.ce.vue'

defineCustomElements(MyElement, {
  shadowRoot: false,
  nonce: 'xxx',
  configureApp(app) {
    app.config.errorHandler = ...
  }
})

Другие примечательные особенности

useTemplateRef()

В версии 3.5 появился новый способ получения ссылок на шаблоны с помощью API useTemplateRef():

<script setup>
import { useTemplateRef } from 'vue'

const inputRef = useTemplateRef('input')
</script>

<template>
  <input ref="input">
</template>

До версии 3.5 мы рекомендовали использовать обычные ссылки с именами переменных, совпадающими со статическими атрибутами ссылок. Старый подход требовал, чтобы атрибуты ссылок были анализируемы компилятором, и поэтому был ограничен статическими атрибутами ссылок. В отличие от этого, useTemplateRef() сопоставляет рефссылки по идентификаторам строк времени выполнения, поэтому поддерживает динамическое привязывание рефссылки к изменяющимся идентификаторам.

В @vue/language-tools 2.1 также реализована специальная поддержка нового синтаксиса, поэтому при использовании useTemplateRef() вы получите автодополнение и предупреждения, основанные на наличии атрибутов ref в вашем шаблоне:

Вышел Vue 3.5 - 2

Deferred Teleport

Известное ограничение встроенного компонента <Teleport> заключается в том, что его целевой элемент должен существовать в момент установки компонента телепортации. Это не позволяло пользователям телепортировать содержимое в другие элементы, отрисованные Vue после телепортации.

В 3.5 мы добавили свойство defer для <Teleport> , которое монтирует его после текущего цикла рендеринга, так что теперь это будет работать:

<Teleport defer target="#container">...</Teleport>
<div id="container"></div>

Это поведение требует prop defer, потому что поведение по умолчанию должно быть обратно совместимым.

Подробнее: PR#11387

onWatcherCleanup()

В версии 3.5 появился глобально импортируемый API, onWatcherCleanup(), для регистрации обратных вызовов очистки в наблюдателях:

import { watch, onWatcherCleanup } from 'vue'

watch(id, (newId) => {
  const controller = new AbortController()

  fetch(`/api/${newId}`, { signal: controller.signal }).then(() => {
    // callback logic
  })

  onWatcherCleanup(() => {
    // abort stale request
    controller.abort()
  })
})

Связано: новый раздел документации по очистке побочных эффектов

Автор: qmzik

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js