Screenshot-1
Одним из самых ярких событий в мире Фронтенда в этому году стала публикация репозитория Vue next — части функционала третьей версии VueJS. В этой статье представлен обзор новых killer features VueJS. На момент публикации статьи репозиторий находился в статусе Pre-Alpha. Планы на релиз можно посмотреть в Roadmap

Предыстория


В феврале 2018 Evan You, создатель Vue.js, поделился планами на 3 версию популярного фреймворка:

  • Разбить функциональность на пакеты для изоляции области видимости
  • В кодовой базе появится TypeScript
  • Vue 3 будет иметь обратную совместимость со 2й версией (т.е. не сломает старый код)
  • Наблюдатели в 3.0 версии основаны на Proxy, что увеличит скорость рендера и снимет ряд ограничений накладываемых Object.defineProperty
  • Появится возможность дебажить с помощью новых хуков renderTracked и renderTriggered
  • Благодаря введению tree shaking (исключение из билда неиспользуемых директив) размер фреймворка составит меньше 10kb в сжатом виде
  • Оптимизация слотов
  • Перфоманс во vue 3 улучшится на 100%

Features such as built-in components and directive runtime helpers (v-model) are now imported on-demand and tree-shakable
Evan You
Компилятор будет отслеживать наличие директив и включать их в билд на стадии компиляции.

В процессе работы над Vue 3 Эван отказался от переписывания компонентов на классы и вместо этого внедрил функциональное API.

Поскольку новая версия будет использовать Proxy, которые не поддерживаются в IE, Эван планирует сделать отдельный билд для IE11. Всего обещают 4 фазы:

  1. Alpha Phase — стадия доработки компилятора и ssr-рендера
  2. Beta Phase — стадия доработки основных библиотек (Vue Router, Vuex, Vue CLI, Vue DevTools)
  3. RC Phase — стадия пререлиза, включающая в себя Vue 2.0
  4. IE11 build
  5. Final Release

Финальный релиз Эван запланировал на 2019 год, но проект все еще в стадии пре-альфа.

Vue 3 будет быстрее


Благодаря ряду нововведений Vue 3 станет в 2 раза быстрее предыдущей версии.

Proxy-based Observation and Reactivity


Одним из крупных нововведений стало изменение механизма наблюдения за объектами с геттеров и сеттеров Object.defineProperty на Proxy. Теперь Vue может отслеживать удаление и добавление свойств реактивных объектов без использования Vue.set и Vue.delete. Нововведение увеличило скорость рендеринга и скриптинга и уменьшило потребление памяти в 2 раза! Сравнить перфоманс Vue 2 и Vue 3 можно, скачав репозиторий Ильи Климова

Сравнение производительности Vue 2 (слева) и Vue 3 (стадия pre-alpha, справа)
Screenshot-1

Благодаря проксям не потеряется реактивность при изменении не отслеживаемых во Vue 2 манипуляций с объектами. Теперь Vue не будет рекурсивно проходить по свойствам объекта, чтобы вычислить изменения.

Что выполнено из обещаний:

  • Компоненты-потомки и родители перерисовываются независимо
  • Уменьшился размер Vue 3 с 20kb до 10kb в сжатом виде
  • Добавлен TypeScript

Другие оптимизации:

  • Vue 3 будет запоминать статичный контент и патчить только динамические данные
  • Статичные пропсы поднимутся наверх области видимости
  • Для простоты разработки код Vue 3 разбит на модульные пакеты
  • Пакет runtime-core сделан кроссплатформенным
  • Вместо классов Эван добавил setup функцию и хуки, благодаря которым код становится чистым, организованным и переиспользуемым*
  • Time Slicing*. Выполнение JS кода нарезается на куски, не блокируя взаимодействие пользователя с приложением

Звездочками отмечено экспериментальное API.
Update: Позже Эван решил отказаться от time sliсing

Вдохновившись HOC Реакта Эван реализовал setup функции с переиспользуемой логикой и кастомными хуками. В отличие от миксинов хуки жизненного цикла не перезаписывают друг друга.

Усовершенствованный патч VDom


Хойстинг статического контента

Screenshot-2

Статичный контент выносится за пределы патчинга VDom при компиляции шаблона. На это команду Vue вдохновил Svelte:

<div>Hello, {{name}}</div>

Здесь передается объект changed и контекст. Если changed содержит реактивную переменную, то она обновляется в контексте.

p(changed, ctx) {
    if(changed.name) {
        set_data(t1, ctx.name);
    }
}

В предыдущей реализации компилятор Vue проходился по всем нодам, включая статичные:

function render(){
    const children = [];
    for(let i = 0; i < 5; i++) {
        children.push(h('p', {
            class: 'text'
        }, i === 2 ? this.message : 'Lorem upsum'))
    }
    return h('div', { id: 'content' }, children)
}

