Замена Date-fns 1.x на 2.x

Смена модели модулей: отказ от default export

Одним из самых критичных изменений стала полная переработка системы экспорта. В версии 1.x часто использовался импорт по умолчанию:

import dateFns from 'date-fns'
dateFns.addDays(new Date(), 1)

В 2.x такой подход удалён. Библиотека перешла к явным именованным импортам, что улучшило tree-shaking и уменьшило размер бандла.

import { addDays } from 'date-fns'

addDays(new Date(), 1)

Следствие перехода:

  • исчезает единый namespace-объект
  • импортируются только используемые функции
  • сборщики (Webpack, Rollup, Vite) эффективнее удаляют неиспользуемый код

Полный переход на ES Modules-структуру

В 2.x библиотека перестроена вокруг ES Modules, даже если проект использует CommonJS.

Было (1.x):

const format = require('date-fns/format')

Стало (2.x):

const { format } = require('date-fns')

или при ESM:

import { format } from 'date-fns'

Особенность:

  • глубокие импорты (date-fns/format) считаются нежелательными
  • рекомендуется централизованный импорт из корня пакета

Изменение подхода к локалям

Локализация стала строго модульной. В 1.x локали могли подтягиваться более «свободно», что приводило к избыточному бандлу.

В 2.x каждая локаль импортируется явно:

import { format } from 'date-fns'
import { ru } from 'date-fns/locale'

format(new Date(), 'PPP', { locale: ru })

Ключевые изменения:

  • локали больше не входят в сборку по умолчанию
  • требуется явный импорт каждой локали
  • улучшена предсказуемость размера бандла

Строгая типизация и поведение функций

Вторая версия усилила предсказуемость API и убрала ряд неявных преобразований.

1. Парсинг дат стал более строгим

Некорректные строки теперь чаще приводят к Invalid Date:

import { parse } from 'date-fns'

parse('2020-13-40', 'yyyy-MM-dd', new Date())
// Invalid Date

Ранее поведение могло быть менее детерминированным.


2. Уточнение сигнатур функций

Функции стали более строгими в отношении аргументов:

import { addDays } from 'date-fns'

addDays('2020-01-01', 1) 
// нежелательное поведение в v2

Ожидается передача Date-объекта:

addDays(new Date('2020-01-01'), 1)

Разделение функциональности и вынос дополнительных пакетов

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

Пример:

  • работа с часовыми поясами теперь вынесена в date-fns-tz
import { format } from 'date-fns'
import { utcToZonedTime } from 'date-fns-tz'

Изменения в форматировании дат

Функция format осталась ключевой, но стала более предсказуемой.

import { format } from 'date-fns'

format(new Date(2020, 0, 1), 'yyyy-MM-dd')

Особенности v2:

  • усилена стандартизация токенов
  • устранены неоднозначные форматы
  • более строгая интерпретация шаблонов

Изменение поведения FP-версии

FP (functional programming) стиль был переработан.

В 1.x:

import addDays from 'date-fns/fp/addDays'

В 2.x структура стала более консистентной, но требует аккуратного использования каррирования:

import { addDays } from 'date-fns/fp'

const addOneDay = addDays(1)
addOneDay(new Date())

Изменения:

  • унификация FP API
  • уменьшение дублирующих экспортов
  • более явная каррированная модель

Улучшения tree-shaking и влияние на сборку

Переход на 2.x значительно повлиял на оптимизацию бандлов.

Причины:

  • отказ от default export
  • строгая модульная структура
  • отсутствие глобального namespace
  • явные импорты функций

Пример эффекта:

import { format, addDays } from 'date-fns'

Включает только используемые модули, без лишних зависимостей.


Обновление API работы с датами

Разделение ответственности функций

Функции стали более атомарными:

  • каждая функция выполняет одну операцию
  • отсутствуют «комбинированные» скрытые поведения

Пример:

import { addMonths, subDays } from 'date-fns'

const date = addMonths(new Date(), 2)
const result = subDays(date, 10)

Ошибки миграции и типовые проблемы

1. Ошибка отсутствия default export

import dateFns from 'date-fns'

Решение:

import { format } from 'date-fns'

2. Неправильные импорты локалей

import ru from 'date-fns/locale/ru'

В v2:

import { ru } from 'date-fns/locale'

3. Передача строк вместо Date

addDays('2021-01-01', 5)

Исправление:

addDays(new Date('2021-01-01'), 5)

Изменения в совместимости с TypeScript

Вторая версия улучшила поддержку типов:

  • более строгие сигнатуры функций
  • точная типизация локалей
  • уменьшение any-зон

Пример:

import { format } from 'date-fns'

const result: string = format(new Date(), 'yyyy-MM-dd')

Обновлённый подход к сравнению дат

Функции сравнения стали более предсказуемыми:

import { isBefore } from 'date-fns'

isBefore(new Date(2020, 1, 1), new Date(2021, 1, 1))

Основной принцип:

  • входные данные должны быть валидными Date
  • отсутствует неявное приведение типов

Рекомендованная стратегия миграции кода

Структурный подход к переходу:

  1. Замена default import на named imports
  2. Проверка всех мест передачи строк вместо Date
  3. Обновление локалей на новый формат импорта
  4. Замена глубоких импортов на корневые
  5. Проверка FP-использования
  6. Подключение date-fns-tz при необходимости таймзон

Изменение философии библиотеки

Версия 2.x усилила несколько принципов:

  • предсказуемость поведения функций
  • явные зависимости вместо скрытых
  • минимизация размера итоговой сборки
  • модульность на уровне каждой функции
  • отказ от глобального API

Эта архитектура делает использование более строгим, но повышает стабильность поведения в крупных приложениях и сборках с оптимизацией.