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

如何将JS运行时错误位置映射转换为原始TypeScript代码错误位置

问题描述

项目支持用户输入TypeScript代码,代码转译后在Web Worker中通过eval执行,当前流程运行正常。需求是代码运行出错时打印对应原始代码的错误提示,但目前只能获取转译后JS代码的错误行列位置,和原始TS代码的错误位置不匹配。
已尝试在转译阶段开启inline source maps生成配置,但无法解决位置映射问题。

原有转译实现代码:

import ts, { ScriptTarget } from "typescript";

const jsCode = ts.transpile(tsCode, { alwaysStrict: true, target: ScriptTarget.ES2020 }),
worker.sendMessage({ task: "execute", code: jsCode });

原有Worker侧错误捕获代码:

worker.addEventListener("error", (event: ErrorEvent) => {
    worker.postContextMessage(worker.currentTaskId!, {
        api: ScriptingApi.Result,
        contextId: worker.currentContext!,
        result: `${event.message} (${event.colno}:${event.lineno})`,
        isError: true,
        final: true,
    });

    event.preventDefault();
});
解决方案

inline source map不生效的核心原因有两个:

  • ts.transpile是简化封装接口,就算开启sourcemap配置,也仅会将sourcemap内容拼接在输出JS末尾,不会返回结构化的sourcemap数据
  • 通过eval执行的动态脚本没有关联的文件标识,Worker运行时默认不会解析这段代码附带的sourcemap,无法建立映射关系

推荐使用手动映射方案,兼容性最好,不依赖浏览器/运行时的sourcemap解析行为,步骤如下:

  • 替换转译接口,获取完整sourcemap
    弃用ts.transpile,改用ts.transpileModule接口转译代码,同时输出编译后JS和完整sourcemap:
    const transpileResult = ts.transpileModule(tsCode, {
      compilerOptions: {
        alwaysStrict: true,
        target: ScriptTarget.ES2020,
        sourceMap: true,
        inlineSources: true, // 将原始TS代码内容嵌入sourcemap,无需额外存储原始文件
      },
      fileName: "user-input.ts" // sourcemap生成需要原始文件标识,可自定义
    });
    
    const jsCode = transpileResult.outputText;
    const sourceMapContent = transpileResult.sourceMapText;
    
  • 初始化sourcemap查询器
    转译完成后,基于生成的sourcemap初始化位置查询实例,将实例和当前任务ID关联存储,方便错误捕获时取用:
    import { SourceMapConsumer } from "source-map";
    const consumer = await new SourceMapConsumer(JSON.parse(sourceMapContent));
    // 按自身业务逻辑存储consumer,和worker.currentTaskId绑定即可
    
  • 错误捕获时做位置转换
    修改原有错误捕获逻辑,拿到运行时返回的JS行列号后,通过sourcemap查询器转换为原始TS代码的位置。注意运行时返回的行列号是1-based计数,和sourcemap要求的格式存在固定偏移,可根据实际运行环境微调偏移量:
    worker.addEventListener("error", (event: ErrorEvent) => {
      const consumer = getConsumerByTaskId(worker.currentTaskId!);
      // 转换为原始TS位置
      const originalPosition = consumer.originalPositionFor({
        line: event.lineno,
        column: event.colno - 1
      });
    
      worker.postContextMessage(worker.currentTaskId!, {
          api: ScriptingApi.Result,
          contextId: worker.currentContext!,
          result: `${event.message} (${originalPosition.column}:${originalPosition.line})`,
          isError: true,
          final: true,
      });
    
      event.preventDefault();
    });
    

如果不想手动维护映射逻辑,也可以选择运行时自动映射方案:在转译后的JS代码末尾追加sourceURL和base64格式的sourceMappingURL注释,再送入eval执行,现代浏览器会自动完成位置映射。但该方案在部分旧版本浏览器、定制Web Worker环境下存在兼容问题,稳定性不如手动映射。
追加注释的示例代码:

const codeToEval = `${jsCode}
//# sourceURL=user-input.ts
//# sourceMappingURL=data:application/json;charset=utf-8;base64,${btoa(unescape(encodeURIComponent(sourceMapContent)))}
`
worker.sendMessage({ task: "execute", code: codeToEval });

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 14:24:21