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

Contacts: @RuslanMakarov
Download Telegram
Использование функций на массивах, типа filter, map и других, очень удобно и даёт красивый код, но может создавать проблемы в производительности из-за:

1. Выделения и потом уничтожения промежуточных массивов
2. Cоздавания циклов в циклах ( сложность O(N^2) ), хотя весь код можно разместить в одном цикле ( O(N) )

Например, код 1. ниже выполняется в 2-3 раза дольше, чем код 2.

// setup:
const numbers = Array.from({ length: 10000 }).map(() => Math.random())

// 1. functional
const result =
numbers
.map(n => Math.round(n * 10))
.filter(n => n % 2 === 0)
.reduce((a, n) => a + n, 0)

// 2. imperative
let result = 0
for (let i = 0; i < numbers.length; i++) {
let n = Math.round(numbers[i] * 10)
if (n % 2 !== 0) continue
result = result + n
}


#js #optimization
Во всех браузерах кроме Firefox реализован Fetch Priority API

Это атрибут fetchpriority на тэгах img, script, link, который указывает, насколько приоритетен данный ресурс для загрузки.

Это важно в первую очередь для метрик Core Web Vitals, а именно - LCP. Если элемент LCP - картинка, имеет смысл указать ей fetchpriority="high".

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

Также можно указать fetchpriority="low" для картинок вне области видимости, - в том числе, в слайдере.

#tip #optimization #webvitals
Если у вас есть большая строка в JavaScript, и вы с помощью slice() вытаскиваете из нее подстроку, то эта подстрока не даст Garbage Collector-у уничтожить большую строку, даже если вы на нее больше не ссылаетесь. Это верно в V8, где подстрока оформляется как С++ указатель на нужное место в большой строке. В результате при обработке большого числа строковых данных могут происходить утечки памяти. Чтобы избежать этого можно делать копирование подстроки.

Также утверждение, что конкатенация строк - дорогая операция, уже не соответствует действительности. Например, на массиве строк

.join(' ')


будет медленней конкатенации через reduce:

.reduce((acc, c) => acc + ' ' + c, '')


Опять же из-за особенностей V8. Более того, конкатенация будет даже быстрее шаблонов строк (`Hello ${name}`), хотя обычно учат обратному.

В целях оптимизации работы со строками следует избегать мутирующих операций.

#tip #js #optimization
Подбирайте для своих данных подходящую структуру, в зависимости от операций над ними.
Это сильно влияет на производительность

В примере ниже Array.includes() примерно в три раза медленней, чем Set.has()

// setup:
const userIds = Array.from({ length: 1000 }).map((_, i) => i)
const adminIdsArray = userIds.slice(0, 10)
const adminIdsSet = new Set(adminIdsArray)

// 1. Array

let num = 0
for (let i = 0; i < userIds.length; i++) {
if (adminIdsArray.includes(userIds[i])) { num += 1 }
}

// 2. Set

let num = 0
for (let i = 0; i < userIds.length; i++) {
if (adminIdsSet.has(userIds[i])) { num += 1 }
}


#js #optimization
В подтверждение нашему недавнему совету по оптимизации js кода, твит Эвана:

Самое приятное в этом то, что вы можете писать хороший функциональный код, который выполняет итерации над коллекциями (аналогично map, filter и т.д.) с оптимизированной вручную производительностью.

Каждый раз, когда я использую map/filter в JS вместо обычных циклов for, мне кажется, что я добровольно отказываюсь от производительности.

#tip #optimization #evanyou
Самое время узнать, за счет чего главная лендинговая статичная страница GitLab смогла набрать 13Мб в скриптах

На скриншоте бандлофобии разрезолвились не все пакеты

Первая тройка тяжеловесов:

