Webpack SourceMap快速定位错误位置

什么是Source Map

我们在使用webpack时,运行时的打包后的代码,然而打包后的代码是经过转换压缩了的,如果我们在开发过程中代码出现了错误,在浏览器中只能定位到打包后的代码中出现错误的地方,而无法定位到打包前代码的错误位置,这使得我们在查找错误点时相当的麻烦。

然而有了SourceMap,它可以对打包前后的文件进行映射。Source map就是一个信息文件,里面储存着位置信息。也就是说,转换后的代码的每一个位置,所对应的转换前的位置。有了这种映射关系后,出错时,可以在控制台直接显示源代码中出错的位置。

往期webpack系列文章推荐

如何使用webpack实现模块化打包(2020-04-21)

webpack的核心机制之loader的秘密(2020-04-24)

彻底剖析webpack的plugin插件机制(2020-04-28)

使用webpack-dev-server提高webpack开发效率(2020-05-08)

举例说明

其实SourceMap在我们的日常开发中基本上一直在使用,例如jQuery,打包后的VUE项目。

打开VUE项目打包后的文件,在js文件下可以看到有两个js文件以及两个相对应的以.map为后缀的文件。

Webpack SourceMap快速定位错误位置_第1张图片
在两个js文件的最后都有一行注释内容,他们以//# 开头,这一行的作用就是引入它所对应的map文件。

Chrome 浏览器中如果打开了开发人员工具,它就会自动请求这个文件,然后根据这个文件的内容逆向解析出来源代码,以便于调试。同时因为有了映射关系,所以代码中如果出现了错误,也就能自动定位找到源代码中的位置了。
我们来看看map文件中是什么

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Epxaswh-1589446751822)(Webpack SourceMap快速定位错误位置_第2张图片])
这是一个 JSON 格式的文件,里面记录的就是转换后和转换前代码之间的映射关系,主要存在以下几个属性:

version 是指定所使用的 Source Map 标准版本;
sources 中记录的是转换前的源文件名称,因为有可能出现多个文件打包转换为一个文件的情况,所以这里是一个数组;
names 是源代码中使用的一些成员名称,我们都知道一般压缩代码时会将我们开发阶段编写的有意义的变量名替换为一些简短的字符,这个属性中记录的就是原始的名称;
mappings 属性,这个属性最为关键,它是一个叫作 base64-VLQ 编码的字符串,里面记录的信息就是转换后代码中的字符与转换前代码中的字符之间的映射关系。

Webpack 中配置 Source Map

要想在webpack的生成Source Map也很简单,我们只需要进行简单的配置即可,有一个叫做devtool的属性。

//webpack.config.js
module.exports = {
  devtool: 'source-map' 
}

在该配置下进行打包,可以看到在dist文件下比之前多了一个map文件

Webpack SourceMap快速定位错误位置_第3张图片
打开bunder.js文件,在最后可以看到它使用了同样的注释方式引入了该map文件

Webpack SourceMap快速定位错误位置_第4张图片
现在我尝试模拟编写错误代码,输出一个未定义的变量 text

let dom = document.createElement('div')
dom.innerHTML = 'webpack'
document.body.append(dom)
console.log(text);

在控制台可以看到报错了

Webpack SourceMap快速定位错误位置_第5张图片
点击右上角的文件名,可以通过行号快速定位到源代码中的错误位置

Webpack SourceMap快速定位错误位置_第6张图片

如果关闭Source Map的话,点击去看到的将是打包后的代码
Webpack SourceMap快速定位错误位置_第7张图片

这里由于代码量比较少,所以还可以退出出错的地方,一旦代码量大了后,要想再定位到原码中的位置可不是件容易的事。
可能你以为到这里就完了,为了真正的满足各种场景,仅仅这样是完全不够的。
webpack为我们提供了多种 source map ,选择一种 source map 格式来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度。具体对比如下表:
Webpack SourceMap快速定位错误位置_第8张图片

没有哪种模式绝对的,只有更适合项目的,接下来我会对他们进行比较,从而了解他们之间的差异,来帮助我们判断何种场景下采用何种模式更佳。

如果要想比较的话,就必须对于每一种模式都要进行打包,有一种高效的方法。webpack的配置文件导出的还可以使一个数组,数组中每一个元素就是一个单独的打包配置,那这样就可以在一次打包过程中同时执行多个打包任务。

const HtmlWebpackPlugin = require('html-webpack-plugin')const allDevtoolModes = [
    'eval',
    'cheap-eval-source-map',
    'cheap-module-eval-source-map',
    'eval-source-map',
    'cheap-source-map',
    'cheap-module-source-map',
    'inline-cheap-source-map',
    'inline-cheap-module-source-map',
    'source-map',
    'inline-source-map',
    'hidden-source-map',
    'nosources-source-map',
]
​
module.exports = allDevtoolModes.map((item) => ({
    devtool: item,
    mode: 'none',
    entry: './src/index.js',
    output: {
        filename: `js/${item}.js`,
    },
    module: {
        rules: [{
            test: /\.js$/,
            use: {
                loader: 'babel-loader',
                options: {
                    presets: ['@babel/preset-env'],
                },
            },
        }, ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: `${item}.html`,
        }),
    ],
}))

执行打包后,在dist目录下会生产所有模式的打包结果

Webpack SourceMap快速定位错误位置_第9张图片

  • eval模式

    该模式下没有 Source Map 文件,所以只能定位是哪个文件出错。

  • eval-source-map模式

    该模式也是使用 eval 函数执行模块代码,不过这里有所不同的是,eval-source-map 模式除了定位文件,还可以定位具体的行列信息。相比于 eval 模式,它能够生成 Source Map 文件,可以反推出源代码

  • cheap-eval-source-map模式

    这种模式名字上多了一个cheap,可以理解为廉价的意思,它只能定位到出错的行,不能定位到具体的列,因此到构建速度上相对eval-source-map模式更快。

  • cheap-module-eval-source-map模式

该模式下定位的源代码与我们编写的源代码是一模一样的,而 cheap-eval-source-map 模式中定位的源代码是经过 ES6 转换后的结果。

  • inline-source-map 模式

    它跟普通的 source-map 效果相同,只不过这种模式下 Source Map 文件不是以物理文件存在,而是以 data URLs 的方式出现在代码中。我们前面遇到的 eval-source-map 也是这种 inline 的方式。

  • hidden-source-map 模式

    在这个模式下,我们在开发工具中看不到 Source Map 的效果,但是它也确实生成了 Source Map 文件,这就跟 jQuery 一样,虽然生成了 Source Map 文件,但是代码中并没有引用对应的 Source Map 文件,开发者可以自己选择使用。

  • nosources-source-map 模式

    在这个模式下,我们能看到错误出现的位置(包含行列位置),但是点进去却看不到源代码。这是为了保护源代码在生产环境中不暴露。

我的网站:www.dengzhanyong.com
关注我,共同进步,不错过我的每一篇推送
Webpack SourceMap快速定位错误位置_第10张图片

你可能感兴趣的:(webpack)