如何让SvelteKit仅加载所需语言文件而非7MB打包文件?
如何在SvelteKit中按需加载语言文件,避免打包全部7MB资源?
我用静态类实现网站本地化,原本希望只加载当前所需的语言文件,测试阶段一切正常,但到生产环境后,每个需要翻译的页面都会打包加载约7MB的语言文件——明明实际只用其中一个。网站有单独的语言切换页面,无需翻译,也不存在同一页面实时切换语言的场景。这些语言文件并非我创建,无法缩小体积,想问怎么配置SvelteKit、Rollup、Vite,让它只提供当前需要的语言文件?
原实现代码:
import cn from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_cn.csv'; import de from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_de.csv'; import en from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_en.csv'; import fr from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_fr.csv'; import id from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_id.csv'; import jp from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_JP.csv'; import kr from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_kor.csv'; import pt from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_pt.csv'; import ru from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_ru.csv'; import sp from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_sp.csv'; import tc from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_tc.csv'; import th from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_th.csv'; import vn from '../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_vn.csv'; const bindings = { cn: cn, de: de, en: en, fr: fr, id: id, jp: jp, kr: kr, pt: pt, ru: ru, sp: sp, tc: tc, th: th, vn: vn }; class Lang { // eslint-disable-next-line no-unused-vars static Get(str, remove_spaces = false, must_translate = false) { if (remove_spaces) { str = str.replace(/ /g, '_').toUpperCase(); } try { const entry = bindings[Cookies.get('lang')].find((entry) => entry.name === str); let composedregex = new RegExp('<[^>]*>', 'g'); return entry.value.replaceAll(composedregex, ''); } catch (e) { if (must_translate) { return null; } else { try { // Fallback to English const entry = en.find((entry) => entry.name === str); let composedregex = new RegExp('<[^>]*>', 'g'); const ret = entry.value.replaceAll(composedregex, ''); return ret; } catch (error) { // Total failure -> return original string return str; } } } } } export default Lang;
解决方案:动态导入+代码分割
你当前的问题根源是静态导入所有语言文件,导致Rollup/Vite编译时把所有文件打包进主代码块。改成动态导入后,构建工具会把每个语言文件拆成独立chunk,只有在需要时才加载。
步骤1:重构Lang类,替换静态导入为动态加载
删掉所有静态import,改成运行时根据当前语言动态加载文件:
import Cookies from 'js-cookie'; class Lang { static #currentLangData = null; static #fallbackLangData = null; // 初始化语言数据,页面加载时调用 static async init(lang = 'en') { // 统一处理文件名大小写问题(比如原代码里的JP.csv) const normalizedLang = lang.toLowerCase(); const langFileName = normalizedLang === 'jp' ? 'JP' : normalizedLang; try { // 动态加载当前语言文件 const langModule = await import(`../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_${langFileName}.csv`); this.#currentLangData = langModule.default; } catch (e) { console.warn(`Failed to load language ${lang}, falling back to English`); } // 预加载备用英文,避免回退时的加载延迟 if (!this.#fallbackLangData) { const fallbackModule = await import('../dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_en.csv'); this.#fallbackLangData = fallbackModule.default; } } static Get(str, remove_spaces = false, must_translate = false) { if (remove_spaces) { str = str.replace(/ /g, '_').toUpperCase(); } try { const entry = this.#currentLangData?.find((entry) => entry.name === str); if (!entry) throw new Error('Entry not found'); const composedregex = new RegExp('<[^>]*>', 'g'); return entry.value.replaceAll(composedregex, ''); } catch (e) { if (must_translate) { return null; } else { try { const entry = this.#fallbackLangData.find((entry) => entry.name === str); const composedregex = new RegExp('<[^>]*>', 'g'); return entry.value.replaceAll(composedregex, ''); } catch (error) { return str; } } } } } export default Lang;
步骤2:在SvelteKit加载流程中初始化语言
在根layout的load函数里获取当前语言(从Cookie或URL参数),提前完成语言文件加载:
// src/routes/+layout.ts import Lang from '$lib/Lang'; import Cookies from 'js-cookie'; export async function load() { const lang = Cookies.get('lang') || 'en'; await Lang.init(lang); return { lang }; }
步骤3:确保Vite正确分割语言文件
Vite默认会对动态导入做代码分割,无需额外配置,但要注意:
- 动态导入的路径必须是静态可分析的模板字符串(比如
cfg_lang_${lang}.csv),Vite会自动识别所有可能的语言文件,生成对应的独立chunk。 - 如果语言文件名有大小写不一致(比如
JP.csv和其他小写文件名),要在init函数里做兼容处理,避免加载失败。
可选优化:预加载高频语言
如果某些语言使用频率高,可以在根组件里添加预加载标签,减少首次加载延迟:
<!-- src/routes/+layout.svelte --> <script> import { page } from '$app/stores'; </script> {#if $page.data.lang} <link rel="preload" href={`/dumps/files/assets/gameres/dat/cfg/lang/cfg_lang_${$page.data.lang.toLowerCase()}.csv`} as="fetch" crossorigin> {/if}
内容的提问来源于stack exchange,提问作者xKeeg
相关产品推荐
相关产品推荐

