Webpack конфигурация

Библиотека Globalize опирается на данные CLDR (Unicode Common Locale Data Repository), что делает её мощным инструментом интернационализации, но одновременно создаёт специфические требования к сборке. В отличие от лёгких i18n-решений, Globalize не работает без явной загрузки данных локалей, поэтому конфигурация Webpack становится частью архитектуры интернационализации приложения.

Ключевая особенность заключается в том, что Globalize не поставляет готовых локализованных пакетов «из коробки». Все данные (числа, даты, валюты, правила pluralization) подключаются вручную, что требует контроля над зависимостями на этапе сборки.


Структура зависимостей Globalize в модульной системе

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

Основные группы зависимостей:

  • core runtime: globalize, cldrjs
  • CLDR supplemental data
  • CLDR locale data
  • runtime modules Globalize: number, date, currency, message

Webpack должен учитывать, что ни один из модулей не является самодостаточным без данных CLDR.


Базовая установка пакетов

Типичная структура зависимостей:

npm install globalize cldrjs

Дополнительно часто требуются пакеты с данными CLDR:

npm install cldr-data

При этом важно понимать, что cldr-data — это не runtime-библиотека, а источник JSON-файлов для сборки.


Организация загрузки CLDR данных

Webpack не обрабатывает CLDR автоматически. Данные должны быть явно импортированы.

Типичная структура импорта:

import Globalize from "globalize";
import Cldr from "cldrjs";

// supplemental data
import likelySubtags from "cldr-data/supplemental/likelySubtags";
import numberingSystems from "cldr-data/supplemental/numberingSystems";
import currencyData from "cldr-data/supplemental/currencyData";
import timeData from "cldr-data/supplemental/timeData";

// locale data
import numbers from "cldr-data/main/ru/numbers";
import currencies from "cldr-data/main/ru/currencies";
import caGregorian from "cldr-data/main/ru/ca-gregorian";
import dateFields from "cldr-data/main/ru/dateFields";

После импорта данные необходимо загрузить в CLDR:

Cldr.load(
  likelySubtags,
  numberingSystems,
  currencyData,
  timeData,
  numbers,
  currencies,
  caGregorian,
  dateFields
);

Globalize.loadTimeZone();
Globalize.locale("ru");

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


Webpack-конфигурация для Globalize

Минимальная конфигурация Webpack учитывает необходимость корректной обработки JSON и ES-модулей.

const path = require("path");

module.exports = {
  mode: "production",
  entry: "./src/index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist")
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  },
  resolve: {
    extensions: [".js"]
  }
};

Дополнительная конфигурация обычно не требуется, так как CLDR поставляется в виде готовых JSON-модулей.


Разделение CLDR данных и кода приложения

Критическая проблема производительности возникает при включении всех локалей одновременно. CLDR содержит большой объём данных, и их бездумное подключение приводит к увеличению bundle size.

Практика разделения:

  • основной bundle — логика приложения и Globalize core
  • отдельные чанки — локали

Webpack позволяет реализовать это через dynamic imports:

async function loadLocale(locale) {
  switch (locale) {
    case "ru":
      await import("cldr-data/main/ru/numbers");
      await import("cldr-data/main/ru/currencies");
      await import("cldr-data/main/ru/ca-gregorian");
      break;

    case "en":
      await import("cldr-data/main/en/numbers");
      await import("cldr-data/main/en/currencies");
      await import("cldr-data/main/en/ca-gregorian");
      break;
  }
}

Такой подход позволяет Webpack автоматически создавать отдельные чанки для каждой локали.


Lazy-loading локалей через Webpack Code Splitting

Code splitting является основным механизмом оптимизации Globalize-интеграции.

Пример динамической загрузки:

import Globalize from "globalize";
import Cldr from "cldrjs";

