You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Webpack构建时混淆导入的客户翻译文件名方案咨询

解决方案:Webpack构建时哈希化客户翻译文件路径

核心思路

通过构建阶段的脚本+Webpack自定义配置,实现:

  1. 仓库保留原客户命名的翻译文件(如en.ford.json)
  2. 构建时自动将客户ID转换为哈希,生成哈希命名的chunk
  3. 主包仅包含哈希路径映射,不暴露其他客户信息

步骤1:生成客户ID-哈希映射表

先写一个自动化脚本,遍历翻译文件目录,生成客户ID到哈希的映射(避免手动维护)。创建generate-customer-hashes.js:

const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

const translationsDir = path.resolve(__dirname, 'client_translations');
const hashMap = {};

fs.readdirSync(translationsDir).forEach(file => {
  if (!file.endsWith('.json')) return;
  const [language, customerId] = file.split('.').slice(0, 2);
  // 用SHA-1生成快速哈希(可替换为其他算法)
  const hash = crypto.createHash('sha1').update(customerId).digest('hex').slice(0, 16);
  
  if (!hashMap[language]) hashMap[language] = {};
  hashMap[language][customerId] = hash;
  // 反向映射供Webpack解析用
  hashMap[language][hash] = customerId;
});

fs.writeFileSync(
  path.resolve(__dirname, 'customer-hash-map.json'),
  JSON.stringify(hashMap, null, 2)
);

在package.json的scripts中添加构建前命令:

"scripts": {
  "prebuild": "node generate-customer-hashes.js",
  "build": "webpack --mode production"
}

步骤2:配置Webpack解析哈希路径

添加自定义解析插件,让Webpack将哈希路径(如en.80ca06ab.json)映射到原客户文件:

const path = require('path');
const webpack = require('webpack');
const customerHashMap = require('./customer-hash-map.json');

class TranslationHashResolver {
  apply(resolver) {
    resolver.hooks.resolve.tapAsync('TranslationHashResolver', (req, ctx, callback) => {
      const match = req.request.match(/^client_translations\/([a-z]{2})\.([0-9a-f]{16})\.json$/);
      if (!match) return callback();

      const [, language, hash] = match;
      const customerId = customerHashMap[language]?.[hash];
      if (!customerId) return callback();

      // 将哈希路径替换为原文件路径
      const newReq = {...req, request: `client_translations/${language}.${customerId}.json`};
      resolver.doResolve(resolver.hooks.resolve, newReq, `Resolved to original file`, ctx, callback);
    });
  }
}

module.exports = {
  // 基础配置省略...
  resolve: {
    plugins: [new TranslationHashResolver()]
  },
  output: {
    // 输出chunk用内容哈希命名,彻底隐藏客户信息
    chunkFilename: 'client_translation-[contenthash].js'
  },
  optimization: {
    // 用确定性哈希作为模块/Chunk ID,避免原文件名泄露
    moduleIds: 'deterministic',
    chunkIds: 'deterministic',
    // 将runtime单独打包,隔离模块映射逻辑
    runtimeChunk: 'single'
  }
};

步骤3:修改前端代码,从服务端获取当前客户哈希

禁止在前端打包所有客户的哈希映射,避免泄露客户列表。改为登录后从服务端获取当前客户的哈希值:

// 登录后调用服务端接口获取当前客户的哈希与语言
const fetchClientHash = async () => {
  const res = await fetch('/api/client-info');
  return res.json(); // 返回格式:{ hash: "80ca06abfa1a5104", language: "en" }
};

const getClientTranslations = async () => {
  try {
    const { hash, language } = await fetchClientHash();
    const translations = await import(
      /* webpackChunkName: "client_translation" */
      /* webpackMode: "lazy" */
      `client_translations/${language}.${hash}.json`
    );
    return translations.default ?? {};
  } catch (err) {
    console.error('加载客户翻译失败:', err);
    return {};
  }
};

步骤4:服务端维护映射表

服务端需要保存customer-hash-map.json中的映射关系,当用户登录后,根据customerId返回对应的哈希和语言,确保前端仅能获取自身的翻译路径。


内容的提问来源于stack exchange,提问作者spassvogel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 08:03:24