Новая стратегия компиляции шаблонов


В новой версии шаблон разбивается на блоки:

Selection-002

  • Шаблон делится на блоки
  • Структура нод внутри каждого блока полностью статична
  • Для отслеживания динамических значений в блоке требуется только 1 плоский массив, куда они помещаются

С новой стратегией производительность напрямую зависит от количества динамического контента вместо размера шаблона.

Vue 3 будет лучше адаптирован под большие проекты


Большие проекты сталкиваются со следующими проблемами при использовании Vue:

  1. Не идеальная поддержка TypeScript
  2. Массивные, сложно поддерживаемые компоненты
  3. Отсутствие простого паттерна для переиспользования кода

Изначально для поддержки TS планировалось добавить классы. Но команда Vue столкнулась с проблемами:


Команда Эвана запросила помощь у экспертов из TC39 и выяснила, что подобная реализация могла бы конфликтовать с плагинами, которые примешивают различные пропсы и атрибуты к контексту Vue.

Потенциально эти проблемы могли решить декораторы, но они находятся в разработке.

Composition API


Команда Vue вдохновилась хуками Реакта и решила создать подобное API. Оно опционально и находится в стадии разработки и обсуждения, поэтому некоторые названия могут меняться.
Главная концепция этого изменения — организовать код компонента логичнее, разбив его на смысловые блоки. Подробнее про composition API можно прочитать в документации.

Пример использования Vue 3. Компонент разбивается на логические функции, внутри которых можно использовать реактивность и хуки жизненного цикла.

Импортируем новые хуки из composition API:

import { reactive, computed, onMounted } from '@vue/composition-api';
export default {
  setup() {
    const { state } = countAnimal("rabbit")
    const { getType, anotherState } = anotherCount()
    return {
      state,
      getType,
      anotherState
    }
  }
}

В функции countAnimal есть реактивные свойства count, animal и метод increment. При нечетном счетчике имя животного меняется. Счетчик запускается при монтировании компонента.

function countAnimal(name) {
  const state = reactive({
    count: 0,
    animal: computed(() => state.count % 2 ? name : 'bear')
  })
  function increment() {
    setTimeout(() => {
      state.count++;
      increment()
    }, 1000)
  }
  onMounted(() => {
    increment()
  })
  return {
    state
  }
}

Создаем другую функцию anotherCount, которая тоже содержит метод increment и state с счетчиком и названием животного. В метод getType передается название животного из шаблона.

function anotherCount() {
  const anotherState = reactive({
    count: 0,
    animal: 'fox'
  })
  function getType(name) {
    return name == 'bear' ? 'slow' : 'fast'
  }
  function increment() {
    setTimeout(() => {
      anotherState.count+=10;
      increment()
    }, 1000)
  }
  onMounted(() => {
    increment()
  })
  return {
    getType,
    anotherState
  }
}

В шаблоне выводятся 2 счетчика и 2 имени животных. Тип бега меняется в зависимости от имени животного.

<template>
  <div>
    <div>Count {{state.animal}}: {{ state.count }}</div>
    <div>{{state.animal}} runs {{getType(state.animal)}}</div>
    <div>Another:
    Count {{anotherState.animal}}: {{ anotherState.count }}</div>
  </div>
</template>

Новые хуки используются внутри setup, не ломая старый API. Обратите внимание, что onMounted ссылается на единый хук жизненного цикла компонента.

У такого апи есть ряд преимуществ:

  • Хуки жизненного цикла не перетирают друг друга
  • Понятен источник свойств
  • Не создаются дополнительные экземпляры компонента

Заключение


Выше перечислены самые важные изменения во Vue 3. Большинство улучшений будут скрыты под капотом сгенерированного компилятором кода.

Основные улучшения:

  • Сгенерированный код оптимальнее для JS компилятора
  • Сгенерированный bundle легче
  • Компоненты родителей/потомков перерисовываются благодаря улучшенному алгоритму патчинга

Vue успел зарекомендовать себя, как один из самых быстрых и оптимальных фреймворков. Новая версия станет еще быстрее и легче. Vue 3 отлично подходит для современного мобильно- и перфоманс-ориентированного веба. Комментарий о будущих изменениях можно оставить в официальном RFC (request for comments).
P.S. Спасибо за исправление опечаток.

Комментарии (1)


  1. CyberTopTuK
    04.12.2019 17:43

    Time Slicing*. Выполнение JS кода нарезается на куски, не блокируя взаимодействие пользователя с приложением

    Time slicing was removed from 3.0
    https://github.com/vuejs/rfcs/issues/89#issuecomment-546988615