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

Contacts: @RuslanMakarov
Download Telegram
Для Linux:
"count:sfc": "find . -type f -name '*.vue' ! -path '*/node_modules/*' | wc -l"


Для Windows:
"count:sfc": "Get-ChildItem -Recurse -Include *.vue -Exclude '*/node_modules/*' | Measure-Object -Line"


Добавьте в скрипты своего package.json.

Считает число компонент в проекте.

#tip
Чтобы заставить Vite HMR перегружаться при изменении конкретных файлов, иногда может понадобиться такой плагин:

// vite.config.ts

const fullReloadJson5 = {
name: "full-reload-json5",
handleHotUpdate({ file, server }) {
if (file.endsWith(".json5")) {
server.ws.send({ type: "full-reload" });
}
return [];
},
};

// ...
plugins: [
vue(),
json5Plugin(),
fullReloadJson5,
],


#vite #tip
Полезные советы при разработке с IDE AI агентами от @vuefaq.

1. Используйте по возможности системный промпт. Cursor позволяет иметь .cursorrules файл, в котором можно прописать основные установки по проекту. Пример файла.
Напишите свой и попросите AI улучшить его. Автокомплит его плохо видит, но чат и composer - вполне. По крайней мере, свою CSS дизайн систему и компоненты использует четко.

2. Научитесь азам promp-engineering. Это полезно и при разработке, и при диалогах с обычными чатботами. От простого few-shots prompt эффективность результата может вырасти в разы. Не надо винить AI в тупости, если вы не умеете формулировать вопрос на языке, который ему более понятен.

3. Используйте сильные стороны AI. Он может хорошо сгенерить новый компонент, новый микросервис, добавить функционал, сделать i18n перевод, дать совет по какой-то лучшей практике в определённой области, рефакторить, делать рутинные задачи, писать тесты, но не так хорошо работает на больших изменениях с существующим кодом. Также может с нуля нагенерировать плохой неоптимальный код на нестандартных задачах (в таких случаях, необходимо давать максимально подробную информацию о контексте задачи).

4. Используйте его как консультанта перед реализацией какой-то задачи. Задайте несколько вопросов в чате, как что-то можно сделать (с использованием вашего кода как контекста), проанализируйте варианты, выберите подходящий и дальше в composer начните постепенно его реализовывать, руководя процессом. Стратегически важные вопросы задавайте также разным внешним системам - Gemini, ChatGPT, DeepSeek. Иногда кто-то один даёт явно более лучший ответ.

4.1. Вместо «Напиши такой-то модуль» используйте цепочку:
- Проектирование API
- Реализация core-логики
- Добавление обработки ошибок
- Интеграция с существующим кодом
- Оптимизация производительности

5. AI - не старик Хоттабыч, он не творит чудеса. Более того, он очень тупой. Тупой инструмент. Но сильный. Управление им это как управление двухтонным ковшом экскаватора - можно быстро сделать много полезного, и можно быстро сделать кучу плохого (со своим кодом). Которую потом будешь долго разгребать.

6. AI хорошо генерит комментарии и документацию. Можете добавить сразу VitePress к проекту и поддерживать его техническую документацию.

7. При использовании AI сервисов в приложении используйте структурированные (JSON) ответы. Не все это умеют, но последняя 4o-mini, например, умеет (по JSON-scheme). С учетом цены на нее, она очень полезна для парсинга документов или картинок, скажем, из которых предварительно можно вытащить текст конвенциональными методами (pdf2text и OCR).

8. Пробуйте разные модели. Причем, разные модели для разных случаев. Дороже ≠ лучше.

9. Переиспользуемые промпты можно хранить в отдельных текстовых файлах.
Также, научитесь использовать структурированные промпты при необходимости, например:

/analyze-tech-debt 
--focus=duplication,complexity 
--suggest-refactoring


Для современных LLM они, часто, предпочтительней для простых задач.

10. Почитайте документацию к вашей LLM и лучшие практики. Ваша продуктивность ( => стоимость как разработчика) может возрасти в несколько раз с этим инструментом. Потратьте время на то, чтобы научиться им эффективно пользоваться.

