Задайте питання та отримайте підсумок документа, вказавши цю сторінку та обраного вами постачальника штучного інтелекту
Вміст цієї сторінки перекладено за допомогою штучного інтелекту.
Переглянути останню версію оригінального вмісту англійськоюЯкщо у вас є ідея щодо покращення цієї документації, будь ласка, долучіться, надіславши pull request на GitHub.
Посилання на документацію на GitHubСкопіювати документацію у форматі Markdown в буфер обміну
Vite i18n: аспекти, що стосуються саме Vite, а не вашого фреймворку
Більшість посібників із назвою "Vite i18n" — це насправді матеріали про React або Vue, які випадково використовують Vite як збирач. Ця стаття присвячена глибшому рівню: як саме імпортуються каталоги, що з ними робить Rollup і чому написане вами ліниве завантаження (lazy loading), швидше за все, насправді зовсім не ліниве.
Зміст
Статичний імпорт є типовим, і він завантажується миттєво
Найпростіша конфігурація імпортує кожен каталог угорі модуля:
Скопіюйте код у буфер обміну
Це призводить до того, що всі три каталоги опиняються в початковому вхідному чанку (entry chunk), на кожній сторінці, для кожного відвідувача. Це прийнятно для двох мов і кількох сотень рядків. Але коли мов стає десять, це перетворюється на найбільшу зайву статтю витрат у вашому бандлі.
import.meta.glob і прапорець, у якому помиляються майже всі
Glob-імпорт у Vite є стандартним рішенням:
Скопіюйте код у буфер обміну
Ліниве завантаження увімкнене за замовчуванням: кожен запис — це функція, яка повертає динамічний імпорт, а Rollup генерує окремий чанк для кожного файлу. Додавання { eager: true } навпаки вбудовує всі файли безпосередньо в модуль-імпортер, повністю перекреслюючи оптимізацію:
Скопіюйте код у буфер обміну
Пастка полягає в тому, що обидва варіанти чудово працюють у режимі розробки, оскільки Vite віддає окремі модулі без бандлінгу. Різниця виявляється лише в директорії dist. Перевірте це за допомогою npx vite build && npx vite preview і подивіться, що насправді містить ваш вхідний чанк.
Поділ за маршрутами рідко розділяє каталоги на практиці
Ця поведінка часто дивує розробників. Ви структуруєте каталоги за сторінками:
Скопіюйте код у буфер обміну
Потім два різних маршрути імпортують checkout.json, і Rollup виносить цей файл у спільний чанк (shared chunk), який завантажується на обох сторінках. Механізм чанкінгу Rollup керується графом залежностей модулів, а не назвами ваших папок: будь-який модуль, доступний із більш ніж однієї точки входу, стає спільним. Додавання третього маршруту нічого не змінить, а четвертий може взагалі несподівано перекроїти структуру чанків.
Тому поділ каталогів за маршрутами працює лише тоді, коли граф імпортів є суворо ізольованим. Якщо розмір бандла критичний, перевіряйте його за допомогою інструментів візуалізації:
Скопіюйте код у буфер обміну
Якщо вам конче необхідно зафіксувати межі чанків, опція build.rollupOptions.output.manualChunks є єдиним виходом, але ціною постійного ручного супроводу.
Каталоги не підтримують гаряче перезавантаження (HMR) автоматично
Змініть компонент — і Vite миттєво оновить його на екрані. Змініть locales/fr.json — і залежно від способу імпорту нічого не станеться. Динамічно імпортований JSON не має власної межі HMR, тому граф модулів не знає, як саме слід інвалідувати залежні компоненти.
Розробники зазвичай обходять це перезапуском dev-сервера щоразу, коли змінюють текст. Правильне вирішення проблеми лежить на боці плагіна i18n: він повинен перехоплювати HMR-оновлення та передавати нові повідомлення в працюючу програму. Обираючи бібліотеку, перевірте, чи вміє її плагін для Vite обробляти HMR для словників.
define намертво фіксує мову в зібраному коді
Виникає спокуса зафіксувати типову локаль під час компіляції:
Скопіюйте код у буфер обміну
Опція define виконує пряму текстову заміну на етапі збірки. Значення, зашите під час компіляції, стає остаточним, що змушує збирати окремий білд для кожної мови. Це робоча стратегія (саме так реалізована офіційна i18n в Angular), але це зовсім не те, що вам потрібно, якщо одне розгортання має обслуговувати всі мови одночасно.
Значення, які повинні змінюватися залежно від запиту користувача, не слід зашивати в define — їх треба розв'язувати під час виконання (runtime).
Перенесення парсингу повідомлень на етап збірки
Усі зрілі рішення в екосистемі зрештою приходять до одного висновку: припинити парсити повідомлення в браузері клієнта.
Відкрийте таблицю в модальному вікні, щоб чітко переглянути всі дані
| Плагін | Що переноситься на етап збірки |
|---|---|
@intlify/unplugin-vue-i18n | Компілює повідомлення vue-i18n у функції рендерингу (рантайм-бандл) |
| Lingui (макрос + плагін) | Витягує та компілює каталоги, замінює макроси на ідентифікатори |
| Paraglide (inlang) | Компілює кожне повідомлення в окрему tree-shakable функцію |
vite-intlayer | Будує словники компонентів, очищає (purge) та мініфікує невідоме |
Вигода подвійна: важкий компілятор повідомлень більше не потрапляє в клієнтський бандл, а невикористані фрази видаляються статично. Плата за це: і dev-сервер, і CI повинні запускати плагін, а для запуску простого tsc або тестів поза Vite знадобиться додаткова конфігурація.
SSR: ніколи не зберігайте локаль у стані модуля
Якщо ви використовуєте SSR (через фреймворк або vite-plugin-ssr), залізне правило звучить так: змінна на рівні модуля, що зберігає поточну локаль, є спільною для всіх паралельних запитів на цьому серверному процесі.
Скопіюйте код у буфер обміну
Двоє користувачів, які одночасно звертаються до сервера, потраплять у стан перегонів (race condition), і один із них побачить сторінку мовою іншого. Під час локальної розробки це непомітно, оскільки ви єдиний тестувальник. Завжди визначайте локаль для кожного запиту окремо і передавайте її явно через контекст або request-local сховище фреймворку.
Плагін Vite для Intlayer
Intlayer надає єдиний плагін, який бере на себе збірку словників, спостереження за файлами в режимі розробки та конвеєр оптимізації:
Скопіюйте код у буфер обміну
Перезапис імпортів, очищення (purge) і мініфікація увімкнені за замовчуванням. Головні параметри налаштовуються у файлі intlayer.config.ts:
Скопіюйте код у буфер обміну
Оскільки контент оголошується поряд із компонентами, а не в гігантських глобальних файлах мов, процес очищення опирається на реальний граф модулів, що робить видалення мертвого коду безпечним. Детальніше в документації з оптимізації бандлів.
Поширені помилки
{ eager: true }для glob, який мав завантажуватися ліниво. Працює локально, але тягне всі мови в продакшен.- Очікування, що структура папок автоматично сформує чанки. Rollup орієнтується на імпорти, а не на папки.
- Перезапуск dev-сервера для перегляду змін у тексті. Свідчення відсутності обробника HMR у плагіні.
- Вшивання локалі в
define. Прив'язує проєкт до окремої збірки на кожну мову. - Збереження стану локалі на рівні модуля в SSR. Призводить до змішування мов між паралельними запитами.
- Вимірювання продуктивності бандла на dev-сервері. Незібрані окремі модулі не відображають структуру продакшен-бандла.
Корисні матеріали
- Оптимізація бандла: purge, мініфікація та підсумковий вміст для браузера
- Звіти про продуктивність фреймворків
- Довідник конфігурації
- Налаштування Intlayer з Vite та React
- Адаптер сумісності з i18next
- React i18n: як працює модель провайдерів
- Vue i18n: як це працює та де криються підводні камені
- Компонентна i18n проти централізованої
Коментарі
Поки що немає коментарів. Будьте першим, хто поділиться своїми думками.
