Forwarded from Denis Chernov
Такс ребятушки. Новый исторический момент в мире Vue.js: Vue language tools v2
- Что это такое и как оно нас касается?
не так давно вы могли слышать о обнове Volar.js. Если нет, то не страшно. Команда Vue очень заточена под улучшения экосистемы целиком, а не только Vue-разработчиков. Поэтому Джонсон (которого вы можете знать по тем самым обновлениям с перфом реактивности во Vue3) закорешился с мейнтенейром Astro и мейнтейнером MDX. Что этих крутышей связывает? Им нужно встраивать несколько языков в рамках одного файла и поддерживать при этом высокий DX. На самом деле это задача не из простых. И во Vue это проявлялось в VSC тем, что был злополучный Takeover Mode. Это особый режим который перекрывает плагин TS и вынуждал нас включать 2 плагина и отключать родной от TS.
Конечно все это пугало новичков. Но полтора месяца назад было объявляено, что эту проблему смогли побороть в рамках Volar 2. Теперь плагин использует возможности самого lsp от TS и не требует перекрытия плагином. С этого момента я оч ждал обновы language-tools.
https://github.com/vuejs/language-tools/releases/tag/v2.0.0
И вот час назад этот релиз вышел:
БОЛЬШЕ НИКАКОГО TAKEOVER MODE
+ к этому
- мы получаем родные для TS преобразования от TS плагина
- правит множество багов связанных с интеграцией и кастомным языком для VSC
- Больше нет плагина Volar - так как это более глобальный проект о фреймворке для поддержания авторов фреймворков. Теперь плагин это "Vue - Official"
- можете смело удалять расширение "TypeScript Vue Plugin"
Как это отразится на пользователях JetBrains? Пока сказать сложно, но буквально недавно была конференция у брейнсов, где скорее всего эту тему поднимали. Очень хочется верить, что это отразится на DX в IDE у JetBrains, так как они уже почти год переехали на Vue language server
PS. Вышло всего час назад, так что вполне возможны баги :D
PPS. Багов выше крыши. Советую переждать недельку!
- Что это такое и как оно нас касается?
не так давно вы могли слышать о обнове Volar.js. Если нет, то не страшно. Команда Vue очень заточена под улучшения экосистемы целиком, а не только Vue-разработчиков. Поэтому Джонсон (которого вы можете знать по тем самым обновлениям с перфом реактивности во Vue3) закорешился с мейнтенейром Astro и мейнтейнером MDX. Что этих крутышей связывает? Им нужно встраивать несколько языков в рамках одного файла и поддерживать при этом высокий DX. На самом деле это задача не из простых. И во Vue это проявлялось в VSC тем, что был злополучный Takeover Mode. Это особый режим который перекрывает плагин TS и вынуждал нас включать 2 плагина и отключать родной от TS.
Конечно все это пугало новичков. Но полтора месяца назад было объявляено, что эту проблему смогли побороть в рамках Volar 2. Теперь плагин использует возможности самого lsp от TS и не требует перекрытия плагином. С этого момента я оч ждал обновы language-tools.
https://github.com/vuejs/language-tools/releases/tag/v2.0.0
И вот час назад этот релиз вышел:
БОЛЬШЕ НИКАКОГО TAKEOVER MODE
+ к этому
- мы получаем родные для TS преобразования от TS плагина
- правит множество багов связанных с интеграцией и кастомным языком для VSC
- Больше нет плагина Volar - так как это более глобальный проект о фреймворке для поддержания авторов фреймворков. Теперь плагин это "Vue - Official"
- можете смело удалять расширение "TypeScript Vue Plugin"
Как это отразится на пользователях JetBrains? Пока сказать сложно, но буквально недавно была конференция у брейнсов, где скорее всего эту тему поднимали. Очень хочется верить, что это отразится на DX в IDE у JetBrains, так как они уже почти год переехали на Vue language server
PS. Вышло всего час назад, так что вполне возможны баги :D
PPS. Багов выше крыши. Советую переждать недельку!
GitHub
Release v2.0.0 · vuejs/language-tools
New Features
Hybrid Mode
Takeover Mode has been deprecated. The extension now has the same performance as Takeover Mode by default.
TypeScript language support has been moved from Vue language se...
Hybrid Mode
Takeover Mode has been deprecated. The extension now has the same performance as Takeover Mode by default.
TypeScript language support has been moved from Vue language se...
❤6👍4
Документация Vue наконец получила долгожданный обновленный перевод на русский язык, который теперь доступен по ссылке ниже, а также в шапке основной англоязычной версии в блоке переводов:
https://ru.vuejs.org/
До этого на русском языке была доступна только устаревшая документация, написанная практически сразу после первоначального релиза Vue 3, но с тех пор многое изменилось, поэтому теперь рекомендуется читать именно обновленную документацию.
Переведены все основные разделы, но в документации все еще есть ошибки и неточности, например, на странице “Component v-model” описана работа функции
Если вы встретили ошибку/опечатку/неточность, о которой еще не написано в issues - можно создать его, либо исправить самому, прислав Pull Request.
Спасибо всем, кто помогал и принимал участие в переводе!
https://ru.vuejs.org/
До этого на русском языке была доступна только устаревшая документация, написанная практически сразу после первоначального релиза Vue 3, но с тех пор многое изменилось, поэтому теперь рекомендуется читать именно обновленную документацию.
Переведены все основные разделы, но в документации все еще есть ошибки и неточности, например, на странице “Component v-model” описана работа функции
toValue
.Если вы встретили ошибку/опечатку/неточность, о которой еще не написано в issues - можно создать его, либо исправить самому, прислав Pull Request.
Спасибо всем, кто помогал и принимал участие в переводе!
ru.vuejs.org
Vue.js
Vue.js - The Progressive JavaScript Framework
🔥32❤6👍4🎉3🙏1
Через пол часа начинается митап от MSK Vue.js
Смотреть онлайн трансляцию можно по ссылке: https://youtube.com/live/7SWzCjDPtoQ
Смотреть онлайн трансляцию можно по ссылке: https://youtube.com/live/7SWzCjDPtoQ
YouTube
Meetup #12
🔥6❤4🌚1
Vue 3.5 alpha.1 - Reactive Props Destructure
#vue_3_5 #changelog
Начали выходить alpha и beta версии нового Vue 🎉
Первое обновление - Reactive Props Destructure теперь доступен без экспериментального флага. Позволяет более красиво описывать значения по умолчанию в SFC Setup + TS.
RFC был спорный и долго горячо обсуждался. При компиляции обращение к переменой превращается в обращение к полю объекта.
Обсуждался ещё с 3.2 и был ранее добавлен под экспериментальным флагом в 3.3.
- RFC: https://github.com/vuejs/rfcs/discussions/502
#vue_3_5 #changelog
Начали выходить alpha и beta версии нового Vue 🎉
Первое обновление - Reactive Props Destructure теперь доступен без экспериментального флага. Позволяет более красиво описывать значения по умолчанию в SFC Setup + TS.
RFC был спорный и долго горячо обсуждался. При компиляции обращение к переменой превращается в обращение к полю объекта.
Обсуждался ещё с 3.2 и был ранее добавлен под экспериментальным флагом в 3.3.
<script setup lang="ts">
// Before
const props = withDefaults(defineProps<
foo?: string
>(), {
foo: 'foo'
})
// After
const { foo = 'foo' } = defineProps<
foo?: string
>()
// foo <==> props.foo
</script>
- RFC: https://github.com/vuejs/rfcs/discussions/502
👍6👎2🔥2😢1
Vue 3.5.0-alpha.3 - Появился новый компосабл
#vue_3_5 #changelog
Типичный use-case - id элементов, например, форм и атрибуты для доступности.
Результат получается невоспроизводимым, что усложняет тестирование и не работает на SSR
Такое решение может приводить к дублированию ID. Например, и в вашем приложении, и в UI фреймворке могли сделать
Чтобы облегчить жизнь разработчиков, добавили долгожданный
- PR: https://github.com/vuejs/core/pull/11404/
useId()
для генерации ID в компонентах.#vue_3_5 #changelog
const inputId = useId()
Зачем генерировать ID?
Типичный use-case - id элементов, например, форм и атрибуты для доступности.
Почему не просто `Math.random()` или `nanoid()`?
Результат получается невоспроизводимым, что усложняет тестирование и не работает на SSR
Почему не просто `id++`?
Такое решение может приводить к дублированию ID. Например, и в вашем приложении, и в UI фреймворке могли сделать
input-label-${id++}
.Чтобы облегчить жизнь разработчиков, добавили долгожданный
useId
, возвращающий уникальный ID, префикс которого можно настроить в конфиге Vue приложения.const app = createApp(App)
app.config.idPrefix = 'my-app'
// useId() === "my-app:0"
- PR: https://github.com/vuejs/core/pull/11404/
GitHub
feat(runtime-core): useId() by yyx990803 · Pull Request #11404 · vuejs/core
Similar to React's useId, this composable returns a unique ID that can be used for form elements and accessibility attributes.
The generated IDs look like v:1-2-3 and are unique across each...
The generated IDs look like v:1-2-3 and are unique across each...
👍9🔥5❤3🤔1🎉1🕊1🌚1
Vue 3.5.0-alpha.3: появился
#vue_3_5 #changelog
Позволяет описывать свойства для
- Семантически понятнее - явно определяется как переменная для template ref
-
- Значение атрибута
- Возможно, будет особая поддержка в IDE ?
- Commit: https://github.com/vuejs/core/commit/3ba70e49b5856c53611c314d4855d679a546a7df
useTemplateRef(key)
для Template Ref
#vue_3_5 #changelog
Позволяет описывать свойства для
Template Ref
аналогично ref()
. Отличия:- Семантически понятнее - явно определяется как переменная для template ref
-
readonly
- нельзя случайно изменить вручную- Значение атрибута
ref
- определяемый отдельно ключ, а не имя переменной (свойства компонента)- Возможно, будет особая поддержка в IDE ?
<script setup lang="ts">
// Vue 3.5+
const inputElement = useTemplateRef<HTMLInputElement>('inputElement')
// Или с отдельным ключом
const fileInputKey = 'FILE_INPUT'
const fileInputElement = useTemplateRef<HTMLInputElement>(fileInputKey)
// Аналог в прошлых версиях
const inputElement = ref<HTMLInputElement|null>()
</script>
<template>
<input ref="inputElement" />
<input :ref="fileInputKey" type="file" />
</template>
- Commit: https://github.com/vuejs/core/commit/3ba70e49b5856c53611c314d4855d679a546a7df
GitHub
feat: useTemplateRef() · vuejs/core@3ba70e4
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web. - feat: useTemplateRef() · vuejs/core@3ba70e4
👍8🤔8🔥5
Vue 3.5: появился отдельный API для работы с cleanup-функциями в watch/watchEffect -
- позволяет зарегистрировать функцию “очищения”, которая будет вызываться прямо перед повторным запуском watch/watchEffect (например, если изменилась зависимость и он вот-вот сработает);
- подходит для того, чтобы, например, отменять асинхронные запросы (избегая гонки состояний) или очищать старые таймеры перед запуском новых;
- сильно облегчает работу в паре с
- имеет те же ограничения, что и остальные функции, привязанные к контексту выполнения - должен выполняться синхронно и вызываться внутри watch/watchEffect;
- дополнительно имеет второй аргумент
либо можно воспользоваться еще одной новой функцией
тогда cleanup-функция будет зарегистрирована только в том случае, если мы находимся внутри watch/watchEffect.
Использование:
Новый подраздел в документации: https://vuejs.org/guide/essentials/watchers.html#side-effect-cleanup
PR: https://github.com/vuejs/core/pull/9927
#vue_3_5 #changelog
onWatcherCleanup
:- позволяет зарегистрировать функцию “очищения”, которая будет вызываться прямо перед повторным запуском watch/watchEffect (например, если изменилась зависимость и он вот-вот сработает);
- подходит для того, чтобы, например, отменять асинхронные запросы (избегая гонки состояний) или очищать старые таймеры перед запуском новых;
- сильно облегчает работу в паре с
watch
: сейчас функция onCleanup
передается в него третьим аргументом (после value и oldValue), что довольно неудобно, особенно, если первые 2 аргумента не нужны, поэтому раньше приходилось писать (_, __, onCleanup)
;- имеет те же ограничения, что и остальные функции, привязанные к контексту выполнения - должен выполняться синхронно и вызываться внутри watch/watchEffect;
- дополнительно имеет второй аргумент
failSilently
, куда можно передать true
, чтобы не получать предупреждение в консоли, если функция вызвана за пределами watch/watchEffect, что открывает окно для следующих паттернов:
export function request() {
const controller = new AbortController();
// регистрируем cleanup-функцию и передаем failSilently: true
onWatcherCleanup(() => controller.abort(), true);
return fetch(…, { signal: controller.signal });
}
либо можно воспользоваться еще одной новой функцией
getCurrentWatcher
и переписать код выше иначе:
export function request() {
const controller = new AbortController();
// если мы внутри вотчера
if (getCurrentWatcher()) {
// то регистрирурем cleanup-функцию
onWatcherCleanup(() => controller.abort());
}
return fetch(…, { signal: controller.signal });
}
тогда cleanup-функция будет зарегистрирована только в том случае, если мы находимся внутри watch/watchEffect.
Использование:
watchEffect(async () => {
const response = await request(…);
});
Новый подраздел в документации: https://vuejs.org/guide/essentials/watchers.html#side-effect-cleanup
PR: https://github.com/vuejs/core/pull/9927
#vue_3_5 #changelog
vuejs.org
Vue.js
Vue.js - The Progressive JavaScript Framework
🔥15🤔2👍1
Работа с картинками в шаблоне
1. Почему такой код не работает? Картинка точно есть по этому, и без переменной работает!
Собранное приложение в проде имеет другие файлы по другим путям. Путь относительно исходников - некорректный. Чтобы это работало, нужно работать с картинками и другими ресурсами, как с модулями, прогоняя их через сборщик. Сборщик переместит файл, поменяет имя, и вернёт новое имя, а может даже вставит inline-ссылкой (data url).
2. Но у меня раньше работало без импорта! Например, так:
Сборщик с
Только чистый
3. Что же тогда делать, если надо хранить путь в данных?
Можно использовать:
- Явные импорты, если заранее известен набор файлов
-
-
-
4. Но как работают все эти функции, если тут путь тоже вычисляется только в рантайме, а нужен ещё на этапе сборки?
Сборщик забирает шаблонную строку или конкатенацию строк. Затем считает, что вы можете импортировать в рантайме ЛЮБОЙ файл, подходящий под шаблон. В примерах выше сборщик найдёт все файлы
Более сложные JS выражения не будут работать.
Подробности:
- https://vitejs.dev/guide/assets.html
- https://vitejs.dev/guide/features.html#glob-import
- https://webpack.js.org/guides/asset-management/#loading-images
- https://github.com/vitejs/vite/issues/10597
!src
#help1. Почему такой код не работает? Картинка точно есть по этому, и без переменной работает!
<img :src="`../assets/images/${image}`" />
Собранное приложение в проде имеет другие файлы по другим путям. Путь относительно исходников - некорректный. Чтобы это работало, нужно работать с картинками и другими ресурсами, как с модулями, прогоняя их через сборщик. Сборщик переместит файл, поменяет имя, и вернёт новое имя, а может даже вставит inline-ссылкой (data url).
import Cat from '../images/Cat.png'
console.log(Cat) // выведет /img/Cat.45df63.png
<img :src="Cat" />
2. Но у меня раньше работало без импорта! Например, так:
<img src="@/assets/images/cat.png" />
Сборщик с
@vue/sfc-compiler
знает, что в src
в HTML и url()
в CSS указывается путь. Если он относительный (не с /), то он автоматически работает с ним, как с модулем, сам делая импорт. Но это должен быть статический путь именно в таком атрибуте. :src
с привязкой у JS вычислению или даже data-src
— работать не будут.<img :src="`@/assets/images/cat.png`" data-src="@/assets/images/cat.png" />
<img src="@/assets/images/dog.png" data-src="@/assets/images/dog.png" />
Превращается в
<img src="@/assets/cat.653gtd.png" data-src="@/assets/images/cat.png" />
<img src="/assets/dog.45df63.png" data-src="@/assets/images/dog.png" />
Только чистый
src
обработался, как путь до модуля.3. Что же тогда делать, если надо хранить путь в данных?
Можно использовать:
- Явные импорты, если заранее известен набор файлов
-
require
в Webpack-
new URL
в Vite (без поддержки алиасов и SSR)-
import.glob
в Vite, если нужен список всех файлов// Нам нужна картинка питомца из переменной
const myPet = 'dog'
// Webpack + Vite - прямой импорт
import cat from '@/assets/pets/cat.png'
import dog from '@/assets/pets/dog.png'
const pets = { cat, dog }
const myPetImage = pets[myPet]
// Webpack - require
const myPetImage = require(`../assets/pets/${myPet}.png`)
// Vite - new URL
const myPetImage = new URL(`../assets/pets/${myPet}.png`, import.iss.oneta.url).href
// Vite - import.glob
const petImages = import.iss.oneta.glob('../assets/pets/*.png', { eager: true })
const myPetImage = petImages[`../assets/pets/${myPet}.png`]
4. Но как работают все эти функции, если тут путь тоже вычисляется только в рантайме, а нужен ещё на этапе сборки?
Сборщик забирает шаблонную строку или конкатенацию строк. Затем считает, что вы можете импортировать в рантайме ЛЮБОЙ файл, подходящий под шаблон. В примерах выше сборщик найдёт все файлы
.png
в директории /assets/pets/
.Более сложные JS выражения не будут работать.
new URL(getPetImageByName(myPet)) // ❌ Не сработает
Подробности:
- https://vitejs.dev/guide/assets.html
- https://vitejs.dev/guide/features.html#glob-import
- https://webpack.js.org/guides/asset-management/#loading-images
- https://github.com/vitejs/vite/issues/10597
👍8❤4🔥2👏1🤔1
Отличия ref и reactive
!ref #help
Ref:
- позволяет удобно и просто перезаписать переменную целиком:
- может быть использован с примитивами (string, number, boolean и т.д.);
- представляет из себя геттер и сеттер в случае с примитивами (без Proxy);
- в случае с объектами просто вызывает
- обязательно имеет контейнер, в котором хранит значение (.value), о котором нельзя забывать.
Reactive:
- работает только с непримитивными значениями (объекты и массивы);
- использует Proxy и глубокую реактивность по умолчанию;
- не может быть просто перезаписан целиком по аналогии с
- удобен для группировки связанных значений в общий объект (чтобы не создавать отдельные независимые переменные для связанного состояния);
- поддерживает ref unwrapping (https://vuejs.org/guide/essentials/reactivity-fundamentals.html#additional-ref-unwrapping-details), а значит в него можно положить другие ref’ы, и они раскроются (не нужно будет писать лишний .value) внутри объекта;
- иногда может быть удобнее в типизации - для него не нужно использовать отдельный тип
В общем случае можно просто использовать
Полезные ссылки:
1. https://vuejs.org/guide/essentials/reactivity-fundamentals.html
2. https://vuejs.org/guide/extras/reactivity-in-depth.html#how-reactivity-works-in-vue
3. https://stackoverflow.com/questions/61452458/ref-vs-reactive-in-vue-3/65262638#65262638
!ref #help
ref
и reactive
позволяют создать реактивную переменную, но имеют некоторые отличия:Ref:
- позволяет удобно и просто перезаписать переменную целиком:
example.value = 123
, при этом сохранив реактивность;- может быть использован с примитивами (string, number, boolean и т.д.);
- представляет из себя геттер и сеттер в случае с примитивами (без Proxy);
- в случае с объектами просто вызывает
reactive
и передает обработку ему;- обязательно имеет контейнер, в котором хранит значение (.value), о котором нельзя забывать.
Reactive:
- работает только с непримитивными значениями (объекты и массивы);
- использует Proxy и глубокую реактивность по умолчанию;
- не может быть просто перезаписан целиком по аналогии с
ref
, потому что потеряется реактивность;- удобен для группировки связанных значений в общий объект (чтобы не создавать отдельные независимые переменные для связанного состояния);
- поддерживает ref unwrapping (https://vuejs.org/guide/essentials/reactivity-fundamentals.html#additional-ref-unwrapping-details), а значит в него можно положить другие ref’ы, и они раскроются (не нужно будет писать лишний .value) внутри объекта;
- иногда может быть удобнее в типизации - для него не нужно использовать отдельный тип
MaybeRef<T>
, как в случае с обычным ref
(например, если хочется иметь объект, который может быть как реактивным, так и нет, то типизация и работа с reactive
будет в целом выглядеть удобнее).В общем случае можно просто использовать
ref
, если это кажется проще, но про reactive
тоже полезно помнить, потому что его особенности могут рано или поздно пригодиться.Полезные ссылки:
1. https://vuejs.org/guide/essentials/reactivity-fundamentals.html
2. https://vuejs.org/guide/extras/reactivity-in-depth.html#how-reactivity-works-in-vue
3. https://stackoverflow.com/questions/61452458/ref-vs-reactive-in-vue-3/65262638#65262638
🔥9👍7👏3❤2🤔1
Зачем Pinia, если можно написать свой стор?
!store #help
Во-первых, это прежде всего велосипед - мы пишем свое собственное решение, которое делает то же самое, что и Pinia.
Во-вторых, у этого велосипеда будет масса недостатков по сравнению с готовым решением:
1. Свой простенький стор не будет унифицирован - у него нет единого API, которое диктует формат определения новых сторов, описания их полей и методов. Можно описывать каждое свойство в виде
2. Если идти по пути комплексного решения, продумывать унифицированный интерфейс (аналог
3. В Pinia сторы инициализируются лениво: если в приложении описано 20 сторов, но на странице используется только один, то инициализирован будет тоже только один. В своем решении из коробки не будет “ленивости”, это отдельный функционал, который требует времени на реализацию.
4. В своем простеньком сторе не будет поддержки SSR: код, описанный в ES-модуле, выполняется на сервере только один раз (при старте сервера), а затем переиспользуется каждым клиентом. Это значит, что стор будет один общий на всех клиентов, вместо изолированных инстансов под каждого клиента. В своем сторе не будет поддержки сериализации для передачи данных с сервера на клиент.
5. Переменные, описанные в скоупе ES-модуля, являются глобальными, поэтому, если эти переменные будут использованы в любом другом коде и на них останутся ссылки, то сборщик мусора будет игнорировать такой код и никогда не освободит память, которую этот код занимает. В Pinia такой проблемы нет, потому что сторы создаются не в скоупе модуля.
6. В Pinia все сторы объединены в общий
7. В Pinia все сторы сгруппированы и хранятся в одной общей Map-структуре, в которой всегда можно найти любой стор. В своей реализации сторы будут раскиданы по модулям и ничем не объединены.
8. В Pinia есть поддержка HMR: стейт точечно обновляется при изменении кода, а не сбрасывается целиком, как было бы в своей собственной реализации.
9. В Pinia есть система плагинов: удобно подвязываться на жизненный цикл стора и, например, писать интеграции с внешними хранилищами. И для этого есть унифицированный, задокументированный и оттестированный API.
10. Pinia интегрирована во Vue DevTools: можно смотреть на таймлайны, отслеживать вызовы функций и дебажить сторы.
При этом у своего решения, как правило, практически нет никаких весомых плюсов, кроме потенциально меньшего размера. Но, как понятно из пунктов выше, за эту экономию придется платить функционалом и удобством.
!store #help
Во-первых, это прежде всего велосипед - мы пишем свое собственное решение, которое делает то же самое, что и Pinia.
Во-вторых, у этого велосипеда будет масса недостатков по сравнению с готовым решением:
1. Свой простенький стор не будет унифицирован - у него нет единого API, которое диктует формат определения новых сторов, описания их полей и методов. Можно описывать каждое свойство в виде
export const count = ref(0);
, а можно оборачивать все в useCount
. Этот формат будет негласным и его нужно проговаривать с командой, документировать и делать то, что уже сделано в Pinia.2. Если идти по пути комплексного решения, продумывать унифицированный интерфейс (аналог
defineStore
), то это будет путь к своей копии Pinia, только это решение не покрыто тестами, не прошло проверку в проде, не тестировалось на утечки памяти, не знакомо другим разработчикам, его нельзя добавить в новый проект одной командой и еще много других “не”.3. В Pinia сторы инициализируются лениво: если в приложении описано 20 сторов, но на странице используется только один, то инициализирован будет тоже только один. В своем решении из коробки не будет “ленивости”, это отдельный функционал, который требует времени на реализацию.
4. В своем простеньком сторе не будет поддержки SSR: код, описанный в ES-модуле, выполняется на сервере только один раз (при старте сервера), а затем переиспользуется каждым клиентом. Это значит, что стор будет один общий на всех клиентов, вместо изолированных инстансов под каждого клиента. В своем сторе не будет поддержки сериализации для передачи данных с сервера на клиент.
5. Переменные, описанные в скоупе ES-модуля, являются глобальными, поэтому, если эти переменные будут использованы в любом другом коде и на них останутся ссылки, то сборщик мусора будет игнорировать такой код и никогда не освободит память, которую этот код занимает. В Pinia такой проблемы нет, потому что сторы создаются не в скоупе модуля.
6. В Pinia все сторы объединены в общий
effectScope
, а значит любой стор можно одной строкой “удалить”, очистив все его ref/computed/watch/watchEffect/etc., и освободив память. В своей простой реализации так сделать будет нельзя.7. В Pinia все сторы сгруппированы и хранятся в одной общей Map-структуре, в которой всегда можно найти любой стор. В своей реализации сторы будут раскиданы по модулям и ничем не объединены.
8. В Pinia есть поддержка HMR: стейт точечно обновляется при изменении кода, а не сбрасывается целиком, как было бы в своей собственной реализации.
9. В Pinia есть система плагинов: удобно подвязываться на жизненный цикл стора и, например, писать интеграции с внешними хранилищами. И для этого есть унифицированный, задокументированный и оттестированный API.
10. Pinia интегрирована во Vue DevTools: можно смотреть на таймлайны, отслеживать вызовы функций и дебажить сторы.
При этом у своего решения, как правило, практически нет никаких весомых плюсов, кроме потенциально меньшего размера. Но, как понятно из пунктов выше, за эту экономию придется платить функционалом и удобством.
👍13🔥3❤2