[译]什么是SourceMap

标签: sourcemap | 发表时间:2023-04-10 17:55 | 作者:奇舞精选
出处:https://juejin.cn/frontend

原文链接: https://web.dev/source-maps/

使用 SourceMap 来提升 web 调试体验。

今天,我们要讨论的是 SourceMap,这是现代 Web 开发中至关重要的工具,它能够显著地简化调试工作。在本文中,我们将探讨 SourceMap 的基础知识,包括它们的生成方式以及它们如何改善调试体验。

SourceMap 的必要性

以前,我们使用纯 HTML、CSS 和 JavaScript 构建 Web 应用程序,并将相同的文件部署到 Web 上。

然而,随着现代 Web 应用程序日益复杂,你的开发工作流可能用到了各种工具。例如:

  • 模板语言和 HTML 预处理器:Pug、Nunjucks、Markdown。
  • CSS 预处理器:SCSS、LESS、PostCSS。
  • JavaScript 框架:Angular、React、Vue、Svelte。
  • JavaScript Meta 框架:Next.js、Nuxt、Astro。
  • 高级编程语言:TypeScript、Dart、CoffeeScript。

等等。

Development workflow

Development workflow

这些工具会将代码转换为标准的 HTML、JavaScript 和 CSS 后给浏览器运行。此外,为了优化性能,通常会对这些文件进行压缩(例如使用 Terser 进行 JavaScript 的压缩和混淆),并将它们合并在一起,减小它们的大小,使其在 Web 传输上更加高效。

例如,使用构建工具,我们可以将以下 TypeScript 文件转换为一行 JavaScript 并进行压缩。你可以在我的 GitHub 库( https://github.com/jecfish/parcel-demo)中尝试这个演示。

  /* A TypeScript demo: example.ts */

document.querySelector('button')?.addEventListener('click', () => {
  const num: number = Math.floor(Math.random() * 101);
  const greet: string = 'Hello';
  (document.querySelector('p') as HTMLParagraphElement).innerText = `${greet}, you are no. ${num}!`;
  console.log(num);
});

压缩后的版本如下:

  /* A compressed JavaScript version of the TypeScript demo: example.min.js  */

document.querySelector("button")?.addEventListener("click",(()=>{const e=Math.floor(101*Math.random());document.querySelector("p").innerText=`Hello, you are no. ${e}!`,console.log(e)}));

但是,这种优化可能会使调试工作更困难。将所有内容都放在一行中并使用更短的变量名的压缩代码可能会使问题更难定位。而 SourceMap 的用途,就是将编译后的代码映射回原始代码。

生成 SourceMap

SourceMap 是以 .map 结尾的文件,比如 example.min.js.mapstyles.css.map。它们可以被大多数构建工具生成,例如 Vite、webpack、Rollup、Parcel、esbuild 等等。

一些工具默认包含 SourceMap,而其他工具可能需要额外的配置来生成。

  /* Example configuration: vite.config.js */
/* https://vitejs.dev/config/ */

export default defineConfig({
  build: {
    sourcemap: true, // enable production source maps
  },
  css: {
    devSourcemap: true // enable CSS source maps during development
  }
})

理解 SourceMap

这些 SourceMap 文件包含有关编译代码如何映射到原始代码的重要信息,使开发人员可以轻松调试。以下是 SourceMap 的示例。

  {
  "mappings": "AAAAA,SAASC,cAAc,WAAWC, ...",
  "sources": ["src/script.ts"],
  "sourcesContent": ["document.querySelector('button')..."],
  "names": ["document","querySelector", ...],
  "version": 3,
  "file": "example.min.js.map"
}

要理解每个字段,可以阅读 SourceMap 规范或者这篇经典文章 《SourceMap 的剖析》

SourceMap 最重要的方面是 mappings 字段。它使用 Base64 VLQ 编码字符串将编译文件中的行和位置映射到相应的原始文件。这个映射可以使用 SourceMap 通过工具(例如 source-map-visualization 和 Source Map Visualization)可视化。

source-map-visualization

source-map-visualization

上图左边显示压缩后的内容,右边显示源代码。

可视化工具为原始列中的每一行和其在生成列中对应的代码着色。

mappings 部分显示了代码的解码映射。例如,条目 65->2:2 表示:

  • 生成的代码:单词 const 在压缩内容的位置 65 开始。
  • 源代码:单词 const 在原始内容中的第 2 行第 2 列开始。

source-map-visualization2

source-map-visualization2

通过这种方式,开发人员可以快速识别压缩后的代码与源代码之间的关系,使得调试过程更加顺畅。

浏览器开发者工具应用这些源映射,帮助你更快地定位调试问题,直接在浏览器中进行调试。

devtools

devtools

该图展示了浏览器开发者工具如何应用源映射,并显示文件之间的映射关系。

SourceMap 扩展

SourceMap 也支持扩展。扩展是以 x_ 命名约定开头的自定义字段。例如由 Chrome DevTools 提出的 x_google_ignoreList 扩展字段。请查看 x_google_ignoreList(https://developer.chrome.com/articles/x-google-ignore-list/) 来了解这些扩展如何帮助你专注于代码。

不够完美

在我们的例子中,变量 greet 在构建过程中被优化掉了。该值直接嵌入到最终的字符串输出中。

source-map-visualization3

source-map-visualization3

在这种情况下调试代码时,开发者工具可能无法推断并显示实际值。它不仅是浏览器开发者工具的挑战,也使得代码调试和分析变得更加困难。

当然,这是可以解决的问题。一种方法是在源映射中包含作用域信息,就像其他编程语言使用它们的调试信息一样。

总之,改进源映射规范和实现仍需共同努力。目前已经有一场活跃的关于如何通过源映射来提高调试能力的讨论(https://github.com/source-map/source-map-rfc/issues/12)。

我们期待着改进 SourceMap,让调试变得更加轻松! - END -

关于奇舞团

奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

相关 [sourcemap] 推荐:

[译]什么是SourceMap

- - 掘金 前端
原文链接: https://web.dev/source-maps/. 使用 SourceMap 来提升 web 调试体验. 今天,我们要讨论的是 SourceMap,这是现代 Web 开发中至关重要的工具,它能够显著地简化调试工作. 在本文中,我们将探讨 SourceMap 的基础知识,包括它们的生成方式以及它们如何改善调试体验.