При использовании FormatJS в современных JavaScript-приложениях ключевую роль играет этап сборки. Основная задача сборщика — подготовить локализационные сообщения, оптимизировать их и обеспечить корректную загрузку в рантайме без избыточного веса бандла.
Webpack остаётся одним из наиболее распространённых инструментов для этой задачи благодаря развитой системе плагинов, loader’ов и поддержке сложных пайплайнов трансформации кода.
FormatJS в контексте сборки опирается на три ключевых этапа:
Исходный код обычно содержит декларативные сообщения:
import { defineMessages } from 'react-intl';
const messages = defineMessages({
title: {
id: 'app.title',
defaultMessage: 'Главная страница'
}
});
На этапе сборки эти сообщения извлекаются и преобразуются в JSON-файлы локализаций.
В связке с Webpack практически всегда используется Babel, поскольку FormatJS опирается на AST-анализ кода.
Основной инструмент — babel-plugin-formatjs, который
выполняет:
id у сообщенийdefaultMessageПример конфигурации Babel:
{
"plugins": [
["formatjs", {
"idInterpolationPattern": "[sha512:contenthash:base64:6]"
}]
]
}
Генерация стабильных id позволяет:
В связке с Webpack используется специализированный loader:
@formatjs/clibabel-loaderТипичная схема пайплайна:
source code → babel-loader → formatjs extraction → json bundles → i18n runtime
Базовая конфигурация Webpack включает:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
}
};
Локали обычно хранятся отдельно:
/locales
/en.json
/ru.json
/de.json
И подключаются через json-loader или встроенный JSON
import:
import ruMessages from './locales/ru.json';
FormatJS предоставляет CLI:
formatjs extract "src/**/*.js" --out-file messages.json
Важные параметры:
--format: формат вывода--id-interpolation-pattern: стратегия генерации ID--extract-from-format-message-call: поддержка
formatMessageПри использовании React структура приложения обычно включает
IntlProvider:
import { IntlProvider } from 'react-intl';
import ruMessages from './locales/ru.json';
<IntlProvider locale="ru" messages={ruMessages}>
<App />
</IntlProvider>
Webpack в этом случае отвечает за:
Одной из ключевых оптимизаций является разделение языков:
const loadLocaleData = (locale) => {
switch (locale) {
case 'ru':
return import('./locales/ru.json');
case 'en':
return import('./locales/en.json');
}
};
Webpack автоматически создаёт отдельные чанки для каждого языка.
Преимущества:
Webpack в production режиме выполняет tree shaking, но его эффективность зависит от структуры импортов FormatJS:
Правильный импорт:
import { FormattedMessage } from 'react-intl';
Нежелательный:
import * as ReactIntl from 'react-intl';
Последний вариант ухудшает оптимизацию, увеличивая итоговый бандл.
Для production-сборки применяются следующие техники:
Длинные defaultMessage могут быть удалены или сжаты:
Webpack-плагины могут удалять:
FormatJS использует ICU MessageFormat. Ошибки в синтаксисе могут быть выявлены на этапе сборки:
{ count, plural,
one {1 элемент}
other {# элементов}
}
Webpack pipeline часто дополняется валидаторами:
Хотя Webpack остаётся наиболее распространённым решением, FormatJS интегрируется и с другими сборщиками.
Vite использует ESBuild и Rollup внутри. Интеграция FormatJS обычно упрощается:
Особенность: более быстрый HMR при разработке.
Rollup часто используется для библиотек.
Особенности интеграции:
FormatJS в Rollup чаще применяется в библиотеках i18n-компонентов.
Parcel обеспечивает zero-config подход:
При серверном рендеринге (Node.js) Webpack используется для:
Типичная проблема — синхронизация локалей между сервером и клиентом.
Решение:
Webpack позволяет оптимизировать локализации через:
Пример:
ru.8f3a91c2.json
en.a91bd332.json
Причина:
Причина:
Причина:
При крупных проектах структура обычно разделяется:
Webpack конфигурация адаптируется через multiple entry points и module federation при необходимости.
В микрофронтендах Webpack Module Federation позволяет:
Основная сложность — синхронизация версий сообщений между независимыми бандлами.