一文彻底搞懂webpack devtool

article/2025/9/29 2:49:01

为什么需要Source Map

首先根据谷歌开发者文档的介绍,Source Map一般与下列类型的预处理器搭配使用:

  • 转译器(Babel)
  • 编译器(TypeScript)
  • Minifiers(UglifyJS)

为什么呢?因为通常我们运行在浏览器中的代码是经过处理的,处理后的代码可能与开发时代码相差很远,这就导致开发调试和线上排错变得困难。这时Source Map就登场了,有了它浏览器就可以从转换后的代码直接定位到转换前的代码。在webpack中,可以通过devtool选项来配置Source Map。

配置项

了解了为什么需要Source Map,我们来了了解下webpack能生成哪些类型的Source Map。

从webpack官网上了解到,devtool的值有20+种。

听起来很吓人,不过幸好它有固定的模式。

[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

通过关键词的组合,就可以生成用于各种场景的Source Map。

理解quality

在学习各种值之前,我们需要先来了解一下表格中的quality列。配置某个属性值,我们是为了达到某个目的,而quality就是目的之一。

那么它是什么呢?它描述了我们在调试时能看到的源码内容。

下面来看看它的取值以及含义

quality含义
bundled code模块未分离
generated code模块分离,未经loader处理的代码
transformed code模块分离,经loader处理过的代码
original source你自己所写的代码
without source content生成的Source Map中不包含sourcesContent
(lines only)包含行信息,不包含列信息

理解devtool

quality就决定了我们调试时能看到的源码内容,所以选取devtool的值时,需要根据项目实际情况配合quality来选择。而devtool有20+个可选值,我们需要进一步来理解其组成原则。

特别提醒:指定devtool时,要与mode配合使用。
复制代码

首先,上述模式中有三类关键词:

  • inline、hidden、eval
  • nosources
  • cheap[module]

俗话说,实践是检验真理的唯一标准学懂一样东西的最好方式,下面有一个🌰来实践一下。

这里是一个简单的demo,里面有连个文件,其中主文件main.js引入了一个a.js。为了更好的模拟实际场景,还使用了webpack中还使用了babel-loader来处理js文件。

具体如下图:

下面就来实操一波~

inline、hidden、eval

这几个模式是互斥的,描述的是Source Map的引入方式。

inline

Source Map内容通过base64放在js文件中引入。

hidden

代码中没有sourceMappingURL,浏览器不自动引入Source Map。

eval

生成代码和Source Map内容混淆在一起,通过eval输出。

nosources

使用这个关键字的Source Map不包含sourcesContent,调试时只能看到文件信息和行信息,无法看到源码。

cheap[module]

这个关键字用于指定调试信息的完整性

cheap

不包含列信息,并且源码是进过loader处理过的

这里可以看到,点击对应文件时,会跳转到对应文件,但是光标是在第一列(缺少列信息则只定位到第一列),并且箭头函数也被转换成了function。

cheap-module

不包含列信息,源码是开发时的代码

也是只能看到列信息,不过代码是原汁原味的开发时所写的代码。

Source Map是如何工作的

Source Map规范

根据Source Map v3规范,推荐的格式是:

{"version" : 3,"file": "out.js","sourceRoot": "","sources": ["foo.js", "bar.js"],"sourcesContent": [null, null],"names": ["src", "maps", "are", "fun"],"mappings": "A,AAAB;;ABCDE;"
}
复制代码

下面来解释一下每个属性代表的含义。

属性掘力值下限
versionSource Map文件版本
file该Source Map对应文件的名称
sourceRoot源文件根目录,这个值会加在每个源文件之前
sources源文件列表,用于mappings
sourcesContent源代码字符串列表,用于调试时展示源文件,列表每一项对应于sources
names源文件变量名和属性名,用于mappdings
mappings位置信息

浏览器与source-map

这里以chrome浏览器为例(其他浏览器应该也是类似的喔~)。

加载source-map

浏览器加载source-map是通过js文件中的sourceMappingRUL来加载的,而且sourceMapping支持两种形式:文件路径或base64格式。

加载source-map之后,在浏览器dev tool中的Sources tab就能看到对应的信息了。

这里重点讲解一下map文件中的sources字段和sourcesContent字段。

sources字段对应的是文件信息,会在浏览器的Sources中生成对应目录结构。之后再将sourcesContent中的内容对应填入上述生成的文件中。我们在调试时为啥能看到文件信息和源码内容,就是sources和sourcesContent共同作用的结果。

这里通过一个栗子来看看,我在sources中添加了一个文件hello.js,并且在sourcesContent中对应添加了内容hello~。下面是浏览器加载map文件后的结果。

mappdings详解

直接举个栗子🌰:

源码:input.js
i am handsome  
you are ugly
复制代码
转换后代码:output.js
i am handsome you are
ugly
复制代码

我们要如何记录这位置对应信息呢?这里可以参考这篇文章[1]。

位置信息必须包含的有:输出位置(Output location)、源文件(Input)、源码位置(Input location)、源码。

所以根据上面的栗子,我们可以得出如下表格。

Output locationInputInput locationCharacter
L1,C0index.jsL1, C0i
L1,C2index.jsL1, C2a
L1,C3index.jsL1, C3m
L1,C5index.jsL1, C5h
L1,C6index.jsL1, C6a
L1,C7index.jsL1, C7n
L1,C8index.jsL1, C8d
L1,C9index.jsL1, C9s
L1,C10index.jsL1, C10o
L1,C11index.jsL1, C11m
L1,C12index.jsL1, C12e
L1,C14index.jsL2, C0y
L1,C15index.jsL2, C1o
L1,C16index.jsL2, C2u
L1,C18index.jsL2, C4a
L1,C19index.jsL2, C5r
L1,C20index.jsL2, C6e
L2,C0index.jsL2, C8u
L2,C1index.jsL2, C9g
L2,C2index.jsL2, C10l
L2,C3index.jsL2, C11y

这个表格描述了每个字符的处理前后的对应位置信息,有了这个表格就可以做位置的映射了。

可以看到对于几个字符来说,需要存储的信息就已经很庞大了,所以这种记录方式还需要进行优化。

优化点如下:

  1. 可以把输入文件放入一个列表中,这样在位置信息中就可以使用列表索引来表示了。
  2. 对于源码,没有必要记录每个字符的对应信息,我们只需要记录变量、属性名就可以了(单词),可以使用一个列表来保存单词,位置信息只记录单词首个字符位置即可。
  3. 输出文件的行信息是相对重复的,所以可以使用;来分割每行输出代码,使用,来分割每个输出代码的位置信息。
  4. 源码的每个单词可以使用对于上一个单词的相对位置,这些位置信息(数字)可以更小些。

优化后如下表:

sources: [index.js]
names: [i, am, handsome, you, are, ugly]
复制代码
Output locationInput indexInput locationName index
L1,C00L1, C00
L1,C+2+0L1, C+2+1
L1,C+3+0L1, C+3+1
L1,C+9+0L2, C-5+1
L1,C+4+0L2, C+4+1
L2,C-18+0L2, C+4+1

此时位置信息可以记录成

mappings: "0|0|1|0|0,2|0|1|2|1,3|0|1|3|1,9|0|2|-5|1,4|0|2|4|1;-18|0|2|4|1"
备注:
1. 数字使用分隔符“|”分割
2. 0|0|1|0|0代表 -> 0(输出单词列), 0(输入文件sources索引),10(输入单词行列),0(单词names索引)
复制代码

使用VLQ进行优化

在上述mappings中,因为每一个位置不一定是一个数字的,所以必须使用|分隔符来分割数字。如果能省略分隔符,mappings的大小可以得到很大的优化。这时就需要引入VLQ(Variable Length Quantities)了。

VLQ的特点就是可以非常精简地表示很大的数值。其原理是使用6个二进制位来表示字符,其中最高位表示是否连续(0:不连续,1:连续),最低位表示是正还是负(0:正数,1:负数)。

举两个栗子🌰🌰:数字1与-23。

数字:1
二进制:1
VLQ编码:000010
Base64 VLQ: C
复制代码
数字:-23
绝对值:23
二进制:10111
VLQ编码:101111 000001
Base64 VLQ: vB
复制代码

这里拿-23来分解一下生成过程。

第一步:去23的二进制码 -> 10111
第二步:将10111分成两部分,第一部分是后四位,后面部分是五位为一部分 -> 1、0111 -> 00001、0111
第三步:按VLQ格式拼接 -> 101111 000001
其中,101111是 1【连续标识位】 + 0111 + 1【正负标识位】
000001是 0【连续标识位】+ 00001
第四步:对照Base64索引表(下表)
复制代码

最后来看一下上述mappings优化之后长啥样吧。

优化前:
mappings: "0|0|1|0|0,2|0|1|2|1,3|0|1|3|1,9|0|2|-5|1,4|0|2|4|1;-18|0|2|4|1"
优化后
mappings: "AACAA,EACEC,GACGC,SAELC,IAEIC,lBAEIC"
复制代码

项目中如何使用

通过上面的理论。我们对source-map以及webpack中devtool配置项已经有一些了解了,下面从实际出发,看看在项目不同环境中应该如何配置webpack。

webpack是如何推荐的

先直接来看看webpack官网的devtool[2]推荐:

Development

推荐使用:

  • eval
  • eval-source-map
  • eval-cheap-source-map
  • eval-cheap-module-source-map

在开发环境,我们比较在意的是开发体验,所以下面从源码级别、构建速度和列信息来对比。

devtool源码级别构建速度列信息
evalwebpack + loader处理后的代码+
eval-source-map源码+
eval-cheap-source-maploader处理后的代码-
eval-cheap-module-source-map源码-

Production

推荐使用:

  • none
  • source-map
  • hidden-source-map
  • nosources-source-map

在生产环境,我们比较在意的是安全性,所以下面从源码级别、安全性和列信息来对比。

devtool源码级别安全性列信息
none---
source-map源码浏览器会加载source-map,调试时会暴露源码+
hidden-source-map源码会生成map文件,但浏览器不会加载source-map。可以将map文件与错误上报工具结合使用+
nosources-source-map源码堆栈没有sourcesContent,调试只能看到模块信息和行信息,不能看到源码-

实际项目是如何配置

翻了一下项目组中的项目,开发环境使用的是eval-cheap-module-source-map,而生产环境这边多大数只需要知道报错的模块和行号就可以了,所以使用的是nosources-source-map


原文链接:https://juejin.cn/post/6844904201311485966


http://chatgpt.dhexx.cn/article/As51k4mF.shtml

相关文章

OpenBmc开发8:devtool简介与使用

1 简介 devtool是yocto中的一个工具,此命令行工具作为可扩展SDK(eSDK)的一部分,是基础组件。可以使用devtool来帮助构建,测试和打包eSDK中的软件。可以使用该工具有选择地将构建的内容集成到OpenEmbedded构建系统构建…

怎么在navicat(Navicat for MySQL)中运行SQL代码

1、首先在navicat中新建一个数据库(之前已经建好数据库,忽略本步) 2、点击上图中的“查询”命令 3、再点击“新建查询” 4、系统自动跳出如下图命令窗口 5、可以在命令行中敲代码或直接复制已有代码。如果代码是关于建表,执行成…

使用SQL语句创建数据表

写法一 create table student (sno char(10) primary key,sname varchar(20) not null,ssex char(2),sage smallint,sdept varchar(20),sid char(18) unique)写法二 create table student (sno char(10), sname varchar(20) not null, ssex char(2), sage smallint, sdept v…

SQL代码自动生成器

SQL代码自动生成器,效果图如下: 实现原理很简单: 通过数据库名,获取到数据表名,进而获取到数据字段。通过可视化的选择自定义的添加修改,一步一步完成SQL语句的编写。 其中对于常用的存储过程参数列表的书…

sql语句智能提示插件

1.下载安装 SqlPrompt10 及SQL.Prompt.Keygen注册码生成工具 链接: https://pan.baidu.com/s/1Oa3Ci6o2JjHZMjTXHdCkQg?pwdghew 提取码: ghew 2.修改hosts文件(如若跳过此步骤,虽然可以成功,但是重启电脑之后,又得重新操作&a…

sql server代码创建数据库详细过程

1.先打开sql server 2.点击新建查询 3.创建 数据库 主数据文件的大小为5MB,文件【按兆字节】的方式增长,一次增长2MB,最大容量20MB; 事务日志文件大小为4MB,文件【按百分比】的方式增长,一次增长25%&#…

vue实现codemirror代码编辑器中的SQL代码格式化功能

vue实现codemirror代码编辑器中的SQL代码格式化功能 1、首先使用npm安装sql-formatter插件 npm install --save sql-formatter2、然后引入该sql-formatter.js文件 import sqlFormatter from "sql-formatter";3、接下来就是针对需要格式化的代码调用该方法就OK啦 /…

SQL Server 代码颜色

今天初识SQL Server 随便敲了点代码、发现这代码真是五颜六色、既然有颜色就有寓意! 原来有这么多颜色、真是学习了! _____________________________chenchen

IDEA格式化SQL代码

IDEA格式化SQL代码 写在前面1.1、建立连接,数据库服务器地址,账号,密码等..1.2、基本操作,很多,增删改查,控制台SQl编写等等 写在前面 IntelliJ IDEA集成了很多我们开发中常用的工具,Linux连接…

SQL除法怎么用代码表示

SQL除法代码详解 前言一、除运算(关系代数)二、第一题:2.1导入数据到SQL Server:2.2理解:2.2.1代码:2.2.2↑代码理解和答案: 三、第二题:求使用了同“供应商S1所供应的全部零件”相同…

VUE实现SQL在线编辑器,SQL分析器,SQL代码关键字提示

1、首先使用npm安装CodeMirror插件,sql-formatter格式化插件 npm install --save codemirror npm install --save sql-formatter2、然后引入该文件 import codemirror/theme/ambiance.css import codemirror/lib/codemirror.css import codemirror/addon/hint/show-hint.cssc…

数据库SQL(基础代码)

启动、连接、断开和停止MySQL服务器 通过系统服务器和命令提示符(DOS)都可以启动、连接断开和停击MySQL,操作非常简单。 1.启动、停止MySQL服务器   启动、停止MySQL服务器,的方法有两种:系统服务器和命令提示符(DOS)。 (1)通过系统服务器启动、停止MySQL服务器   …

html640设计稿,移动设备分辨率(终于弄懂了为什么移动端设计稿总是640px和750px)...

在我开始写移动端页面至今,一直有2个疑问困扰着我,我只知道结果但不知道为什么 问题1:为什么设计师给的设计稿总是640px或750px(现在一般以Phone6为基准,给的750px) 问题2:为什么我们拿到640px和750px的设计稿&#xf…

1px像素问题

为什么会存在1px问题?怎么解决? - 掘金 作为前端,你应该了解的分辨率/逻辑像素/物理像素/retina屏知识🧐 - 掘金 解决移动端1px边框问题的几种方法 - AhuntSun - 博客园 1、分辨率 分辨率x像素(水平) * …

px和分辨率的关系总结

在相同的屏幕宽高下:如:15.6英寸(396.24毫米)的笔记本电脑: 每单位1920*xxx的分辨率1366*xxx的分辨率一毫米1920/396.244.8个px1366/396.243.4个px 高分辨率意味着大约每一毫米5像素点,像素点越多&#x…

uni-app之响应式单位upx和rpx

一、upx uni-app 使用 upx 作为默认尺寸单位, upx 是相对于基准宽度的单位,可以根据屏幕宽度进行自适应。 uni-app 规定屏幕基准宽度750upx。 开发者可以通过设计稿基准宽度计算页面元素 upx 值,设计稿 1px 与框架样式 1upx 转换公式如下&…

HTML5 实现本地图片裁剪

HTML5 实现本地图片裁剪 文章目录 HTML5 实现本地图片裁剪1.知识点1.HTML 结构与 CSS 样式2.初始化3 实现 handleFiles,获取文件,读取文件并生成 url4.实现 paintImage 方法5 实现 cutImage 方法6 编写 drag 方法7 保存截图8 js部分 代码 这次小的案例是…

css像素px,物理像素(pt),设备像素比(dpr),1px边框问题,viewport自适应

关于 css像素px,物理像素(pt),设备像素比(dpr),1px边框问题,viewport自适应等问题。 目录 **关于 css像素px,物理像素(pt),设备像素比…

html怎么设置页面最小像素,html px像素单位

html长度尺寸单位px像素 设置字体大小以像素单位 笼统设置装备摆设宽度width、高度height、border边框等花式数字单位px。 一、px引见 px是html长度单元像素。譬如咱们电脑、手机显示屏均使用因而像素为单元,也即是px为单位。透露表现屏区分率1200*800其实便是指120…

【CSS】物理像素 DP(device pixels)、物理像素比(DPR)、px 逻辑像素(CSS像素)、DPI、PPI 的概念解析 以及1px问题解决方法

物理像素 、物理像素比、物理像素比、px 逻辑像素概念解析 前言一、前提概念1.分辨率与物理尺寸关系目前绝大部分显示器都是基于点阵的同样的分辨率下,每个小点的尺寸仍然是可以大可以小的DPI(点每英寸)PPI(像素每英寸&#xff09…