#ai #tip #ide #cursor
Если показываете через <router-view> страницу с route параметром (продукты, каталоги, пользователей через id), и надо при смене параметра загружать нового, - то есть, следить за изменением параметра, то делать это можно двумя способами.

Через watch:

watch(
() => props.id,
async () => {
userData.value = await fetchUser(to.params.id);
},
{ immediate: true }
);


Через хук роутера onBeforeRouteUpdate:

js 
import { onBeforeRouteUpdate } from 'vue-router'

onBeforeRouteUpdate(async (to, from) => {
if (to.params.id !== from.params.id) {
userData.value = await fetchUser(to.params.id);
}
})


Второй способ дает еще возможность использовать onBeforeRouteLeave, если вдруг надо

#router #tip
Как отключить scroll страницы, когда показываешь модальный диалог через <dialog>?

body:has(dialog[open]) {
overflow: hidden;
}


Размыть фон/overlay?

dialog::backdrop {
backdrop-filter: blur(2px);
}


#css #tip #scroll
Если делаете два близких приложения (например, клиентский фронтенд и админку) , и хотите расшарить какие-то компоненты и ресурсы, то есть несколько вариантов

1. Монорепозиторий. Оба проекта идут как пакеты и общие пакеты тоже отдельно. На любителя.

2. Выделить общее в отдельный NPM пакет и подключать его. Неудобно возиться с версиями и апдейтом.

3. Делать в одном проекте, настроить на две точки входа. Собирать Vite будет в одну кучу с двумя html файлами входа. Подразумевается, что так удобно работать на одном сайте с двумя мини-приложениями

4. Два отдельных vite.config.ts файла, два html, два App.vue и роутера. В package.json в скриптах прописываете свой Vite конфиг и копирование своего html в index.html. Запускается и собирается каждый как отдельный проект, в коде всё общее.

4. Git submodules. Отдельный проект подключается как поддиректория в твой (общие компоненты).

#tip
Маленький кубик - волшебная иконка в Cursor при поиске

Открывает все найденные файлы в Composer и можно сразу с ними что-то делать / использовать как контекст

#ai #cursor #tip
CSS свойства transform, opacity, filter и некоторые другие используют GPU компьютера для рендеринга.

Проверяйте в browser devtols, что им хватает ресурсов, они не грузят процессор и нет отброшенных фреймов

Свойство will-change используется чтобы явно включить GPU оптимизацию на элементе

#css #tip
Я ранее советовал переходить от .env к конфигурационным файлам в json формате

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

Это значит блок кода

if (import.meta.env.MODE === "development") {
// do some debug work
}


не попадет в бандл вообще в первом случае, а аналог с конфиг файлом - попадет, (но не будет выполняться, естественно).

Так что иногда имеет смысл использовать эту конструкцию (для import.meta.env.MODE переменной .env файл не нужен, она определена всегда).

#vite #tip
Псевдокласс CSS :empty свидетельствует, что в элементе пусто.

Полезен при необходимости, например, обнулять padding и margin пустого элемента, либо делать что-то еще

#css #tip
Если у вас есть массив, в каждом элементе которого есть computed, то лучше создать один на весь массив, чем много для каждого элемента

// Bad
const rows = productRows.map(row => ({
...row,
total: computed(() => row.price * row.qty),
}));


// Good
const computedRows = computed(() =>
productRows.map(row => ({
...row,
total: row.price * row.qty,
}))
);


#tip #performance #reactivity
Глубокое клонирование реактивных объектов в Vue 3

Vue 3 использует Proxy для реактивности, что создает проблемы при попытке клонировать объекты. Стандартные методы работают не так, как ожидается:

const state = reactive({ user: { name: "Al" } });

// Проблемы:
const badCopy1 = { ...state }; // сохраняет Proxy-ссылки
const badCopy2 = JSON.parse(JSON.stringify(state)); // теряет методы и Proxy


3 рабочих способа

1. Комбинация toRaw + structuredClone

import { toRaw } from 'vue';

const original = reactive({ data: 123 });
const copy = structuredClone(toRaw(original));


2. Ручное глубокое копирование

