Vue 3 станет быстрее

    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. Спасибо за исправление опечаток.
    • +28
    • 13.8k
    • 2
    Support the author
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 2

    Only users with full accounts can post comments. Log in, please.