Vue-FAQ
923 subscribers
561 photos
90 videos
556 links
Канал сайта https://vue-faq.org
Информация о Vue.js, фронтенд разработке и не только

Contacts: @RuslanMakarov
Download Telegram
Оптимизатор Элон сразу взял быка за рога.

Мир вздрогнул.

#musk
В чате vuejs_ru вчера прошла короткая дискуссия о вредности и ненужности :deep(). Типа его можно заменить на установление путем JS в 2 строчки класса на внутреннем компоненте.

Попросил привести пример в случае, если container query во внешнем компоненте меняет flex-direction во внутреннем - абсолютно реальный use-case.

Возможно, конечно, но две строчки CSS превращаются в кучу громоздкого уродливого JS с огромными потерями в производительности.

:deep() - это инструмент, пользоваться им надо умело, и не будет никаких проблем. Если ты постоянно пытаешься, ограничивая инструментарий, сделать защиту от дурака, то ты этих дураков и плодишь.

CSS - это уровень представления вашего приложения, его функционал давно выходит за пределы только простенькой адаптивности, анимации и цветовых тем. В CSS тоже есть логика, и перекладывать её работу на JS нецелесообразно.

CSS
всегда на порядки быстрей JS в браузерах. И поэтому использование JS вместо CSS как минимум очень сильно бьет по производительности, да еще и замусоривает скриптовую секцию вашего SFC.

Когда мне надо в проекте сделать свой небольшой UI kit, я обычно size=large в BaseButton передаю не пропсом, а CSS классом. Потому что эта штука принадлежит именно уровню представления - то есть, CSS. И потому что приложение так будет работать быстрее, а SFC получается проще, чище и понятней.

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

TS для разработчика, а не разработчик для TS.

#css
Красивая картинка, объясняющая почему закрыли проекты "Буран" и "Space Shuttle", и почему SpaceX Маска революционализировал космос

(стоимость вывода 1кг груза на орбиту)

#musk #offtop
Copilot Edits

Не успели мы написать о каскадном прыжке Codeium, как тут и Copilot вылез.

GitHub Copilot добавил в VS Code в свое расширение функцию Copilot Edits - генерация кода в разных файлах (аналог Cursor Composer и Codeium Cascade)

Причем, Copilot по-прежнему остается расширением IDE, хотя Cursor и Codeium типа "не смогли" добиться такого функционала и вынуждены были форкнуть VS Code для своих платных продуктов. Видимо такая у последних двух бизнес модель.

VS Code разместил об этом новость у себя и показал, как сгенерить окно логина на примере проекта на Vue ))



Еще интересные AI помощники для IDE, к которым можно подключить свою LLM - Continue, Cline (опенсорсные) и
Codebuddy (не опенсорсный). Планирую на своем мини-пк все-таки развернуть небольшую LLM и попробовать работать локально.

#vscode #ai #copilot
Олдскульные программеры

- работал программистом над полетами «Аполлона».
- основал компанию McAfee software
- входил в Forbes Top 100
- убил своего отца
- был кандидатом в президенты США
- разыскивается в 3 странах
- пережил 50+ покушений
- женился на проститутке, которую наняли, чтобы убить его
- стоял за спиной Эдварда Сноудена
- биткоин-миллиардер
- написал книгу «Ямы и ниямы йоги» и основал секту в Колорадо
- взломал офис Хиллари Клинтон, отправив ее сотрудникам бесплатные компьютеры
- убил человека в Белизе
- жил на яхте в Карибском море с вооруженной охраной
- использовал шпионское ПО для сбора данных
- имел компромат на правительства и картели разных стран и шантажировал их
- сбежал из плена в Гватемале, симулировав сердечный приступ
- по официальным заявлениям, совершил самоубийство в тюрьме
- может быть жив

John McAfee

Скрываясь в Белизе, пригласил из США съемочную бригаду, в результате чего получилась супер крутая документалка "Running with the Devil: The Wild World of John McAfee"

