Vue,js Feed — Канал русскоговорящего сообщества
174 subscribers
3 photos
30 links
Канал Vue.js русскоговорящего сообщества: @vuejs_ru
Download Telegram
Vue 3.4.alpha.2 + alpha.3

Вчера вышло сразу две следующие альфы Vue 3.4.

🧹 Удалён Reactivity Transform ($ref сахар), который был deprecated в Vue 3.3

🫱 Добавлена сокращённая запись директивы v-bind, когда аргумент директивы совпадает со значением (аналогично { shorthand } в JS объектах ):
<input :disabled="disabled" />
<UiInput :model-value="modelValue" />

Теперь можно записывать как

<input :disabled />
<UiInput :model-value />

PR: https://github.com/vuejs/core/pull/9451

🕰 Добавлен oldValue для computed.
Подобно watch теперь можно получить старое значение вычисляемого свойства при перевычислении.
Это позволяет, например, избежать лишнего вычисления нового значения при иммутабельных изменениях
const dataObject = computed((oldValue) => {
const newValue = computeSomeObject()
// Если объект получился с тем же значением - возвращаем старый,
// чтобы не создавать новый объект по новой ссылке
// и не триггерить реактивность лишний раз
return isEqual(newValue, oldValue) ? oldValue : newValue
})

PR: https://github.com/vuejs/core/pull/9497

👀 Улучшен DX ошибок. Теперь в ошибке в рантайме будет ссылка на страницу ошибок в документации
https://deploy-preview-2515--vuejs.netlify.app/errors/

Полный список изменений: https://github.com/vuejs/core/compare/v3.3.9...v3.4.0-alpha.3
CHANGELOG: https://github.com/vuejs/core/blob/v3.4.0-alpha.3/CHANGELOG.md
🔥15👏3😱3🎉3🤔2👍1🙏1
🚀 Vue 3.4.0-beta.1

- defineModel макрос больше не экспериментальный, а его производительность улучшена

- Появилась поддержка MathML тегов для шаблона

- Добавился тип ComponentInstance, позволяющий из типа описания компонента получить тип экземпляра компонента

- В валидатор пропсов теперь приходят значения других пропсов
color: {
type: String,
validator: (value, props) =>
props.format === 'hex'
? HEX_RE.test(value)
: RGB_RE.test(value)
},


- defineSlots теперь поддерживает keyof от generic компонентов. Это позволяет описывать тип слотов в зависимости от типа пропсов, например, для типизации универсальной таблицы
<script lang="ts" setup generic="TRow extends Record<string, unknown>">
const props = defineProps<{
rows: TRow[] // тип объекта для каждой строки - из дженерика
cols: { name: keyof TRow; label: string }[]
}>()

const slots = defineSlots<{
// Тип слота для заголовкой каждой ячейки
[K in keyof TRow as `header:${K & string}`]: (props: {
col: { name: keyof TRow; label: string }
}) => any[]
}>()
</script>


А также множество фиксов и улучшений для SSR и Suspense и других изменений.
Полный CHANGELOG: https://github.com/vuejs/core/blob/v3.4.0-beta.1/CHANGELOG.md
🔥12👍3🎉3🤯2👏1😱1
Forwarded from Denis Chernov
https://github.com/vuejs/vue/blob/main/CHANGELOG.md
Финальный релиз для Vue2 2,7,16 с грустным именем: Swan Song
В релизе нет новых фичей, лишь последний набор правки багов

А 31 декабря мы попрощаемся с официальным EOL для Vue2 (Хотя есть компания которая продолжит выпускать Security-патчи, так что все не так плохо)
Кто-то останется до конца на 2ке
Для кого-то станет мотивацией уйти на 3ку
А кто-то попращается с экосистемой Vue

Press V to pay respect
👍3
В документации Vue появился глоссарий.

Может помочь как в изучении фреймворка при работе с незнакомыми терминами, так и разработчикам говорить на одном языке при упоминании термина.

https://vuejs.org/glossary/

Спасибо @mattersj за ссылочку.
🔥83😱2👍1🤔1
🚀 Релиз Vue 3.4.0 Slam Dunk

Относительно beta и rc релизов ничего нового, так что вспомним обо всех значимых изменениях в них.

Добавления и значимые улучшения

🏎 Ускорение реактивности PR#5912, включающее в себя множество оптимизаций. Например, ранее computed не был зависимостью как самостоятельное значение, использующий его эффект зависел от его вычисления. Теперь перевычисление computed с тем же результатом не будет триггерить использующие его эффекты.