1. @nuxtjs/i18n - 2.5Mb
2. slippers-ui (GitLab's Marketing Design System) - 1.8Mb
3. vue-mermaid-string (построение диаграмм) - 1.1Mb

#gitlab #optimization #nuxt #i18n
Немного OSINT-a в ленту.

Давайте еще поизучаем результаты исследования бандла лендинга GitLab, потому что это интересно и познавательно.

Первая тройка тяжеловесов:

1. @nuxtjs/i18n - 2.5Mb
2. slippers-ui (GitLab's Marketing Design System) - 1.8Mb
3. vue-mermaid-string (построение диаграмм) - 1.1Mb

На третьем месте хорошая библиотека для генерации налету диаграмм по тексту mairmaid . Я тоже хотел поставить её на Vue-FAQ, поставил, посмотрел насколько она просадила размер бандла и производительность в браузере, убрал и заменил генерацию налету на статичные заранее сгенеренные ею картинки ради UX.

На втором - slippers-ui, это гитлабовский относительно небольшой (20 компонент) UI kit. Без какого- либо тришейкинга и оптимизации, естественно. Очень много, с учетом того, что любая современная UI библиотека весит в несколько раз меньше.

Ну и победитель - то, за что так любят Nuxt. Это когда он берет что-то хорошее и делает его еще лучше. В этот раз он взял vue-i18n, естественно, для интернационализации.

Используя pkg-size.dev смотрим сперва на vue-i18n, отключив учет peer dependencies:

Install size: 2.8MB / 6 packages
Bundle size: 73KB minified (23KB gzip) / 9 modules

Очень неплохо для i18n библиотеки

То же с @nuxtjs/i18n:

Install size: 61MB / 239 packages
Bundle size: Не собрался (ошибки)

Error: Process exited with code 1
✘ [ERROR] No matching export in "node_modules/unicorn-magic/default.js" for import "toPath"


Bundlephobia тоже дала ошибки при сборке

Самая простая реализация i18n пишется в один composable. Но на Nuxt-e всё намного серьезней.

#nuxt #optimization #i18n #gitlab
Два самых значимых улучшения в грядущем Vue 3.5 связаны с оптимизацией реактивности

- PR#9511 - улучшает работу с большими reactive массивами (которые сейчас обслуживаются как все объекты - через Proxy), что должно дать многократное ускорение при работе с ним и оптимизацию по памяти

- PR#10407 - в целом в два раза уменьшает использование памяти на реактивном коде

#vuejs #optimization
v-memo - директива для микро-оптимизации

При изменении актуального состояния компонента он ре-рендится весь. Может случиться, что какие-то куски его шаблона тяжелы для построения, и при определенных изменениях их не надо ре-рендерить, тогда можно определить эту логику через v-memo. Особенно это может пригодиться при отображении большого массива нетривиальных элементов/компонентов.

#optimization
Поставил Firebase Authentication на сайт (логин через Google, Apple и т.д.)

Бандл был 200Кб, стал 400Кб...

wtf%№?:;*"(;?;*!!!!!

AI бот предлагает другие варианты, но уверяет, что они хуже.

Кто как делает?

#firebase #auth #optimization
В очередной раз делая i18n на Vue проекте, задумался - а зачем этому модулю (и функции t() в частности) реактивность? Неважно, стандартный это i18n-next или самописный.

Понятно, что для того, чтобы при смене языка он сразу менялся на странице без ее перезагрузки. А оно того стоит? Ценой этого - пронизывание практически всех компонентов сетью реактивной зависимости, что точно не благотворно сказывается на производительности и сложности кода.

Большинство сайтов направлены на определенную языковую аудиторию. Кроме того, можно определять по браузеру язык системы и автоматически в него переключаться в первый раз. То есть, процент тех, кто на сайте сменит язык какой - 1-2? И из-за одного их переключения должны тормозить все?

Напомню, что у монструозного лендинга GitLab основная зависимость в 13Mb скриптов именно i18n

Какие мысли по этому поводу?

#i18n #optimization
Сайт icones.js.org довольно удобен для подбора иконок (хотя выбор средний и поиска по параметрам нет, но хорошо сделано копирование найденного сразу в svg), но такое потребление памяти после поиска нескольких иконок выше понимания.

К вопросу о том, качественный ли код пишет Anthony Fu, автор VueUse, Nuxt и многого другого

#antfu #icons #optimization
VS Code позволяет отключить аппаратное ускорение при отрисовке, что может заметно убыстрить IDE при плохом GPU или проблемах с драйверами

1. Preferences > Configure Runtime Arguments
2. Добавить: "disable-hardware-acceleration": true

Или сразу в .vscode/argv.json

#vscode #tip #optimization
Vite позволяет использовать новый более производительный и функциональный компилятор SASS через эту опцию:

export default {
css: {
preprocessorOptions: {
scss: {
api: 'modern-compiler'
}
}
}
}


Дефолтным его не делали пока потому, что это breaking change, но в Vite 6 он будет по умолчанию.

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

#vite #css #optimization
Заспорил тут в Твиттере с создателем FormKit Justin Schroeder, который с чего-то призвал отказаться от использования ref в пользу reactive

На аргумент о ShallowRef он привел ShallowReactive, и стало интересно, как сильно они отличаются

В итоге получился вот такой бенчмарк на Stackblitz по замеру времени изменения разных массивов

ShallowRef не использует JavaScript Proxy, отсюда такая эффективность

С одной стороны, ужасно, как Proxy уронил общую производительность в JS

С другой, еще раз стало очевидно, что писать программы на Vue надо с умом. Необходимо полностью контролировать модель и потоки данных. Именно поэтому доверять таким библиотекам, как VueUse и Tanstack, это, как минимум, торговать производительностью и архитектурой.

#optimization #benchmark
Сперва они советуют всегда для роутов использовать динамичные роуты, потом учат делать префетчинг...

Этот совет из документации Vue Router - самое глупое что есть в ближайшей Vue экосистеме.

#routing #optimization
// useUserService.ts

function isAuthenticated() {
return !!user.value;
}


// Component A

<script>
const { isAuthenticated } = useUserService();
</script>

<template>
<p v-if="isAuthenticated()">hello</p>
</template>


Функции во Vue ведут себя не совсем как функции

В данном примере функция isAuthenticated() ведет себя как computed и будет вызываться каждый раз, когда user изменится или компонент А будет перерисовываться.

Происходит это из-за того, что Vue определяет все реактивные зависимости внутри тела функции и перерендивает компонент, когда кто-то из них меняется.

Таким образом, большой разницы в использовании функции вместо computed нет. Но если внутри большая логика, то лучше использовать computed, потому что он будет пересчитываться только когда его зависимости изменились, а функция - при любом рендеринге

#reactivity #tip #optimization
Время от времени можно удалять локальный npm/yarn/ pnpm кэш, чтобы освободить место на диске от устаревших версий пакетов.

#npm #pnpm #optimization
Датацентры всего мира производят 3.7% мирового CO2 (carbon footprint, углекислый газ)

Каждый показ вашего сайта является причиной выделения CO2 - в среднем 0.8 грамм.

Замерьте карбоновый след вашего сайта

Еще одна причина писать эффективные PWA

#pwa #optimization