async function initLocale(locale) {
  const [
    likelySubtags,
    numbers,
    currencies,
    gregorian
  ] = await Promise.all([
    import("cldr-data/supplemental/likelySubtags"),
    import(`cldr-data/main/${locale}/numbers`),
    import(`cldr-data/main/${locale}/currencies`),
    import(`cldr-data/main/${locale}/ca-gregorian`)
  ]);

  Cldr.load(likelySubtags.default, numbers.default, currencies.default, gregorian.default);
  Globalize.locale(locale);
}

Webpack интерпретирует такие конструкции как точки разбиения бандла.


Оптимизация размера бандла

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

Основные техники оптимизации:

1. Импорт только необходимых модулей Globalize

import number from "globalize/number";
import date from "globalize/date";

Вместо:

import Globalize from "globalize";

2. Tree shaking

Webpack 4+ способен удалять неиспользуемые части, но только при ESM-импортах:

optimization: {
  usedExports: true,
  sideEffects: false
}

3. Разделение vendor chunk

optimization: {
  splitChunks: {
    cacheGroups: {
      vendor: {
        test: /node_modules/,
        name: "vendors",
        chunks: "all"
      }
    }
  }
}

Обработка JSON CLDR в Webpack

CLDR данные — это JSON-файлы, и Webpack обрабатывает их через встроенный JSON loader.

В некоторых конфигурациях требуется явное указание:

module: {
  rules: [
    {
      test: /\.json$/,
      type: "json"
    }
  ]
}

Использование DefinePlugin для окружения локали

Webpack позволяет задавать глобальные параметры локали на этапе сборки:

const webpack = require("webpack");

module.exports = {
  plugins: [
    new webpack.DefinePlugin({
      DEFAULT_LOCALE: JSON.stringify("ru")
    })
  ]
};

Дальнейшая инициализация:

Globalize.locale(DEFAULT_LOCALE);

Работа с несколькими локалями в одном приложении

Поддержка нескольких языков требует изоляции данных CLDR.

Структура загрузки:

const locales = {
  ru: () => import("cldr-data/main/ru/ca-gregorian"),
  en: () => import("cldr-data/main/en/ca-gregorian"),
  de: () => import("cldr-data/main/de/ca-gregorian")
};

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


Влияние Webpack на производительность Globalize

Основные факторы производительности:

  • размер CLDR данных
  • количество локалей в initial bundle
  • стратегия lazy-loading
  • дублирование импортов Globalize модулей

Webpack не оптимизирует CLDR автоматически, поэтому архитектура загрузки определяет итоговую скорость приложения.


Частые ошибки конфигурации сборки

Типовые проблемы при интеграции:

  • подключение всех локалей одновременно в entry
  • отсутствие разделения supplemental данных
  • дублирование Cldr.load() в разных модулях
  • использование CommonJS вместо ES modules, что отключает tree-shaking
  • отсутствие code splitting для локалей

Каждая из этих ошибок приводит к увеличению bundle size и замедлению инициализации интернационализации.


Организация структуры проекта с Globalize и Webpack

Типичная структура:

src/
  i18n/
    cldr.js
    locales/
      ru.js
      en.js
  core/
    globalize.js
  index.js

Файл инициализации CLDR:

// i18n/cldr.js
import Cldr from "cldrjs";

export function setupCldr(data) {
  Cldr.load(...data);
}

Сборка production-версии

Production-сборка требует минимизации и строгого контроля зависимостей:

module.exports = {
  mode: "production",
  devtool: false,
  optimization: {
    minimize: true,
    usedExports: true,
    sideEffects: true,
    splitChunks: {
      chunks: "all"
    }
  }
};

Особое внимание уделяется тому, чтобы CLDR данные не попадали в несколько чанков одновременно.


Итоговая архитектурная модель интеграции

С точки зрения Webpack Globalize формирует трёхслойную модель:

  • ядро библиотеки (runtime API)
  • локальные модули Globalize (number/date/currency/message)
  • CLDR данные (динамически загружаемые JSON чанки)

Webpack выступает связующим слоем, обеспечивая разделение, ленивую загрузку и оптимизацию доставки локализационных данных без изменения логики самой библиотеки