🌼 Долгожданный once в watch. Теперь можно однократно среагировать на изменение значения без ручного вызова stop!
// before
const foo = ref(...)
const stop = watch(foo, () => {
// react
stop()
})

// After v3.4
watch(foo, () => {
// react
}, { once: true })


🫱 Добавлена сокращённая запись директивы v-bind, когда аргумент директивы совпадает со значением (аналогично { shorthand } в JS объектах ):

<input :disabled="disabled" />
<UiInput :model-value="modelValue" />

Теперь можно записывать как

<input :disabled />
<UiInput :model-value />


🕰 Добавлен oldValue для computed.
Подобно watch теперь можно получить старое значение вычисляемого свойства при перевычислении.
Это позволяет, например, избежать лишнего вычисления нового значения при иммутабельных изменениях

const dataObject = computed((oldValue) => {
const newValue = computeSomeObject()
// Если объект получился с тем же значением - возвращаем старый,
// чтобы не создавать новый объект по новой ссылке
// и не триггерить реактивность лишний раз
return isEqual(newValue, oldValue) ? oldValue : newValue
})


- defineModel макрос больше не экспериментальный, а его производительность улучшена
const modelValue = defineModel()
// Заменяет (но эффективнее)
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
const modelValue = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
})


∫ Появилась поддержка MathML тегов для шаблона

🛡 В валидатор пропсов теперь приходят значения других пропсов

color: {
type: String,
validator: (value, props) =>
props.format === 'hex'
? HEX_RE.test(value)
: RGB_RE.test(value)
},


А также улучшения для TS

Добавился тип ComponentInstance, позволяющий из типа описания компонента получить тип экземпляра компонента

defineSlots теперь поддерживает keyof от generic компонентов. Это позволяет описывать тип слотов в зависимости от типа пропсов, например, для типизации универсальной таблицы
<script lang="ts" setup generic="TRow extends Record<string, unknown>">
const props = defineProps<{
rows: TRow[] // тип объекта для каждой строки - из дженерика
cols: { name: keyof TRow; label: string }[]
}>()

const slots = defineSlots<{
// Тип слота для заголовкой каждой ячейки
[K in keyof TRow as `header:${K & string}`]: (props: {
col: { name: keyof TRow; label: string }
}) => any[]
}>()
</script>


Удалены `deprecated`:

🧹 Reactivity Transform ($ref сахар), который был deprecated в Vue 3.3. Много горячих обсуждений было о разных вариантах его внедрения.

🧹 Директива v-is, вместо которой используется специальный атрибут is

🧹 app.config.unwrapInjectedRef, который включен по умолчанию с 3.3

🧹 Старые события жизненного цикла компонента @vnodeXXX, вместо которых есть @vue:xxx

Прочее:
- Улучшение вывода ошибок компиляции шаблона в проде
- Улучшение типизации, включая JSX
- Множество багфиксов в SSR и гидратации
- Багфиксы Suspense

Подробности в блоге: https://blog.vuejs.org/posts/vue-3-4
Changelog: https://github.com/vuejs/core/blob/main/CHANGELOG.md#340-slam-dunk-2023-12-29
🔥105🎉4😱3👍2
🤕 Vue 3.4.0 вышел в релиз только 2 недели назад, но за ним уже последовало 9 патчей, а на этой неделе патчи буквально каждый день. Иногда в них откатывают изменения. Пофикшено много багов с SSR, suspense, compiler-sfc, а также несколько багов нового defineModel, новой реализации реактивности, включая производительность, и другие.

Если используете Vue 3 в проде, где критичны ошибки, или не хотите разбираться, вылезхает ли у вас ошибка из-за бага в Vue или вашего бага - возможно, стоит не обновляться на 3.4 пока он не стабилизируется, и хотя бы несколько недель не будет новых патчей и активного появления новых issue.

FULL CHANGELOG
😢5👍2😱21🤔1🤯1🤬1🥴1
Ещё одна интересная статья об опыте миграции на Vitest.
1🔥1🤔1
Vitest: 9 месяцев спустя

Напомню, мы в Авиасейлс переехали с Jest на Vitest и были (ну, я уж точно) не очень довольны результатом. Прошло 9 месяцев, вышла Vitest 1.0 (а актуальная версия уже и 1.2.1) и мы научились с ним как-то жить.

