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

动态导入读取错误文件路径问题排查及替代方案咨询

问题分析与解决方案

原因:模块缓存导致的读取错误

这肯定是Node.js的模块缓存机制搞的鬼。Node.js(包括ts-node这类工具)会缓存已经加载过的模块,当你后续再次导入相同模块标识符的文件时,直接返回缓存内容,不会重新读取磁盘文件。

你遇到的情况是:第一次导入./translations/nl/[file].ts后,模块被缓存;后续处理其他语言时,虽然打印的路径还是nl目录,但可能因为文件名完全相同导致模块标识符冲突,或是ts-node的编译缓存路径重叠,Node.js直接返回了之前生成的fr版本缓存内容。而readFileSync直接读取磁盘文件,不受模块缓存影响,所以能拿到正确的nl内容。

解决方案

1. 手动清除模块缓存

每次动态导入nl目录文件前,手动删除对应模块的缓存记录,强制Node.js重新读取文件。

示例代码:

import { resolve } from 'path';
import { fileURLToPath } from 'url';

// 生成模块绝对路径,避免相对路径解析歧义
const getModuleAbsolutePath = (fileName: string) => {
  return resolve(fileURLToPath(import.meta.url), `../translations/nl/${fileName}.ts`);
};

// 清除缓存并导入文件
async function loadNlTranslations(fileName: string) {
  const modulePath = getModuleAbsolutePath(fileName);
  // 删除CommonJS缓存(ts-node可能混用模块系统)
  delete require.cache[modulePath];
  // 用绝对URL导入,避免相对路径解析问题
  const moduleUrl = new URL(`file://${modulePath}`);
  const translations = await import(moduleUrl.href);
  return translations.default; // 假设你的导出是default
}

2. 用TypeScript编译器API解析文件(无需动态导入)

如果不想依赖动态导入,可以直接用TypeScript的编译器API读取并解析TS文件,提取导出的翻译对象,同时保留类型安全。

示例代码:

import * as ts from 'typescript';
import { readFileSync } from 'fs';
import { resolve } from 'path';

// 定义翻译类型,保持类型安全
type Translations = Record<string, string>;

function parseTranslationFile(filePath: string): Translations {
  const fullPath = resolve(filePath);
  const fileContent = readFileSync(fullPath, 'utf8');
  
  // 创建TS源文件对象
  const sourceFile = ts.createSourceFile(
    fullPath,
    fileContent,
    ts.ScriptTarget.ESNext,
    true
  );

  let translations: Translations = {};

  // 遍历AST找到导出的翻译变量(假设是export const translations = { ... })
  ts.forEachChild(sourceFile, (node) => {
    if (ts.isVariableStatement(node) && node.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword)) {
      const declaration = node.declarationList.declarations[0];
      if (declaration.name.getText() === 'translations' && ts.isObjectLiteralExpression(declaration.initializer)) {
        translations = parseObjectLiteral(declaration.initializer);
      }
    }
  });

  return translations;
}

// 辅助函数:解析TS对象字面量AST为JS对象
function parseObjectLiteral(node: ts.ObjectLiteralExpression): Translations {
  const result: Translations = {};
  node.properties.forEach((prop) => {
    if (ts.isPropertyAssignment(prop)) {
      const key = prop.name.getText().replace(/['"]/g, '');
      if (ts.isStringLiteral(prop.initializer)) {
        result[key] = prop.initializer.text;
      }
    }
  });
  return result;
}

// 使用示例
const nlTranslations = parseTranslationFile('./translations/nl/home.ts');

这个方案直接操作TS抽象语法树,完全避开模块缓存问题,同时通过类型定义保留类型安全,不用转JSON。

3. 临时规避方案(不推荐)

如果上面的方案暂时不好实现,可以尝试在每次处理不同语言前重启进程——但这会降低工具效率,仅适合临时测试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 07:37:06