#offtop
Поговорим о Shared composables

Страшный термин, который многие понимают, как хотят.

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

1. Composable

Это технически (JS closure) и по факту (ООП) объект с данными и поведением. Компонент его создает, пользуется, при уничтожении компонента обнуляется ссылка на объект, и он подлежит уборке Garbage Collector-ом (GC).

2. "Модульный реф" / Pinia store

Тоже можно считать объектом в смысле ООП, но реализующим паттерн Singleton. Создается при первом вызове его кем-либо, затем ссылка на него записывается в некий глобальный реестр, и любой другой компонент, обращающийся к этой структуре, получает эту ссылку и работает с тем же самым инстансом.

3. Shared composable как в примерах в документации во VueUse и Vue

Рождается как стор, умирает как обычный composable. При первом обращении создается один объект, который затем используется всеми компонентами, которым он нужен. Но как только не остается ни одного такого компонента, этот объект "умирает". В дальнейшем если он понадобится, он создается опять в одном экземпляре.

Некоторые разработчики (не будем показывать пальцем) уверены, что использование shared composable именно как реактивного стейта вместо модульного рефа/стора помогает сделать программу эффективней.

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

Вот у нас есть модульный реф с рефом. Вот он используется, потом все компоненты со ссылкой на него, уничтожаются. Что происходит? Ничего. У него нет внешних зависимостей, он просто лежит мертвым грузом в памяти, занимая свои несчастные пару килобайт. Появился использующий его компонент - он заработал.

Как с shared composable? Вот он создается, используется, потом все компоненты, его использующие, кончаются - и он должен типа уничтожиться. Вызывается код по обнулению, но у Garbage CollectorJS VM своя логика работы, и он не будет чистить эту память сразу. А если и будет - потратит на это ресурсы CPU. Затем снова появляется компонент, которому нужен этот объект - и он снова создается, тратятся ресурсы CPU, выделяется новая память. И так по кругу. В итоге, через 10 циклов у нас в куче памяти в 10 раз больше, чем нам надо, зарезервированного места, и мы потратили в десять раз больше ресурсов на создание/уничтожение структуры.

Так для чего нужен shared composable?

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

Таким образом,

состояние в shared composable выполняет не самостоятельную функцию, а является просто адаптером для некого внешнего сервиса / Web API.

И суть shared composable - создать единую реактивную точку доступа к внешнему сервису.

Даже чисто логически если подумать (по описанному выше юз-кейсу в пункте 3), то shared composable не может использоваться для непосредственного обмена данными между компонентами. Он может только передавать данные во внешний сервис, и получать их оттуда. Даже vueuse/useLocalStorage так работает. И если передача не удалась - это ошибка выполнения программы.

Но, опять же, если подумать, то данная логика (оптимизация работы с внешним сервисом) очень похожа на логику работы глобального лоадера. И реализована может быть так же в несколько строк, безо всяких effectScope и прочих заморочек - простым и понятным кодом. Нету там ничего из Composition API, что надобилось бы для реализации данной логики. Обычный модульный реф и синхронный код для отслеживания числа подписчиков с подключением/отключением этого рефа к внешнему сервису.

Ref, reactive, shallowRef, watch и computed должны покрывать 99.9% потребностей прикладного программирования на Vue.js. Не надо делать простое сложным.

Shared composable как он есть - изначально неудачное название и ненужная структура. Предлагается не использовать.

#composable #reactivity
Как же это близко...

Иногда хочется перед отправкой промпта встать на колени и сложить молитвенно ладони. Не потому что религия, а в качестве такого символического гагаринского "Поехали!".

Хотя... Если в LLM используют квазислучайность для придания большей естественности ответам, почему бы психо-энергетически не попытаться направить ее в нужное тебе русло?

#ai
FilePond

Подсказали красивый file uploader компонент

15K+ звезд, много плагинов,, правда, довольно увесистый - 100Кб+

На JS. Подключается монтированием к элементу.