Во-первых, я оказался прав на счёт шардирования. В синтетических тестах (только vitest в пайплайне, это существенно ускоряет тесты) используя 12 тредов, тесты проходили за ~3 минуты. 4 шарда по 3 треда в каждом (с меньшим количеством тредов тесты начинали зависать) мы укладываемся в ~2 минуты. Сайд-эффект шардов — теперь у нас 4 разных отчёта, а не один единый. Неудобно. Команда Vitest открыта к blob репортерам, как в playwright. Их можно склеить после и получить единый отчёт. Осталось написать ишью и реализовать, хех.
Касательно перформанса тредов вот моё ишью — The performance of threads doesn't scale much after 8 threads.

Во-вторых, нам удалось стабилизировать тесты и избавиться от залипаний и случайных падений. С тех пор мы обновились до node v18.19.0 и vitest v1.1.3, удалили любые исключения из poolMatchGlobs и используем threads пул (стандартный и не самый быстрый).

В-третьих, нестабильность витеста породила особенный подход обновлению его самого и ноды. Мы запускаем 100+ пайплайнов по крону, смотрим fail rate и принимаем решение об обновлении или включении каких-то опций. Как я сказал выше, на v1.1.3 нам удалось добиться 100% стабильности, но вот уже с v1.2.1 (latest) один из тестов начинает отваливаться в трети случаев.

В-четвёртых, я был не особо прав, когда сравнивал типы пулов. С тех пор в витесте появился пул vmThreads, который полностью копирует подход из джеста. Он действительно быстрее (в нашем случае срезает ~30 секунд), но менее стабильный и течёт по памяти (как и джест).

В общем, кажется мы научились его готовить, но иногда процесс готовки становится, прямо скажем, неприятным.
👍1😱1
Forwarded from Vue-FAQ
Vue.js Nation конференция началась с часовой рекламы курсов и сертификаций (скоро появится по Nuxt и JS)

Затем Evan You отвечал на вопросы ведущей:

- Поддержка TypeScript во Vue 3 нормальная
- В феврале будет Vuenniversary - 10 лет Vue
- В 3.5 и 3.6 изменения будут небольшие, типа сomponent types и uuid для SSR
- Во второй половине года объявит о чем-то интересном (exciting)
- Если Signals будут стандартизованы, то Vue может использовать это
- Elk (клиент Mastodon) - пример крутого нетривиального приложения на Vue (Nuxt)
- Vue украл был вдохновлен разными моментами в Angular 1, React, Knockout, Svelte
- Options API убирать не собираются
- Evan сомневается, что React идет куда-то туда с RSC
- Объяснил, почему не рекомендуется мутировать пропс-объект (не так явно видно, кто и как его меняет)
- VitePress 1.0.0 готов, но в конце декабря они погрязли в другой работе и не релизнулись. Скоро выпустят с фанфарами.
- AI сильно фронтенд не изменит в ближайшем времени. Пока это просто помощник

#evanyou #vuejsnation
👍7😁2🤔1
Forwarded from artalog (artalar)
Зачем реатом во vue?

У нас там апдейты подъехали, стоит рассказать о мотивации.

Во вью из коробки идут простые и достаточно мощные примитивы для обработки состояния, рефы можно создавать вне компонента и большая часть задач этим решается. Но есть ряд вопросов, которые реатом покрывает лучше.

- Реатом лучше позволяет описывать логику полностью отделенную от компонента, которую потом еще и легче дебажить. Проявляется это в наличии лайфсайкл хуков у каждого атома (можно инициировать ресурс на первую подписку - использование в компоненте, и уничтожить ресурс при последней отписке) и выделенной сущности “экшен”, для удобного разделения кода на логические блоки. Т.к. все эти сущности именованны (автоматически еслинтом), в последствии можно наблюдать полезные логи того что поменялось и по какой причине (уникальная фича реатома).

- За счет первого пункта реатом можно использовать как ядро микрофронтовой системы, у нас уже есть адаптеры для vue, react, solid, svelte, и в разработке адаптеры для lit и angular.

- У реатома есть очень мощные примитивы для описания асинхронной логики, собравшие все самое лучшее с rxjs, redux-saga и TanStack Query. Тут впринципе альтернатив, вроде, нет.

- У реатома одна из самых больших экосистем среди всех стейт менеджеров и, посмею сказать, самая сбалансированная. При этом, каждый пакет разрабатывается с маниакальным фокусом на бандлсайзе и перфе.

Если стало интересно, вот видосики по реатому: https://www.youtube.com/playlist?list=PLXObawgXpIfxERCN8Lqd89wdsXeUHm9XU
👍5🤔1
Forwarded from Denis Chernov
vue-vapor обзавелся своим плейграундом.

