likes
comments
collection
share

使用Source Maps来调试TypeScript

作者站长头像
站长
· 阅读数 17

当你运行TypeScript代码时,你实际上是在运行TypeScript编译器生成的JavaScript代码,大部分情况下,TypeScript编译器生成的JavaScript源码与原始的TypeScript源码并非十分相似,这将使调试变得更加困难。这时,可以通过使用Source Maps来调试TypeScript,来提高开发效率。

什么是 Source Maps。

Source Maps 是一种可以映射源代码与生成代码之间的关系的文件。它们将生成的文件中的位置和符号映射回原始的源代码中相应的位置和符号,这意味着,当我们在生成代码中设置断点时,实际上可以在源代码中调试。

先来看两个不使用Source Maps的例子 1,假设你已经创建了一个小脚本来添加一个按钮到一个HTML页面,每次点击它都会自增:

function addCounter(el: HTMLElement) {
    let clickCount = 0;
    const button = document.createElement('button');
    button.textContent = 'Click me';
    button.addEventListener('click', () => {
        clickCount++;
        button.textContent = `Click me ${clickCount}`;
    });
    el.appendChild(button);
}
addCounter(document.body);

如果你在浏览器中加载这个按钮并打开调试器,你会看到生成的JavaScript.这与原始的源代码非常吻合,所以调试并不困难。如下图

使用Source Maps来调试TypeScript

2,通过从numbersapi.com获取关于每个数字对应的描述来使这个页面增加数值描述:

function addCounter(el: HTMLElement) {
    let clickCount = 0;
    const triviaEl = document.createElement('p');
    const button = document.createElement('button');
    button.textContent = 'Click me';
    button.addEventListener('click', async () => {
        clickCount++;
        const response = await fetch(`http://numbersapi.com/${clickCount}`);
        const trivia = await response.text();
        triviaEl.textContent = trivia;
        button.textContent = `Click me ${clickCount}`;
    });
    el.appendChild(triviaEl);
    el.appendChild(button);
}

addCounter(document.body);

如果你现在打开浏览器的调试器,你会发现生成的源代码已经变得非常复杂了,这将加到调试的困难程度,如下图:

使用Source Maps来调试TypeScript

为了支持旧版浏览器中的async和await,TypeScript已经将事件处理程序重写为一个状态机。它的行为不变,但代码不在与原始的源代码那么接近了。

这就是Source Maps可以帮忙的地方。如果要让TypeScript生成Source Maps, 可以在你的tsconfig.json中设置sourceMap选项:

{
    "compilerOptions": {
        "sourceMap": true
    }
}

现在当你运行tsc时,它会为每个.ts文件生成两个输出文件,一个.js文件和一个.js.map文件。后者就是Source Map.

有了这个文件,一个新的index.ds文件就会出现在你浏览器的调试器中。你可以在其中设置断点和检查变量,就像下图一样:

使用Source Maps来调试TypeScript

注意index.ts在左边的文件列表中以斜体形式出现。这表明从Web页面是否包含它的意义上将,index.ts并不是一个“真正”的文件。相反,它是通过Source Map包含的。根据你的设置,index.js.map要么包含index.ts的引用(在这种情况浏览器通过网络加载它),要么包含它的内联副本(在这种情况下不需要请求)。

使用Source Maps有以下一些需要注意的地方:

  • 如果你正在使用一个Typescript的打包工具(bundler)或压缩工具(minifier),它可能会生成一个自己的SourceMap。为了获得最好的调试体验,你希望它能映射到原始的TypeScript源代码,而不是生成的JavaScript。如果你的打包工具已经内置了对TypeScript的支持,那么应该能正常工作。如果没有,你可能需要找到一些设置选项来使它读取Source Map输入。
  • 要注意你是否在生产环境也提供了Source Map。除非打开浏览器,否则浏览器不会加载Source Map,所以对终端用户来说没有性能影响。但如果Source Map中包含了你的原始的源代码的内联副本,那可能就会有你不打算公开的内容。

你也可以使用Source Maps来调试NodeJS程序。这通常是通过你的编辑器或将浏览器调试器链接到你的node进程来完成。具体详情可以查阅Node文档。

尽管类型检查器可以在你运行代码之前捕获许多错误,它仍然不能代替一个好的调试器。使用Source Maps可以获得良好的TypeScript调试体验。

要记住的事情

  • 不要调试生成的JavaScript。要在运行时使用Source Maps来调试你的TypeScript代码。
  • 确保你的Source Maps一直映射到你运行的代码里。
  • 根据你的设置,你的Source Maps可能包含你的原始代码的内联副本,除非你知道你在做什么,否则不要发布它们。