javascript - 为什么 JS 源映射通常以 token 粒度?

标签 javascript source-maps gulp-sourcemaps

JavaScript 的源映射似乎通常不比 token 粒度更精细。
例如,identity-map uses token granularity .

我知道我看过其他例子,但不记得在哪里。

为什么我们不使用基于 AST 节点的粒度呢?也就是说,如果我们的源 map 有所有 AST 节点的位置,并且只有 AST 节点的起点,那么不利的一面是什么?

在我的理解中,源映射用于崩溃堆栈解码和调试:永远不会有错误位置或有用的断点不在某个 AST 节点的开头,对吧?

更新 1

一些进一步的澄清:

  • 该问题与 AST 已知的情况有关。因此,“生成 AST 比生成 token 数组更昂贵”不会回答这个问题。
  • 这个问题的实际影响是,如果我们可以降低源映射的粒度,同时保留调试器和崩溃堆栈解码器的行为,那么源映射可能会小得多。主要优点是调试器的性能:开发工具可能需要很长时间来处理大型源文件,这让调试很痛苦。
  • 这是使用 source-map 在 token 级别添加源 map 位置的示例图书馆:

  • for (const token of tokens) {
        generator.addMapping({
          source: "source.js",
          original: token.location(),
          generated: generated.get(token).location(),
        });
    }
    

    这是在 AST 节点级别添加位置的示例:

    for (const node of nodes) {
        generator.addMapping({
          source: "source.js",
          original: node.location(),
          generated: generated.get(node).location(),
        });
    }
    

    更新 2

    Q1:为什么期望 AST 节点的启动次数少于代币的启动次数?

    A1:因为如果 AST 节点的开始数多于 token 的开始数,那么就会有一个以非 token 开始的 AST 节点。对于解析器的作者来说,这将是一个相当大的成就!为了具体说明,假设您有以下 JavaScript 语句:

    const a = function *() { return a + ++ b }
    

    以下是 token 开头的位置:

    const a = function *() { return a + ++ b } /*
    ^     ^   ^        ^^^ ^ ^      ^ ^ ^  ^ ^
    */
    

    这大概是大多数解析器所说的 AST 节点的开始位置。

    const a = function *() { return a + ++ b } /*
    ^     ^   ^              ^      ^   ^  ^
    */
    

    那是 减少 46% 在源 map 位置的数量中!

    Q2:为什么期望 AST-Node-granularity source maps 更小?

    A2:见上面的 A1

    Q3:你会使用什么格式来引用 AST 节点?

    A3:没有格式。见 中的示例代码更新 1 以上。我说的是为 AST 节点的开始添加源 map 位置。该过程几乎与为标记开头添加源 map 位置的过程完全相同,只是您要添加的位置更少。

    Q4:您如何断言所有处理源映射的工具都使用相同的 AST 表示?

    A4:假设我们控制整个管道并且在所有地方都使用相同的解析器。

    最佳答案

    TypeScript编译器实际上只在 AST 节点边界上发出源映射位置,但有一些异常(exception)是为了提高与某些工具的兼容性,这些工具期望映射到某些位置,因此基于 token 的映射实际上并不是很通用。在您给出的示例中,TS 的源图适用于如下位置:

    const a = function *() { return a + ++ b } /*
    ^     ^^  ^              ^      ^^  ^  ^^^
    */
    

    它们通常是每个标识符 AST 节点的开始和结束(否则加上开始)。

    映射标识符 AST 节点的开始和结束位置的基本原理非常简单 - 当您重命名标识符时,您希望重命名标识符上的选择范围能够映射回原始标识符,而不必依赖启发式。

    关于javascript - 为什么 JS 源映射通常以 token 粒度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57690105/

    相关文章:

    gulp - 如何创建 Gulp 任务以正确执行缩小和源映射到 .min 文件

    node.js - Uglify Minify 并使用 Gulp 生成 source map

    node.js - gulp-sourcemaps 将源指向错误的目录

    javascript - 是否有类似 youtube-dl 的东西,但在纯 jquery 或 js 中?

    javascript - 递归查找 JSON 值并返回对象

    css - Webpack:如何在css sourcemap中获取相对路径

    javascript - 捕获错误时 JavaScript 源映射是否有效?

    Typescript + gulp-sourcemaps 生成 map 但浏览器 DevTools 无法识别它

    javascript - MVC 中的 jQuery Accordion

    javascript - 如何用html测试