如何从字符串中将Sourcemap与评估TypeScript一起使用

时间:2019-05-10 10:08:18

标签: javascript node.js typescript

我将首先显示代码(节点10.15.3):

var ts = require("typescript");
require('source-map-support').install({
   environment: 'node',
   hookRequire: true
})
var content = "let a = 0;\n\nb = b * a";

var compilerOptions = { 
   module: ts.ModuleKind.CommonJS,
   inlineSourceMap: true 
};

var res1 = ts.transpileModule(content, {
  compilerOptions: compilerOptions,
  moduleName: "myModule2"
});
console.log(res1);
console.log('-------')
console.log(content)
console.log('-------')
console.log(res1.outputText)
console.log('-------')
eval(res1.outputText)

作为执行此代码的结果,我希望具有与给定内容变量相关的回溯(第3行中的错误),但是我不断在第2行中收到错误-这是代码的编译版本中的错误行。

这是输出

{ outputText:
   'var a = 0;\nb = b * a;\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUVWLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBIn0=',
  diagnostics: [],
  sourceMapText: undefined }
-------
let a = 0;

b = b * a
-------
var a = 0;
b = b * a;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztBQUVWLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFBIn0=
-------
SS: /root/ts-eval/exal.js undefined
SS: internal/modules/cjs/loader.js undefined
SS: internal/bootstrap/node.js undefined
ReferenceError: b is not defined
    at eval (eval at <anonymous> (/root/ts-eval/exal.js:24:1), <anonymous>:2:1)
    at Object.<anonymous> (/root/ts-eval/exal.js:24:1)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)

1 个答案:

答案 0 :(得分:3)

您正在使用内联源映射,并且documentation处于source-map-support状态:

  

要支持带有内联源地图的文件,可以指定hookRequire选项,该选项将监视所有源文件中的内联源地图。

您已将hookRequire设置为true。但是,我引用的段落表明source-map-support依赖于钩接到require来检测内联源映射,因此,如果您的代码在未通过require的情况下执行,则其源映射将不会被检测到,source-map-support将无法修复堆栈跟踪。的确,如果我用以下代码替换您的eval呼叫:

fs.writeFileSync("myModule2.js", res1.outputText);

require("./myModule2");

我得到了这样的堆栈跟踪,并带有正确的行号:

ReferenceError: b is not defined
    at Object.<anonymous> (/tmp/t4/module.ts:3:1)
[...]

文件名为module.ts,因为尚未为fileName指定选项ts.transpileModule。您可以将其设置为myModule2.ts,以与moduleName保持一致。

此外,如果您更改编译器选项以也内联源代码,如下所示:

var compilerOptions = {
  module: ts.ModuleKind.CommonJS,
  inlineSourceMap: true,
  inlineSources: true,
};

您可以获得更好的堆栈跟踪。使用上面显示的compilerOptions和我之前建议的fileName,跟踪为:

/tmp/t4/myModule2.ts:3
b = b * a
^
ReferenceError: b is not defined
    at Object.<anonymous> (/tmp/t4/myModule2.ts:3:1)

您可以在ReferenceError之前看到引起问题的代码行的引用。


以上方法是导致source-map-support修复源引用的最简单方法。这是另一种更复杂的方法,不需要将任何文件保存到磁盘,但是需要自定义source-map-support从源文件路径获取源代码的方式。来源中的注释表明了新零件的作用。

const fs = require("fs");
const ts = require("typescript");
const vm = require("vm");
const path = require("path");

// This establishes a mapping between sourcePaths and the actual source.
const sourcePathToSource = Object.create(null);

require("source-map-support").install({
  environment: "node",
  // Pass to source-map-support a custom function for retreiving sources
  // from source paths. This runs after source-map-support's default logic,
  // only if that logic fails to find the requested source.
  retrieveFile: (sourcePath) => sourcePathToSource[sourcePath],
});


const content = "let a = 0;\n\nb = b * a";

const compilerOptions = {
  module: ts.ModuleKind.CommonJS,
  sourceMap: true,
  inlineSources: true,
};

// The path that the ts module would have.
const tsPath = path.resolve("myModule2.ts");

const res1 = ts.transpileModule(content, {
  compilerOptions: compilerOptions,
  fileName: tsPath,
  moduleName: "myModule2"
});
console.log(res1);
console.log("-------");
console.log(content);
console.log("-------");
console.log(res1.outputText);
console.log("-------");

// The path that the compiled module would have.
const jsPath = path.resolve("myModule2.js");

// Establish the relationship between the path and the source.
sourcePathToSource[jsPath] = res1.outputText;
// Ditto for the source map file.
sourcePathToSource[path.resolve("myModule2.js.map")] = res1.sourceMapText;

vm.runInThisContext(res1.outputText, {
  filename: jsPath,
});

运行上面的代码将得到以下输出:

/tmp/t4/myModule2.js:2
b = b * a;
^

ReferenceError: b is not defined
    at /tmp/t4/myModule2.ts:3:1
    at Script.runInThisContext (vm.js:123:20)
[...]

source-map-support修改了堆栈跟踪中的源行号,以使其指向正确的位置,但是一开始的源引用没有被修改。问题在于source-map-support使用的正则表达式。正则表达式要求将源文件引用括在括号中(例如(vm.js:123:20))。我尝试在source-map-support到达异常之前对其进行转换,以使其适合正则表达式,但source-map-support无法看到该转换。