- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Webpack 实战系列一:正确使用 Sourcemap由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
Sourcemap 协议最初由 Google 设计并率先在 Closure Inspector 实现,它能够将经过压缩、混淆、合并的代码还原回未打包状态,帮助开发者在生产环境中精确定位问题发生的行列位置.
发展至今,Sourcemap 已广泛受 Webpack、Rollup、Babel、Less、Typescript、Chrome、Safari、VS Code 等工具支持.
参考:https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k 。
实现上,Sourcemap 由三部分组成
页面初始运行时只会加载编译构建产物,直到特定事件发生 —— 例如在 Chrome 打开 Devtool 面板时,才会根据 //# sourceMappingURL 内容自动加载 Map 文件,并按 Sourcemap 协议约定的映射规则将代码重构还原回原始形态,这既能保证终端用户的性能体验,又能帮助开发者快速还原现场,提升线上问题的定位与调试效率.
以 Webpack 为例,设置 devtool = 'source-map' 即可同时打包出代码产物 xxx.js 文件与同名 xxx.js.map 文件,Map 文件通常为 JSON 格式,内容如:
各字段含义分别为:
使用时,浏览器会按照 mappings 记录的数值关系,将产物代码映射回 sourcesContent 数组所记录的原始代码文件、行、列位置,这里面最复杂难懂的点就在于 mappings 字段的规则.
Sourcemap 最初版本生成的 .map 文件非常大,体积大概为编译产物的 10 倍;V2 引入 base64 编码等算法将之减少 20% ~ 30%;而最新版本 V3 又在 V2 基础上引入 VLQ 等算法,体积进一步压缩了 50%。这一系列进化造就了一个效率极高的 Sourcemap 体系,但伴随而来的则是较为复杂的 mappings 编码规则.
1.2.1 mappings 编码规则 。
举个例子,对于下面的代码:
当 devtool = 'source-map' 时,Webpack 生成的 mappings 字段为:
字段内容包含三层结构:
第三层逻辑为片段映射到源码的具体位置,以上例 IAAMA 为例:
上述第1、2层逻辑比较简单,唯一需要注意的是片段之间是一种相对偏移关系,例如对于上例第六行映射值:AAAA,IAAMA,IAAI,GAAG,QAAb,每一个片段的第一位 —— 即片段列数为 A,I,I,G,Q,分别代表:
这种相对偏移能减少 Sourcemap 产物的体积,提升整体性能.
而第三层的片段位置映射则用到了一种比较高效数值编码算法 —— VLQ(Variable-length Quantity).
1.2.2 VLQ编码 。
参考:https://en.wikipedia.org/wiki/Variable-lengsth_quantity 。
VLQ 本质上是一种将整数数值转换为 Base64 的编码算法,它先将任意大的整数转换为一系列六位字节码,再按 Base64 规则转换为一串可见字符。VLQ 使用六位比特存储一个编码分组,例如:
数字 7 经过 VLQ 编码后,结果为 001110,其中:
这样一个六位编码分组,就可以按照 Base64 的映射规则转换为 ABC 等可见字符,例如上述数字 7 编码结果 001110,等于十进制的 14,按 Base64 字码表可映射为字母 O.
但是,分组中只有中间的 4 个字节用于表示数值,因此单个分组只能表达 「-15 ~ 15」 之间的数值范围,对于超过这个范围的整数需要组合多个分组共同表达同一数字,组合规则:
例如对于十进制 -17,其二进制为 10001 (取 17 的二进制) 共5位,首先从后到前拆分为两组,后四位 0001 为第一组,连续标志位为 1,符号位为 1,结果为 1,0001,1;剩下的 1 分配到第二个 —— 也是最后一个分组,连续标志位为 0,结果为 0,00001。按 Base64 规则 [100011, 000001] 最终映射为 jA.
同样的,对于更大的数字,例如 1200,其二进制为 10010110000,分组为 [10, 01011, 0000],从后到前编码,第一个分组为 1,0000,0;第二个分组为 1,01011;最后一个分组为 0,00010。按 Base64 映射为 grC.
1.2.3 解码 mappings 。
结合 VLQ 编码知识,我们再回过来头来解读本章开头的例子,对于代码:
编译生成 mappings:
按行、片段规则分割后,得出如下片段:
以第 6 行 ['AAAA', 'IAAMA', 'IAAI', 'GAAG', 'QAAb'] 为例:
其它片段以此类推.
Webpack 提供了两种设置 Sourcemap 的方式,一是通过 devtool 配置项设置 Sourcemap 规则短语;二是直接使用 SourceMapDevToolPlugin 或 EvalSourceMapDevToolPlugin 插件深度定制 Sourcemap 的生成逻辑.
下面我们先展开介绍比较晦涩的 devtool 配置项,理解 Webpack 所提供的各种 Sourcemap 功能规则.
支持 25 种字符串枚举值,包括 eval、source-map、eval-source-map 等,分开来看都特别晦涩,但仔细观察可发现这些值都是由 inline、eval、source-map、nosources、hidden、cheap、module 七种关键词组合而成,这些关键词各自代表一项 Sourcemap 规则.
2.1.1 eval 。
当 devtool 值包含 eval 时,生成的模块代码会被包裹进一段 eval 函数中,且模块的 Sourcemap 信息通过 //# sourceURL 直接挂载在模块代码内。例如:
eval 模式编译速度通常比较快,但产物中直接包含了 Sourcemap 信息,因此只推荐在开发环境中使用.
2.1.2 source-map 。
当 devtool 包含 source-map 时,Webpack 才会生成 Sourcemap 内容。例如,对于 devtool = 'source-map',产物会额外生成 .map 文件,形如:
实际上,除 eval 之外的其它枚举值都包含该字段.
2.1.3 cheap 。
当 devtool 包含 cheap 时,生成的 Sourcemap 内容会抛弃「列」维度的信息,这就意味着浏览器只能映射到代码行维度。例如 devtool = 'cheap-source-map' 时,产物:
浏览器映射效果:
虽然 Sourcemap 提供的映射功能可精确定位到文件、行、列粒度,但有时在「行」级别已经足够帮助我们达到调试定位的目的,此时可选择使用 cheap 关键字,简化 Sourcemap 内容,减少 Sourcemap 文件体积.
2.1.4 modulemodule 。
关键字只在 cheap 场景下生效,例如 cheap-module-source-map、eval-cheap-module-source-map。当 devtool 包含 cheap 时,Webpack 根据 module 关键字判断按 loader 联调处理结果作为 source,还是按处理之前的代码作为 source。例如:
注意观察上例 sourcesContent 字段,左边 devtool 带 module 关键字,因此此处映射的是包含 class Person 的最原始代码;而右边生成的 sourcesContent 则是经过 babel-loader 编译处理的内容.
2.1.5 nosources 。
当 devtool 包含 nosources 时,生成的 Sourcemap 内容中不包含源码内容 —— 即 sourcesContent 字段。例如 devtool = 'nosources-source-map' 时,产物:
虽然没有带上源码,但 .map 产物中还带有文件名、 mappings 字段、变量名等信息,依然能够帮助开发者定位到代码对应的原始位置,配合 sentry 等工具提供的源码映射功能,可在异地还原诸如错误堆栈之类的信息.
2.1.6 inline 。
当 devtool 包含 inline 时,Webpack 会将 Sourcemap 内容编码为 Base64 DataURL,直接追加到产物文件中。例如对于 devtool = 'inline-source-map',产物:
inline 模式编译速度较慢,且产物体积非常大,只适合开发环境使用.
2.1.7 hidden 。
通常情况下,产物中必须携带 //# sourceMappingURL= 指令,浏览器才能正确找到 Sourcemap 文件, 。
当 devtool 包含 hidden 时,编译产物中不包含 //# sourceMappingURL= 指令。例如:
两者区别仅在于编译产物最后一行的 //# sourceMappingURL= 指令,当你需要 Sourcemap 功能,又不希望浏览器 Devtool 工具自动加载时,可使用此选项。你也可以通过以下操作手动打开 Sourcemap:
2.1.8 小结 。
总结一下,Webpack 的 devtool 值都是由以上七种关键字的一个或多个组成,虽然提供了 27 种候选项,但逻辑上都是由上述规则叠加而成,例如:
其它选项以此类推。最后再总结一下:
对于开发环境,适合使用:
对于生产环境,则适合使用:
上面介绍的 devtool 配置项本质上只是一种方便记忆、使用的规则缩写短语,Sourcemap 的底层处理逻辑实际由 SourceMapDevToolPlugin 与 EvalSourceMapDevToolPlugin 插件实现.
参考:https://webpack.js.org/plugins/source-map-dev-tool-plugin/ 。
在 devtool 基础上,插件还提供了更多更细粒度的配置项,用于满足更复杂的需求场景,包括:
使用方法与其它插件无异,如:
插件配置规则较简单,此处不赘述.
至此,有关 Sourcemap 的大部分内容就讲解完毕了,读者们需要了解 Sourcemap 是一种高效位置映射算法,它将产物到源码之间的位置关系表达为 mappings 分层设计与 VLQ 编码规则,再通过 Chrome、Safari、VS Code、Sentry 等工具异地还原为接近开发状态的源码形式.
在 Webpack 场景下,通常只需要选择适当的 devtool 短语即可满足大多数场景需求,特殊情况下也可以直接使用 SourceMapDevToolPlugin 做更深度的定制化.
原文链接:https://mp.weixin.qq.com/s/-y35QBSIx2jMvG5dNklcPQ 。
最后此篇关于Webpack 实战系列一:正确使用 Sourcemap的文章就讲到这里了,如果你想了解更多关于Webpack 实战系列一:正确使用 Sourcemap的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我在网上搜索但没有找到任何合适的文章解释如何使用 javascript 使用 WCF 服务,尤其是 WebScriptEndpoint。 任何人都可以对此给出任何指导吗? 谢谢 最佳答案 这是一篇关于
我正在编写一个将运行 Linux 命令的 C 程序,例如: cat/etc/passwd | grep 列表 |剪切-c 1-5 我没有任何结果 *这里 parent 等待第一个 child (chi
所以我正在尝试处理文件上传,然后将该文件作为二进制文件存储到数据库中。在我存储它之后,我尝试在给定的 URL 上提供文件。我似乎找不到适合这里的方法。我需要使用数据库,因为我使用 Google 应用引
我正在尝试制作一个宏,将下面的公式添加到单元格中,然后将其拖到整个列中并在 H 列中复制相同的公式 我想在 F 和 H 列中输入公式的数据 Range("F1").formula = "=IF(ISE
问题类似于this one ,但我想使用 OperatorPrecedenceParser 解析带有函数应用程序的表达式在 FParsec . 这是我的 AST: type Expression =
我想通过使用 sequelize 和 node.js 将这个查询更改为代码取决于在哪里 select COUNT(gender) as genderCount from customers where
我正在使用GNU bash,版本5.0.3(1)-发行版(x86_64-pc-linux-gnu),我想知道为什么简单的赋值语句会出现语法错误: #/bin/bash var1=/tmp
这里,为什么我的代码在 IE 中不起作用。我的代码适用于所有浏览器。没有问题。但是当我在 IE 上运行我的项目时,它发现错误。 而且我的 jquery 类和 insertadjacentHTMl 也不
我正在尝试更改标签的innerHTML。我无权访问该表单,因此无法编辑 HTML。标签具有的唯一标识符是“for”属性。 这是输入和标签的结构:
我有一个页面,我可以在其中返回用户帖子,可以使用一些 jquery 代码对这些帖子进行即时评论,在发布新评论后,我在帖子下插入新评论以及删除 按钮。问题是 Delete 按钮在新插入的元素上不起作用,
我有一个大约有 20 列的“管道分隔”文件。我只想使用 sha1sum 散列第一列,它是一个数字,如帐号,并按原样返回其余列。 使用 awk 或 sed 执行此操作的最佳方法是什么? Accounti
我需要将以下内容插入到我的表中...我的用户表有五列 id、用户名、密码、名称、条目。 (我还没有提交任何东西到条目中,我稍后会使用 php 来做)但由于某种原因我不断收到这个错误:#1054 - U
所以我试图有一个输入字段,我可以在其中输入任何字符,但然后将输入的值小写,删除任何非字母数字字符,留下“。”而不是空格。 例如,如果我输入: 地球的 70% 是水,-!*#$^^ & 30% 土地 输
我正在尝试做一些我认为非常简单的事情,但出于某种原因我没有得到想要的结果?我是 javascript 的新手,但对 java 有经验,所以我相信我没有使用某种正确的规则。 这是一个获取输入值、检查选择
我想使用 angularjs 从 mysql 数据库加载数据。 这就是应用程序的工作原理;用户登录,他们的用户名存储在 cookie 中。该用户名显示在主页上 我想获取这个值并通过 angularjs
我正在使用 autoLayout,我想在 UITableViewCell 上放置一个 UIlabel,它应该始终位于单元格的右侧和右侧的中心。 这就是我想要实现的目标 所以在这里你可以看到我正在谈论的
我需要与 MySql 等效的 elasticsearch 查询。我的 sql 查询: SELECT DISTINCT t.product_id AS id FROM tbl_sup_price t
我正在实现代码以使用 JSON。 func setup() { if let flickrURL = NSURL(string: "https://api.flickr.com/
我尝试使用for循环声明变量,然后测试cols和rols是否相同。如果是,它将运行递归函数。但是,我在 javascript 中执行 do 时遇到问题。有人可以帮忙吗? 现在,在比较 col.1 和
我举了一个我正在处理的问题的简短示例。 HTML代码: 1 2 3 CSS 代码: .BB a:hover{ color: #000; } .BB > li:after {
我是一名优秀的程序员,十分优秀!