Как стать автором
Обновить

Комментарии 36

А еще я бы добавил вот этот репозиторий из серии you-dont-need-%library%.


Иногда вместо танцев с бубном стоит этот бубен не использовать.


Практически весь lodash заменим нативным Javascript функционалом.
Moment.js можно заменить альтернативной, браузер-ориентированной библиотекой.
А Material-UI стал поддерживать tree-shaking из-коробки.

Иногда действительно есть адекватные замены в несколько ПОНЯТНЫХ строк, а иногда:


// Lodash
var grouped = _.groupBy(['one', 'two', 'three'], 'length')

// Native
var grouped = ['one', 'two', 'three'].reduce((r, v, i, a, k = v.length) => ((r[k] || (r[k] = [])).push(v), r), {})

Я бы на код ревью эту кашу из магических r,v,i,a,k не пропустил

Ключевое слово здесь "иногда". А если бездумно тащить каждую популярную библиотеку на initial load, никакие метрики скорости не пройдут. Конечно, если писать под electron, то можно и Moment.js тянуть без tree-shaking.


А придумывать в качестве аргумента задачи защищающие lodash — довольно странно.

Пусть вы начали писать новый проект, понадобился map по объектам, но вы не взяли лодаш, вы написали Object.values(arrayLikeObject).map


Через несколько дней вам понадобился последний элемент массива и вы написали numbers[numbers.length — 1], зачем тут лодаш?


Еще через несколько дней вам понадобился debounce, вы либо написали свой, либо поставили другую(не лодаш) библиотеку где есть debounce


Еще через несколько дней вам понадобился initial, но вы написали array.slice (и десять раз подумали не перепутали ли вы splice и slice)


Еще через пару дней вам понадобилось отфильтровать что-то из массива, и вы написали array.filter(function(value) {
return value !== filteredValue;
}) и потеряли скорость выполнения кода, ибо вам пришлось заюзать фильтр чтоб получить иммутабельность там где лодаш дает и мутабельные и иммутабельные варианты типа without, pull и так далее


Еще через какое-то время вам понадобился этот ужасный groupBy который нативным методов выглядит жутко. И воооот тут вы ставите лодаш.


А теперь вопрос, через сколько дней (или строк линий кода) в среднем наступит этот момент что лодаш уже можно ставить, и сколько человеко-часов вы потеряли в поисках как нативно сделать простые вещи типа Object.values(obj).map ?


Сколько человеко-QA-часов вы потеряете из-за того что перепутали slice и splice, или случайно мутировали данные там где не нужно, или наоборот?


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


А вдруг с вашим debounce все норм, вы его используете в разных местах по проекту и получаете новую задачу, где вам нужно воспользоваться тем что в lodash debounce есть (к примеру maxTime) а в вашей ПРОСТОЙ реализации по аналогии с сайта you-dont-need- нет?

У нас всё как вы описали от начала и до
Сколько человеко-QA-часов вы потеряете из-за того что перепутали slice и splice

Собственно, наши специалисты не путают slice и splice.
А так нам нормально и без lodash.

Что за надуманный пример? Мало того, что однобуквенные переменные, так еще и коллбэк в reduce принимает пять аргументов (чтобы избежать объявления переменной внутри него), хотя туда передается только четыре.


Вот это, по-вашему, не является заменой в несколько понятных строк кода:


var grouped = ['one', 'two', 'three'].reduce((accumulator, element) => {
    var key = element.length;
    if (!accumulator[key]) {
        accumulator[key] = [];
    }
    accumulator[key].push(element);
    return accumulator;
}, {});

?

Что за надуманный пример?

Я его взял с сайта you-dont-need-lodash который в самом начале этой ветки упоминался.


Вот это, по-вашему, не является заменой в несколько понятных строк кода:

Спорно, увидев такое в коде мне понадобится наверное в 2-10 раз больше времени чтоб прочитать/осознать чем на _.groupBy(arr, 'length')


А уж если будет баг в функции в которой это используется внутри, то мне еще и придется потратить время чтоб дебажить внутренность этой функции

Вот это, по-вашему, не является заменой в несколько понятных строк кода

Если это встречается раза 2-3 в коде и в целом это и есть вся задача, то да, нет реальной нужды тащить что-то удобнее. Если же у вас повсеместно разные хитрые трансформации данных, то разумеется использование _.keyBy, _.groupBy, _.mapValues и многих других методов сильно упростит восприятие вашего кода.


И да, в принципе вы можете написать свои собственные _.keyBy, _.groupBy, etc методы и сложить их куда-нибудь в ~/helpers/collections.ts. Но если через полгода плотной работы с вашим проектом вы заметите что ваш файл разросся до десятка другого килобайт нетестированного кода, то вы наверное вынужденно согласитесь, что не стоило артачиться с самого начала :D


Особенно если учесть что современные бандлеры умеют подключать только задействованную часть кода либы.


P.S. при попытке типизировать код выше — его читаемость сильно упадёт. А для groupBy есть готовые типы.

Практически весь lodash заменим нативным Javascript функционалом

Вообще любая JS библиотека заменима "нативным Javascript функционалом". Она ведь на JS написана. Давайте не будем использовать NPM! Железная логика :)


Lodash покрывает убогость стандартной библиотеки JS. Я не вижу смысла избегать его в пользу своих велосипедов в проектах среднего и большого размера (за исключением кейсов когда ваш велосипед гораздо круче решает поставленную задачу, разумеется).

Убогость стандартной библиотеки покрывает babel. А поддержка IE8 не стоит ухудшения метрик для всех девайсов, в особенности мобильных.

Убогость стандартной библиотеки покрывает babel