Для тех кто не знает что это:
На данный момент Vue используем механизм VDOM (виртуальный DOM), но у него есть свои недостатки: избыточность по памяти, непрямое изменение и тд
Так вот Vapor это вдохновленный Solid-ом подход к механизму рендеринга без использования VDOM. Все происходит чисто на работе реактивности и счедуллингу эффектов. Более подробно можно ознакомиться тут

Мы можем вполне оценить то что уже сделано в плейграунде:
https://vapor-repl.netlify.app

выглядит действительно многообещающе
Для того, чтобы увидеть результат работы заходим во вкладку: JS / SSR
там можно обратить внимание как меняется результат билда между vapor режимом и обыкновенным (кликаем VAPOR ON/OFF в правой части шапки плейграунда)

На что я обратил внимание:
1) более агрессивно берется все из контекста рендеринга (например, Array сейчас будет браться из _ctx.Array). В исходники не заглядывал, но возможно исправят
2) Часть функционала ожидаемо нереализована (ее можно посмотреть на чеклисте репозитория )
3) Багов хватает :D Любая попытка потестить перф выходила каким-то багом

В целом решение пока сыроватое и прям сильно его не оценить. Но первые шаги уже видны явно, а не на словах
🤔6🔥3👍21
Forwarded from Denis Chernov
Ого какая новость пролетела мимо:
Vue опять нехило импрувнули перф реактивности (в этот раз поменяли структуры данных используемые внутри системы реактивности на манер сигналов Preact)

Это дало перф:
- на ~56% уменьшено потребление памяти системой реактивности 🤯
- случай когда 1 реф вызыввает несколько эффектов (+118%-185% прирост производительности)
- чтение множества invalidated computed-ов (+176%+244% прирост производительности)

Дополнительно:
- Обнова обещает никак не афектить поведение и вся реализация прячется лишь в @vue/reactivity
- Закрывает некоторые специфичные баги/корнер-кейсы для системы реактивности
- Компьютеды стали гораздо дешевле и теперь еще более ленивые
- теперь если компьютед не имеет подписчиков на него то он сбрасывает все свои зависимости
- компьютед теперь в целом не может иметь зависимостей если от него никто не зависит
- Противный варнинг из 3.4.19 о грязных компьютедах удален!
- Обещают что сборка мусора в режиме SSR будет работать лучше (как это будет аффектить в реальности пока неизвестно)

Для любителей копаться в тонкостях:
- Больше никакого ручного счедуллинга:
- pauseScheduling, pauseTracking, resetScheduling больше недоступны (впрочем они и не были задокументированной возможностью)
- теперь зависимости в deps это не Map/Set а самостоятельная структура Dep с версионированием и на базе двусвязанного списка
- код стал читаться как-то проще :D
- еще не копался на в Dev режиме включили какой-то трекинг по типу действия сигнала и как его трекают

Обновление попало в минорную ветку, так что пока неизвестно когда оно попадет в наши приложения. Однако остается только порадоваться, как много сил было вложено в последнее время в повышение перфа во Vue за последние месяцы
👍43🔥1
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. Багов выше крыши. Советую переждать недельку!
6👍4
Документация Vue наконец получила долгожданный обновленный перевод на русский язык, который теперь доступен по ссылке ниже, а также в шапке основной англоязычной версии в блоке переводов:

https://ru.vuejs.org/

До этого на русском языке была доступна только устаревшая документация, написанная практически сразу после первоначального релиза Vue 3, но с тех пор многое изменилось, поэтому теперь рекомендуется читать именно обновленную документацию.

Переведены все основные разделы, но в документации все еще есть ошибки и неточности, например, на странице “Component v-model” описана работа функции toValue.

Если вы встретили ошибку/опечатку/неточность, о которой еще не написано в issues - можно создать его, либо исправить самому, прислав Pull Request.

Спасибо всем, кто помогал и принимал участие в переводе!
🔥326👍4🎉3🙏1
Через пол часа начинается митап от MSK Vue.js

Смотреть онлайн трансляцию можно по ссылке: https://youtube.com/live/7SWzCjDPtoQ
🔥64🌚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.

<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 - Появился новый компосабл 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/
👍9🔥53🤔1🎉1🕊1🌚1
Vue 3.5.0-alpha.3: появился 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
👍8🤔8🔥5
Vue 3.5: появился отдельный API для работы с cleanup-функциями в watch/watchEffect - 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
🔥15🤔2👍1
Работа с картинками в шаблоне
!src #help

1. Почему такой код не работает? Картинка точно есть по этому, и без переменной работает!
<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
👍84🔥2👏1🤔1