webpack 和vite 如何使用Source Map

什么是Source Map?

通过构建编译,可以将开发环境的源代码转化为能在生产环境运行的代码,这使得 运行代码 完全不同于 源代码。由于调试和报错都是基于运行代码。如果需要调试应用,或运行应用时报出了错误,就无法定位

Source Map(源代码地图) 就是解决这类问题最好的办法。它用来映射 转换后的代码(compiled) 与 源代码(source) 之间的关系。转换后的代码,通过转换过程中生成的 Source Map 解析,就可以逆向得到源代码。

Source Map 文件

目前很多第三方的库在打包后都会生成一个.map后缀的Source Map文件,它是一个 json 格式的文件,主要包含以下属性:

  • version:表示当前文件所使用source map标准的版本
  • sources:记录转换之前源文件的名称。可能是多个文件合并转换成一个文件,所以它是数组形式
  • names:记录源代码中使用的成员名称。压缩代码时,会将开发阶段编写的有意义的变量名替换为简短的字符,从而去压缩整体代码的体积
  • mappings:记录转换后的代码当中的字符,与转换前所对应的映射关系。它是整个source map的核心属性,是一个 Base64 VLQ 编码的字符串

如下:

{
    "version": 3"sources": ["jquery.js"],
    "names": [...],
    "mappings": "Base64 VLQ编码字符串"
}

Webpack 使用 Source Map

在 Webpack 中,可以通过配置 `devtool` 属性来启用 Source Map。常见的配置包括:

module.exports = {
  // 其他配置...
  devtool: 'source-map', // 或 'inline-source-map', 'cheap-module-source-map' 等
};

参数说明如下:

  • `source-map`: 提供完整的 Source Map,适合生产环境。
  • `inline-source-map`: 将 Source Map 直接嵌入到生成的文件中,适合开发环境。
  • `cheap-module-source-map`: 提供更快的构建速度,适合开发调试。

Vite 使用 Source Map

在 Vite 中,Source Map 是默认启用的。你可以在 `vite.config.js` 中通过 `build.sourcemap` 属性进行配置:

import { defineConfig } from 'vite';
export default defineConfig({
  build: {
    sourcemap: true, // 开启 Source Map,默认为 false
  },
});

参数说明如下:

  • 设置为 `true`:在构建时生成 Source Map。
  • 设置为 `'inline'`:将 Source Map 直接嵌入到生成的文件中。

Source Map 文件使用

在转换后的文件中通过添加注释的方式引入source map文件。例如:

// jquery.min.js
// ...转换后的代码

//# sourceMappingURL=jquery.min.map

最后一行注释的作用,是告知浏览器的开发者工具该JavaScript文件对应的源代码映射文件(Source Map文件)的位置

引入后,如果在浏览器中打开开发者工具,开发者工具在加载到这个js文件时发现有这个注释,它就会自动去请求这个source map文件。然后根据这个文件的内容,逆向解析对应的源代码,以便于调试。(在开发者工具的sources面板就会多出一个解析后的源文件)

选中开发者工具 -> More tools -> Developer resources

从Developer resources中看到sourcemap文件已被加载,并在状态为success。

一般来讲,线上产物中会把 SourceMap 去除,除了为了加速构建过程,更重要的是避免有开发经验的人直接在浏览器中「阅读源码」。

除了直接去除,企业内也常常利用内部的存储能力,将构建好的 SourceMap 资源转存到其他地方,这样一来,构建产物中的 sourceMappingURL 将无法正确指向 SourceMap 的资源地址,从而实现与直接去除接近的效果

手动添加sourcemap

1. 浏览器控制台报错,报错信息如下所示:

点击第一行飘蓝的user-BQ5Z0b6n.js,跳转到Sources

可以看到,这个经过编译之后的代码,与源码不一致,这时需借助sourcemap进行定位

2. 在浏览器中打开构建之后代码文件,然后右键,就可以看到 add source map的选项

然后填上 soucemap 的路径就可以了。

3. 重新点击打印控制台第一行飘蓝的user.tsx,跳转到Sources,可以看到源码报错的地方。

优点:

  • map文件可存放在本地,适用于生产环境不允许有sourcemap的项目。 

例如生产环境的user-BQ5Z0b6n.js路径为www.test.com/js/user-BQ5Z0b6n.js,在add source map中填入本地资源文件地址http://localhost:4173/static/js/user-BQ5Z0b6n.js.map

缺点:

  • 浏览器刷新之后需手动重新添加.map文件;
  • 在实际项目中,因为路由懒加载等代码分割技术,会产生很多js文件,相应的也会产生多个map文件。在调试时需根据js文件名,手动找到对应的map文件并添加

私有静态服务托管 SourceMap

在线上加载到正确的 SourceMap 资源地址。

在构建时将 SourceMap 上传至某个私有的地址(如 CDN 或 OSS),然后利用 Webpack 插件将 sourceMappingURL 改为该私有地址。这样开发人员在打开 DevTools 时,Chrome 将根据 sourceMappingURL 直接加载实际的 SourceMap 地址,而外部用户则完全被隔离。原理展示如下:

需要说明的是,sourcemap 需指定为 hidden,其效果等同 Webpack 的 hidden-source-map,此时会构建出 SourceMap 但不会有 sourceMappingURL 的注释。

线上排查

1. 发现控制台中报异常,根据 Chrome 提供的堆栈定位到报错文件

2. 在代码编辑面板中,右键 - Reveal in sidebar,在文件树中定位到部署文件

3. 右键部署文件,点击 Copy link address,在控制台中查看资源的地址 

4. 确定构建产物对应的 SourceMap 资源地址

5. 在代码编辑面板,右键 - Add source map,添加 SourceMap 地址

6. 从已经映射到源码的堆栈信息再次进入,即可看到报错在源码中的位置

posted @ 2024-11-15 18:07  李小菜丶  阅读(2286)  评论(0)    收藏  举报