# 使用 Source Map 提高开发效率
写在前面
注意:webpack 5 对 devtool 属性值更为严格,属性值名称规定了一定的顺序。
下面有些内容是基于 webpack 4.x 配置的,如果有关于 webpack 5 具体改动而出现的报错,需要我们自己查看官网文档去做对应的改动。
# 什么是 Source Map
打包编译后的代码与开发时候的代码有很大的差异,如果需要调试应用,或者应用出现错误,将很难定位错误。因为此时调试和报错都是基于转换过后的代码,Sourse Map (源代码地图)就是解决这种问题的。

很多第三方库都有 Source Map 文件。一般会以注释的方式引入 Source Map 文件,在最新版的 jQuery 里去除了 Source map 的注释,这里我们可以手动将 Source Map 引入进来。在加载到 jquery-3.4.1.min.js 文件的时候,控制台调试器会根据 Source Map 注释自动加载 Source map 文件,根据 Source Map 内容逆向解析出对应的源代码,以便于我们的代码调试。因为有了映射关系,出现错误就很容易定位源代码位置。

总结:Source Map 的作用就是解决了前端引入了自动构建方式所导致的源代码与运行代码不一致产生的问题。
# 配置 Source Map
webpack 提供了多种 Source Map 类型的配置。

打包后:

可以看到打包后的 bundle 文件自动添加了 Source Map 的注释。运行代码时,根据控制台错误信息就可以直接定位到源代码。

webpack 还支持多种 Source Map 模式。

# eval 模式的 Source map
eval 是 js 的一个函数,可以用来运行字符串中 js 代码。
eval('console.log(123)') // 123
在控制台中运行这段代码,默认会运行在虚拟机环境中。

我们可以通过 sourceURL 声明这段代码所属的文件路径。
eval('console.log(123) //# sourceURL=./foo/bar.js') // 123

这时候所声明的这段代码的运行环境就是 ./foo/bar.js,这就意味着我们可以通过 sourceURL 改变 eval 执行的这段代码的所属环境的名称,其实依然是运行在虚拟机环境,只不过是告诉了 js 引擎这段代码执行的路径名称,只是一个标识。下面将 devtool 属性设置为 "eval":

打包后:
根据控制台提示可以找到错误出现的文件,打开文件会发现这是打包转换过后的代码。因为这种模式下 webpack 会把所有打包的模块代码放到 eval 函数去执行,并且通过 eval 函数所传入字符串的最后用 sourceURL 方式去说明对应的文件路径。

eval 模式下不会生成 Source Map 文件,出现错误时可以根据 sourceURL 在控制台定位出错的文件,但仅仅只是定位到文件。因为 eval 模式不需要生成 Source Map 文件,所以构建速度是最快的。
# devtool 模式对比
不同的 devtool 模式有不同的差异,下面对这些不同的方式进行横向对比。

webpack.config.js 文件可以导出一个对象或数组。

运行打包命令后,会根据不同模式打包出不同的文件。

使用开发服务器把 dist 目录运行起来。
关于开发服务器可以使用 browser-sync 也可以使用 serve,这里使用 serve。
yarn add global serve
serve dist

- eval
- eval-source-map
- cheap-eval-source-map
- cheap-module-eval-source-map
- cheap-source-map
- inline-source-map
- hidden-source-map
- nosources-source-map
注意:webpack 5 对 devtool 属性值更为严格,属性值名称规定了一定的顺序。
由模式的命名特点可以总结:
eval -> 是否使用 eval 执行模块代码
cheap -> Source Map 是否只包含行信息
module -> 是否能够得到 Loader 处理之前的源代码
# 选择 Source Map 模式
理解不同模式的区别,选择适合的 Source Map。开发模式下使用 cheap-module-eval-source-map,生产模式下使用 none。
最新的 webpack 5 对 devtool 格式更严格,webpack 5 开发模式下的 devtool 模式使用 eval-cheap-module-source-map 最高效。