Performance: i18n Lazy Loading, Bundle-Größe halbiert

- i18n lädt EN/SR Übersetzungen nur bei Bedarf
- Hauptbundle von 356KB auf 179KB reduziert (~50%)
- Entfernt modulepreload für nicht-kritische Chunks
- Nur react-vendor und i18n-vendor werden vorgeladen

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-05 23:20:18 +01:00
co-authored by Claude Opus 4.5
parent ff92b58e83
commit db6d969874
2 changed files with 31 additions and 13 deletions
+22 -10
View File
@@ -3,9 +3,19 @@ import i18n from 'i18next';
import { initReactI18next } from 'react-i18next'; import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector'; import LanguageDetector from 'i18next-browser-languagedetector';
// Only load German synchronously (default language)
import translationDE from './locales/de'; import translationDE from './locales/de';
import translationEN from './locales/en';
import translationSR from './locales/sr'; // Lazy load other languages when needed
const loadLanguage = async (lng: string) => {
if (lng === 'en' && !i18n.hasResourceBundle('en', 'translation')) {
const { default: translationEN } = await import('./locales/en');
i18n.addResourceBundle('en', 'translation', translationEN, true, true);
} else if (lng === 'sr' && !i18n.hasResourceBundle('sr', 'translation')) {
const { default: translationSR } = await import('./locales/sr');
i18n.addResourceBundle('sr', 'translation', translationSR, true, true);
}
};
i18n i18n
.use(LanguageDetector) .use(LanguageDetector)
@@ -14,19 +24,21 @@ i18n
resources: { resources: {
de: { de: {
translation: translationDE translation: translationDE
},
en: {
translation: translationEN
},
sr: {
translation: translationSR
} }
}, },
fallbackLng: 'en', fallbackLng: 'de',
supportedLngs: ['en', 'de', 'sr'], supportedLngs: ['de', 'en', 'sr'],
interpolation: { interpolation: {
escapeValue: false escapeValue: false
} }
}); });
// Load language bundle when language changes
i18n.on('languageChanged', loadLanguage);
// Load initial language if not German
if (i18n.language && i18n.language !== 'de') {
loadLanguage(i18n.language);
}
export default i18n; export default i18n;
+9 -3
View File
@@ -5,18 +5,24 @@ import mdx from '@mdx-js/rollup';
import remarkFrontmatter from 'remark-frontmatter'; import remarkFrontmatter from 'remark-frontmatter';
import remarkMdxFrontmatter from 'remark-mdx-frontmatter'; import remarkMdxFrontmatter from 'remark-mdx-frontmatter';
// Plugin to make CSS non-blocking using the print media trick // Plugin to make CSS non-blocking and remove unnecessary preloads
function asyncCssPlugin(): Plugin { function asyncCssPlugin(): Plugin {
return { return {
name: 'async-css', name: 'async-css',
enforce: 'post', enforce: 'post',
transformIndexHtml(html) { transformIndexHtml(html) {
// Convert blocking CSS to async loading with print media trick // Convert blocking CSS to async loading
return html.replace( html = html.replace(
/<link rel="stylesheet" crossorigin href="(\/assets\/css\/[^"]+\.css)">/g, /<link rel="stylesheet" crossorigin href="(\/assets\/css\/[^"]+\.css)">/g,
`<link rel="preload" href="$1" as="style" onload="this.onload=null;this.rel='stylesheet'"> `<link rel="preload" href="$1" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="$1"></noscript>` <noscript><link rel="stylesheet" href="$1"></noscript>`
); );
// Remove modulepreload for non-critical chunks (animations, icons loaded later)
html = html.replace(/<link rel="modulepreload" crossorigin href="\/assets\/js\/animations[^"]*\.js">\n?/g, '');
html = html.replace(/<link rel="modulepreload" crossorigin href="\/assets\/js\/icons[^"]*\.js">\n?/g, '');
return html;
} }
}; };
} }