Как сбросить вес бандла с датами до двух килобайт без боли
Каждый фронтендер хотя бы раз смотрел на отчет Webpack Bundle Analyzer с тихим ужасом. Огромный кусок пирога почти всегда занимал Moment.js вместе с десятками локалей, которые никто не просил бандлить. Проект давно перешел в статус legacy, авторы сами советуют искать альтернативы, но старые привычки умирают с трудом. Привычный чейнинг вызовов и форматирование строк въелись в пальцы на уровне мышечной памяти.
Именно для таких случаев и создали Day.js. Библиотека весит всего 2 килобайта в сжатом виде, при этом сохраняет почти стопроцентную совместимость с API Moment.js.
Что под капотом и почему она такая легкая
Основная проблема старых библиотек заключалась в монолитности. Вы подключали пакет ради форматирования даты, а сборщик тащил за собой парсеры таймзон, работу с относительным временем и переводы на сотню языков.
В Day.js архитектура построена иначе. В ядре лежат базовый парсинг, валидация, простые манипуляции и форматирование по стандартным маскам. Весь остальной функционал разбит на независимые плагины. Если вам нужен расчет кварталов года или сложная кастомная маска, вы импортируете отдельный модуль.
Локали работают по такому же принципу. Никакой испанский или китайский язык не попадет в итоговый бандл, пока вы явно не вызовете импорт нужного файла.
import dayjs from 'dayjs'
import 'dayjs/locale/ru'
dayjs.locale('ru')
Иммутабельность без сюрпризов
Если вы работали со старым Moment, то наверняка наступали на грабли с мутациями. Достаточно было передать объект даты во вспомогательную функцию и вызвать там .add(1, 'day'), как исходная дата менялась во всем приложении. Отлаживать такие баги было сомнительным удовольствием.
Day.js делает все объекты неизменяемыми. Любая операция манипуляции возвращает новый экземпляр, оставляя исходный нетронутым.
const today = dayjs('2024-01-01')
const tomorrow = today.add(1, 'day')
console.log(today.format('YYYY-MM-DD')) // 2024-01-01
console.log(tomorrow.format('YYYY-MM-DD')) // 2024-01-02
Это поведение избавляет от лишних клонирований объекта перед каждым расчетом.
Знакомый API и цепочки вызовов
Переход на новые инструменты часто тормозится необходимостью переучивать команду. В случае с Day.js переучиваться не нужно. Почти любой метод выглядит в точности так, как в коде пятилетней давности.
Парсинг, смена значений и форматирование собираются в одну цепочку:
dayjs()
.startOf('month')
.add(7, 'day')
.set('hour', 12)
.format('YYYY-MM-DD HH:mm:ss')
Проверка условий тоже выглядит лаконично:
const deadline = dayjs('2024-12-31')
const isExpired = dayjs().isAfter(deadline)
Плагины для нестандартных задач
Минимализм ядра не означает бедность возможностей. Если базовая функциональность заканчивается, подключаются плагины. Делается это в пару строк через метод dayjs.extend().
Например, если проекту нужны редкие токены форматирования или порядковые числительные:
import dayjs from 'dayjs'
import advancedFormat from 'dayjs/plugin/advancedFormat'
dayjs.extend(advancedFormat)
dayjs().format('Q Do k kk X x')
Аналогично подключаются относительное время (формат «5 минут назад»), работа с UTC, определение разницы в днях с учетом рабочих часов и поддержка ISO-недель. Вы платите весом бандла только за то, чем реально пользуетесь в проекте.
Кому проект зайдет, а кому лучше пройти мимо
Day.js отлично вписывается в приложения, где важна скорость загрузки первой страницы. Для лендингов, мобильных интерфейсов, админок и клиентских дашбордов это один из лучших вариантов по соотношению возможностей к размеру.
Однако есть ситуации, когда стоит выбрать другие варианты:
- Если вы строите архитектуру с нуля на современных браузерах, обратите внимание на нативный объект
Intlили готовящийся Temporal API. Для простых задач форматирования сторонняя библиотека может вообще не понадобиться. - Если в проекте уже активно используется функциональный подход и lodash-style архитектура, возможно, удобнее будет взять
date-fns, где функции импортируются поштучно.
Для всех остальных случаев, особенно при миграции с кодовой базы на Moment.js, Day.js остается самым безболезненным и быстрым решением. Вы просто меняете имя импорта в пакетах и срезаете десятки килобайт бесполезного веса со своего бандла.