function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
const clone = Array.isArray(obj) ? [] : {};
for (const key in obj) {
clone[key] = deepClone(obj[key]);
}
return clone;
}

const copy = reactive(deepClone(toRaw(original)));


3. Библиотечные решения

import { cloneDeep } from 'lodash-es';
const copy = reactive(cloneDeep(toRaw(obj)));


#tip #reactivity
В конце каждого поста я ставлю хэштеги. Не все, оказалось, знают, что это не просто для красоты или декларативной категоризации

Кликните на какой-нибудь и увидите, почему Telegram на голову выше других известных мессенджеров и соцсетей

По ним же можно искать

#tip #telegram
This media is not supported in your browser
VIEW IN TELEGRAM
:hover > :not(:hover)

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

ul {
@media (hover) and (prefers-reduced-motion: no-preference) {
& > li {
transform-origin: left center;
transition: transform 1s var(--ease-spring-3), opacity 0.3s var(--ease-3);
}

&:hover > li:not(:hover) {
opacity: 0.25;
transform: scale(0.8);
}
}
}


#css #tip
В JS чтобы выйти из вложенных циклов можно использовать метки

outerLoop: for (let i = 0; i < 5; i++) {
let j = 0;
while (true) {
if (j === 2) {
break outerLoop; // Выходит из внешнего цикла
}
j++;
}
}


И не забываем, что Array.prototype.sort() приводит к строкам. Нужен компаратор.

[10, 2, 1].sort(); // [1, 10, 2] (как строки!)  
[10, 2, 1].sort((a, b) => a - b); // [1, 2, 10] (правильно)


#js #tip
Метод navigator.sendBeacon() предоставляет возможность гарантированно отправить небольшой объем данных на сервер, даже если пользователь закрывает страницу или браузер. В отличие от традиционных AJAX-запросов, которые могут быть прерваны при выгрузке страницы, sendBeacon обеспечивает доставку данных в таких сценариях.

Браузер дает запросу sendBeacon приоритетное выполнение перед завершением работы страницы, что делает этот метод идеальным для критически важных данных.

Практические применения

- Финализация аналитических данных - отправка собранной за сессию аналитики перед закрытием страницы
- Автосохранение - сохранение последнего состояния приложения, которое пользователь мог не сохранить явно
- Отчеты об ошибках - гарантированная отправка логов о критических ошибках
- Трекинг поведения - фиксация последних действий пользователя перед уходом

const data = JSON.stringify({event: 'page_close', time: Date.now()});
navigator.sendBeacon('/analytics', data);


Ограничения

- Максимальный размер полезной нагрузки ограничен (обычно 64Кб)
- Поддерживает только POST-запросы
- Не поддерживает кастомные заголовки
- Ответ сервера не может быть обработан

#tip
Несколько месяцев назад Cursor (и другие, наверно, тоже) научились работать с линтером, за один прогон исправляя ошибки

Можно пойти дальше - попросите Cursor написать и использовать тестовый скрипт для проверки некого функционала (без каких либо тестовых библиотек), который вы ему заказали. Тогда агент будет в цикле сам запускать этот скрипт, который будет проверять правильность уже проектного кода, ставить логи, изучать ошибки и исправлять их, пока всё не пофиксит. Часто он делает это сам.

Экономия времени и кредитов.

(не для vue, для js, py, php etc).

P.S. В новом Курсоре появилась фича Run agent in Clouds, включенная по умолчанию, из-за которой редактор начинает жутко тормозить. Можно отключить.

#ai #cursor #tip
При использовании router-view с transition с mode="out-in" в dev режиме при переходах по роутам часто ловится белый экран

Единственное найденное решение - отключать этот mode в dev режиме

<router-view v-slot="{ Component }">
<Transition mode="out-in">
<component :is="Component" />
</Transition>
</router-view>


#router #tip
Совет: если ваш Cursor начал сильно тормозить, почистите историю чатов



На днях Anthropic опубликовала длинный документ, в котором описывает, как его сотрудники используют Claude Code. Можно рассматривать, как полезные советы при работе с AI.

#ai #tip #cursor