<script setup lang="ts">
import * as FilePond from "filepond";
import FilePondPluginFileValidateType from "filepond-plugin-file-validate-type";
import { onMounted, ref, useTemplateRef } from "vue";
import "filepond/dist/filepond.min.css";

const fileInput = useTemplateRef("fileInput");

FilePond.registerPlugin(FilePondPluginFileValidateType);

onMounted(() => {
FilePond.setOptions({
acceptedFileTypes: ["image/*", "application/pdf"],
server: "api/upload/",
});
FilePond.create(fileInput.value);
});
</script>

<template>
<div class="analysis-view">
<h2>Analysis upload</h2>
<p></p>
<input
ref="fileInput"
type="file"
class="filepond"
name="filepond"
multiple
data-allow-reorder="true"
data-max-file-size="3MB"
data-max-files="3"
/>
</div>
</template>


Вот, кстати, один из вариантов использовать динамические импорты/роуты - в мобильной версии drag-n-drop не нужен, поэтому можно обойтись более простым file input и сэкономить на бандле.

#lib
Довольно свежие Vue сниппеты для VS Code, среди большого количества хлама.

Vue 3 VS Code Snippets

#vscode #tip
Появление на фронтенде всевозможных фреймворков, методологий и прочей ереси - это woke-идеология

#esse
В команде Nuxt-а при выводе Nitro на внешний рынок внезапно осознали, что автоимпорты - плохо. И попытались их сделать опциональными. Но вход - рубль, выход - два.

Дело настолько деликатное, что ветку даже закрыли для просмотра посторонними.

Автоимпорты имеют существенные проблемы:
- не весь тулинг (IDE, Volar etc) их понимает, не всегда будут подсказки;
- код с ними выглядит гораздо менее явным, чем с обычными импортами в IDE;
- полная нечитабельность на площадках типа GitHub;

#goodpractices #nuxt
Уже и индийские vue.js митапы идут.

Где в странах ex-СССР?

Московская тусовка, ау?

#event
Случайно нашел неплохой бесплатный хостинг для бэка

alwaysdata.net

До 100Mb, MySQL/PostgreSQL с портом наружу, PHP, Python, Ruby, Node.js, Elixir, Java, Deno, .NET , SSH, подключение кастомного домена

Год использую - всё ровно.

#webhosting
Сегодня - читальный зал

Белобров Попов
Груз ВКЖ-65

#offtop
Для реализации своих tooltip-ов и "выпадашек", наверное, самым оптимальный вариантом является использование современной и минималистичной библиотеки Floating UI

Их Vue адаптер мне не подошел. Вот простой вариант своего тултипа на их чистом js пакете.

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

Обертывать в Tooltip компонент то, на чем его надо показать, имхо, извращение.

<script setup lang="ts">
import { computePosition, flip, offset, shift } from "@floating-ui/dom";
import { onMounted, ref, useTemplateRef } from "vue";

const popover = useTemplateRef("popover");

onMounted(() => {
popover.value.showPopover();
computePosition(popover.value.parentElement, popover.value, {
placement: "left",
middleware: [flip(), shift({ padding: 5 }), offset(10)],
}).then(({ x, y }) => {
Object.assign(popover.value.style, {
left: `${x}px`,
top: `${y}px`,
});
});
});
</script>

<template>
<div
ref="popover"
class="popover"
popover
role="tooltip"
>
<div class="tooltip-body">Hello</div>
</div>
</template>

<style scoped>
.popover {
position: fixed;
width: max-content;
top: 0;
left: 0;
margin: 0;
padding: 1em;
text-align: left;
border: 1px solid var(--bbl-c-border);
border-radius: 5px;
max-width: 400px;
box-shadow:
0 14px 44px rgba(0, 0, 0, 0.12),
0 3px 9px rgba(0, 0, 0, 0.12);
border-color: #bbb;
}
</style>

#lib #tooltip #dropdown
Чтобы немного нейтрализовать психологическую травму, нанесенную TypeScript, вот на ночь четыре капли седатива от JS

#js