如何配置Vite为XHR加载的静态资源添加哈希并获取文件名?
解决Vite中静态JSON文件的哈希缓存与XHR请求问题
针对你遇到的静态文件哈希与XHR加载的矛盾,这里提供三种可行方案,按推荐优先级排序:
方案一:用import.meta.glob让Vite自动追踪处理文件
这是最贴合Vite原生机制的方案,无需额外配置或插件:
- 保持
src/assets/locales/目录结构不变 - 在代码中通过
import.meta.glob批量导入语言文件,同时获取带哈希的文件URL:
// src/utils/locale-loader.js // 批量导入文件内容(按需加载可去掉eager: true) const localeContentMap = import.meta.glob('../assets/locales/*.json', { eager: true, import: 'default' }); // 批量获取带哈希的文件URL(用于XHR动态加载) const localeUrlMap = import.meta.glob('../assets/locales/*.json', { eager: true, as: 'url' }); // 封装加载函数 export function loadLocale(lang) { // 直接获取已加载的内容(适合预加载场景) return localeContentMap[`../assets/locales/${lang}.json`]; // 如果需要懒加载,用带哈希的URL发起XHR请求 // return fetch(localeUrlMap[`../assets/locales/${lang}.json`]) // .then(res => res.json()); }
- 在业务代码中直接调用
loadLocale('en')即可,Vite会自动将这些JSON文件打包到dist/assets并添加哈希后缀,localeUrlMap中存储的就是处理后的完整URL。
方案二:通过Rollup配置手动包含文件并生成清单
适合需要完全控制文件输出路径或批量处理大量静态文件的场景:
- 修改
vite.config.js配置,让Rollup处理目标文件并生成资产清单:
// vite.config.js import { defineConfig } from 'vite'; import { writeFileSync } from 'fs'; import path from 'path'; export default defineConfig({ build: { // 开启资产清单生成 manifest: true, rollupOptions: { input: { // 手动指定要处理的语言文件 'locales/en': './src/assets/locales/en.json', 'locales/de': './src/assets/locales/de.json', 'locales/ru': './src/assets/locales/ru.json' }, output: { // 自定义哈希命名规则 assetFileNames: 'assets/[name]-[hash][extname]' } } }, plugins: [ { name: 'generate-locale-manifest', // 打包完成后生成语言文件映射清单 writeBundle() { const manifest = require('./dist/manifest.json'); const localeManifest = {}; Object.entries(manifest).forEach(([key, value]) => { if (key.startsWith('locales/')) { const lang = key.split('/')[1]; localeManifest[lang] = value.file; } }); writeFileSync( path.resolve(__dirname, 'dist/locales-manifest.json'), JSON.stringify(localeManifest, null, 2) ); } } ] });
- 前端代码中先加载映射清单,再发起XHR请求:
// 加载语言文件映射 fetch('/locales-manifest.json') .then(res => res.json()) .then(manifest => { const targetLang = 'en'; // 替换为当前语言 return fetch(`/${manifest[targetLang]}`).then(res => res.json()); }) .then(localeData => { // 使用语言数据 });
方案三:用静态复制插件自定义哈希处理
适合需要将文件复制到指定目录且保留原有结构的场景:
- 安装插件:
npm install vite-plugin-static-copy --save-dev - 配置
vite.config.js,自定义哈希生成与文件复制逻辑:
// vite.config.js import { defineConfig } from 'vite'; import { viteStaticCopy } from 'vite-plugin-static-copy'; import crypto from 'crypto'; import fs from 'fs'; import path from 'path'; // 生成文件哈希(可自定义长度) function generateFileHash(filePath) { const fileBuffer = fs.readFileSync(filePath); return crypto.createHash('md5').update(fileBuffer).digest('hex').slice(0, 8); } export default defineConfig({ plugins: [ viteStaticCopy({ targets: [ { src: 'src/assets/locales/*.json', dest: 'assets/locales', // 重命名文件时添加哈希 rename: (name, ext) => { const hash = generateFileHash(path.resolve(__dirname, 'src/assets/locales', `${name}${ext}`)); return `${name}-${hash}${ext}`; } } ] }), { name: 'generate-locale-map', writeBundle() { const localeDir = path.resolve(__dirname, 'src/assets/locales'); const localeFiles = fs.readdirSync(localeDir).filter(f => f.endsWith('.json')); const localeMap = {}; localeFiles.forEach(file => { const lang = file.replace('.json', ''); const hash = generateFileHash(path.join(localeDir, file)); localeMap[lang] = `assets/locales/${lang}-${hash}.json`; }); writeFileSync( path.resolve(__dirname, 'dist/locale-map.json'), JSON.stringify(localeMap, null, 2) ); } } ] });
- 前端通过加载
/locale-map.json获取带哈希的文件名,再发起XHR请求即可。
内容的提问来源于stack exchange,提问作者Dieter Pisarewski
相关产品推荐
相关产品推荐