??? причём тут babel? esnext не лечит убогость стандартной библиотеки. Она убога, что с ним, что без него.

Объясните, пожалуйста, почему?

Почему что? ) Почему я рекомендую не писать import { get } from 'lodash/get'? Ну потому что в реальных проектах это легко превращается что половина всех ваших импортов в приложении это копипаста импортов методов лодеша. К чему весь этот мусор если у вас и без того подключён какой-нибудь babel и можно всё сделать гораздо удобнее?

>> Но может случиться так, что, импортировав всю библиотеку, вызовут лишь 4-5 функций. Это приводит нас к вопросу о целесообразности импорта всего пакета в ситуации, когда использовано будет лишь 2-3% его возможностей

Тут не стоит забывать, что импортировав только 4-5 функций мы можем в итоге получить те же самые 23 килобайта, как если бы импортировали всю библиотеку целиком, т.к. некоторые функции lodash тянут за собой вереницу других функций.

А вы попробуйте. Я думаю как бы вы не старались — больше 50% за 5 функций вы не утянете ;)

НЛО прилетело и опубликовало эту надпись здесь

Есть фанаты и такого подхода (lodash.get).

НЛО прилетело и опубликовало эту надпись здесь
Написать, внезапно узнать, что они не всегда верно работают, написать тесты.
Ради опыта и экономии 23Кб…
НЛО прилетело и опубликовало эту надпись здесь

Эти 23Kb скорее всего будут необходимы для первоначального рендеринга и инициализации всего проекта. Врядли вы сможете настроить lodash так, чтобы он действительно нужен был не сразу, а подгружался динамически (как, например, можно сделать с плагином для автокомплита).


А 23Kb — это 10-20% от первоначального бандла напрямую определяющего Time to Interactive метрику.

Так вопрос стоимости:
— потратить, пусть, два часа на каждую самописную функцию или использовать lodash с проигрышем в 10% TTI
— потерять два часа на каждую самописную функцию или использовать альтернативное готовое решение c неполучением «опыта».

Мне кажется, среди этих вариантов нечто самописное проигрывает всегда, если только ты не совсем зеленый junior, пишущий свой pet-проект.
Уж между lodash и альтернативой я буду смотреть на то, когда нужно было реализовать фичу и на насколько нагруженном участке будут использоваться необходимые функции.

Там ещё 1 аргумент в пользу lodash есть. Он уже давно суперпопулярен и большинство разработчиков с ним уже работало, и знает его API. А вот у своих велосипедов будет другое API. Всем новичкам придётся к ним привыкать и наступать на грабли с нуля. Скорее всего никакой документации не будет, хорошо если хотя бы типы будут.

Если вы всё сделали правильно и импортировали 23 KiB lodash-а, то есть вероятность что ваши собственные велосипеды отъели бы 10-30 KiB сами по себе. То же мне выгода :)

Ну, с таким же успехом можно придумать что угодно. Подключить plotly и говорить, что 23KiB фигня по сравнению с 600KiB.
А пользователи с мобильных устройств будут тем временем сажать батарейку.

23 KiB vs 10-30 KiB (1/2...3/2)
23 KiB vs 600 KiB (1/30)


Что вы хотели этим сказать? И ещё уточню — вы отдаёте себе отчёт что 1 картинка из какого-нибудь слайдера часто весит 300 KiB. И никакой gzip её уже не сожмёт (в отличие от lodash-а).


Какой-то фанатизм, ей богу. Если вы хотите оптимизировать скорость загрузки вашего приложения — начните с правильного конца. А для лодеша достаточно подключить babel-plugin-import. Вы легко можете выйти даже в плюс по размеру (на больших проектах).

Ради опыта и экономии 23Кб

Ну круто же. Я серьёзно. Опыт дорогого стоит. Можно безбоязненно тащить из lodash всё когда можешь его сам с нуля весь переписать. Экономит кучу времени. Но в рамках "поучиться" — хороший тренажёр. Ещё и готовые тесты можно взять.

С приходом typescript 3.7.4 появился optional chaining. На мой взгляд get больше не нужен, как и многие ситуации, где применяли тернарные операторы и однострочные if'ы
можно писать так:


     employee?.address?.contact//_.get(employee, "address.contact", []
     //или
     employee?.address?.contact ?? []

Всё так. Особенно это радует в связке с typescript, т.к. _.get возвращает any, а .? сохраняет все типы.

Нормальные библиотеки поддерживают tree-shaking через sideEffects: false в package.json и инструкций /* @__PURE__ */

Вроде бы у material в доке написано, что можно использовать именованные импорты безопасно если вебпак настроен нормально. Думаю в cra он настроен с поддержкой tree shaking. Поправьте если я не прав
https://material-ui.com/ru/guides/minimizing-bundle-size/#when-and-how-to-use-tree-shaking

Эм… А может хватит смотреть на moment и ждать, пока его разобьют на части? :)
Давным давно есть прекрасные date-fns и luxon (последний, кстати, от авторов moment)

Конкретно с Lodash — мимо. Для ES-модулей и tree shaking есть lodash-es.

А это использовать нельзя при правильно сконфигурированном межмодульном взаимодействии, т.к. у lodash один экспорт — default:

import { get } from 'lodash';


Вот это
_.get(employee, "address.contact", []);

убивает все автокомплиты и проверки типов в IDE. Ну а с приходом оператора .? вовсе перестает быть нужным.

Импорт отдельных функций — вполне понятная самоцель, главное, чтобы она не выходила за рамки разумного. Ну а вопрос «своё или подключать обширную либу» стоит всегда и в любом языке. Обе крайности плохи — и подключение либы ради одной-двух простых функций, и упорная реализация собственных велосипедов для всего подряд.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий