Webpack中Source Map配置深入解析

目录
  • 为什么需要Source Map
    • devtool选项
  • devtool为false和'eval'有啥区别
    • 准备工作
      • 1,创建项目 安装依赖
      • 2,添加文件
      • 3,写配置 webpack.config.js
      • 4,在package.json中添加
      • 5,执行 npm run build,打包文件生成到了dist文件夹中,至此,准备工作完毕。
    • 观察devtool为false时
      • 1, 在dist/main.js中
      • 2,在浏览器中,观察开发者工具中的Sources。
      • 小结
    • 观察devtool为'eval'时
      • 1, 在dist/main.js中
      • 2,在浏览器中
      • 小结
  • devtool为'source-map'和'eval-source-map'有啥区别
    • 观察devtool为'source-map'时
      • 1, 在dist/main.js中
      • 2,在浏览器中
      • 小结
    • 观察devtool为'eval-source-map'时
      • 1, 在dist/main.js中
      • 2,在浏览器中
      • 小结
  • devtool为'eval-cheap-source-map'和'eval-cheap-module-source-map'有啥区别
    • 观察devtool为'eval-cheap-source-map'时
      • 1, 在dist/main.js中
      • 2,在浏览器中
      • 3,eval-cheap-source-map的问题
    • 观察devtool为'eval-cheap-module-source-map'时
      • 小结
  • 开发模式下其他配置
    • inline-source-map,inline-cheap-source-map等inline开头的
    • eval-nosources-cheap-source-map 等有nosources关键字的
  • 生产环境的source map配置
    • (none)
    • source-map
    • hidden-source-map
  • 总结

为什么需要Source Map

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

devtool选项

当mode为development时,devtool默认为‘eval’,当mode为production时,devtool默认为false。

devtool为false和'eval'有啥区别

在回答这个问题之前,我们得做点准备工作。

准备工作

1,创建项目 安装依赖

// 1,创建项目 安装依赖
mkdir sourcemap-demo
cd sourcemap-demo
npm init -y
npm install webpack webpack-cli --save-dev
npm install html-webpack-plugin --save-dev

2,添加文件

// 添加index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>起步</title>
</head>
<body>
</body>
</html>
// 添加src/index.js
import a from './a';
console.log(`hello index`);
a();
// 添加src/a.js
export default function b() {
  console.log('hello a');
}

3,写配置 webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
  entry: './src/index.js',
  mode: 'development', // 注意:这地方要将mode设置为development。因为当mode为production时webpack会开启代码压缩,不利于我们观察现象。
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,
  },
  devtool: false, // 先配置为false
  plugins: [new HtmlWebpackPlugin()],
};

4,在package.json中添加

"scripts": {
    "build": "webpack"
  }

5,执行 npm run build,打包文件生成到了dist文件夹中,至此,准备工作完毕。

观察devtool为false时

我们要观察两个地方,一个是dist/main.js。一个在浏览器中的情况。

1, 在dist/main.js中

var __webpack_modules__ = ({
 "./src/a.js":
      ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
        __webpack_require__.r(__webpack_exports__);
        __webpack_require__.d(__webpack_exports__, {
          "default": () => (b)
        });
        function b() {
          console.log('hello a');
        }
  })
 ...
 var __webpack_exports__ = {};
  (() => {
    __webpack_require__.r(__webpack_exports__);
    var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/a.js");
    console.log(`hello index`);
    (0, _a__WEBPACK_IMPORTED_MODULE_0__["default"])();
  })();

内容分析:

  • __webpack_modules__对象对应着我们源码中的js文件, key是路径,value就是经过webpack转换过的模块。
  • 我们写的 console.log(hello index); 这类源码中的内容,基本没什么变化的被打包到dist/main.js中。

2,在浏览器中,观察开发者工具中的Sources。

内容分析:

  • 只能看到webpack打包后的代码.

小结

devtool为false,只能看到打包后的代码,不利于开发调试和线上排错。

观察devtool为'eval'时

重新编译后。

1, 在dist/main.js中

  var __webpack_modules__ = ({
    "./src/a.js":
      ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
        eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ b)\n/* harmony export */ });\nfunction b() {\n  console.log('hello a');\n}\n\n//# sourceURL=webpack://sourcemap/./src/a.js?");
      }),
    "./src/index.js":
      ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
        eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./a */ \"./src/a.js\");\n\n\nconsole.log(`hello index`);\n(0,_a__WEBPACK_IMPORTED_MODULE_0__[\"default\"])();\n\n//# sourceURL=webpack://sourcemap/./src/index.js?");
      })
  });

内容分析:

  • 模块中的内容被eval包裹。内容末尾有// # sourceURL=webpack://sourcemap/./src/index.js。浏览器会对eval后面的sourceURL特殊处理。下面看看怎么特殊处理的

2,在浏览器中

内容分析:

  • 所有sourceURL的内容会被翻译成上图中左侧下方sourcemap-demo节点的结构,点击某个节点,会看到其eval对应的代码。从中我们看到了console.log(hello index);。

小结

devtool为'eval',可以在浏览器开发者工具中看到模块结构,通常也就是我们源码的结构。也能看到被webpack转换过点代码,在一定程度上能帮助我们调试代码和排查问题了。

devtool为'source-map'和'eval-source-map'有啥区别

观察devtool为'source-map'时

现在将devtool设置成source-map,看看效果。

1, 在dist/main.js中

//# sourceMappingURL=main.js.map

内容分析:

  • 最下面多了一行注释代码sourceMappingURL指向main.js.map。同时dist文件夹下多了个main.js.map。
main.js.map文件

源码和打包后代码的映射文件,有了它,当线上出bug时,浏览器可以在控制台显示报错在源码中的行数和列数。

2,在浏览器中

内容分析:

  • 在浏览器中可以看到我们的源码了。

小结

  • devtool为'source-map',会生成映射文件,出bug时可以准确定位到问题在源码中的位置,便于开发调试和排查问题。
  • 它同样有缺点,一是source-map的生成比较耗时,二是在开发时,我们会用热更新,没有source-map的话只需替换被更改的模块就行了,但是有source-map时,就要重新生产整个打包文件的map文件,比较耗时。

那么有什么方式可以避免devtool为'source-map'的缺点吗,答案是'eval-source-map'

观察devtool为'eval-source-map'时

1, 在dist/main.js中

var __webpack_modules__ = ({
    "./src/a.js":
      ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
        eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"default\": () => (/* binding */ b)\n/* harmony export */ });\nfunction b() {\n  console.log('hello a');\n}//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvYS5qcy5qcyIsIm1hcHBpbmdzIjoiOzs7O0FBQWU7QUFDZjtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vc291cmNlbWFwLWRlbW8vLi9zcmMvYS5qcz82ZTFjIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGIoKSB7XG4gIGNvbnNvbGUubG9nKCdoZWxsbyBhJyk7XG59Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./src/a.js\n");
      }),
    "./src/index.js":
      ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
        eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _a__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./a */ \"./src/a.js\");\n\n\nconsole.log(`hello index`);\n(0,_a__WEBPACK_IMPORTED_MODULE_0__[\"default\"])();//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvaW5kZXguanMuanMiLCJtYXBwaW5ncyI6Ijs7QUFBb0I7O0FBRXBCO0FBQ0EsOENBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9zb3VyY2VtYXAtZGVtby8uL3NyYy9pbmRleC5qcz9iNjM1Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhIGZyb20gJy4vYSc7XG5cbmNvbnNvbGUubG9nKGBoZWxsbyBpbmRleGApO1xuYSgpOyJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./src/index.js\n");
      })
  });

内容分析:

  • 与devtool为'source-map'的区别是,不是在文件最底部多了一行//# sourceMappingURL=main.js.map,也没有生成map文件。而是每个模块直接跟随一个sourceMappingURL,其中是源码和打包后代码的映射信息。这样点好处时在webpack因为开发者的更改要进行热更新时,不必重新生成全局map文件,只需重新生成更改模块的map信息就好。

2,在浏览器中

内容分析:

  • 在浏览器中同样可以看到源码,相比于'source-map',热更新时编译时间更少。

小结

  • 这里总结下'eval'的好处,由于Mapping信息被拆分在了每个模块eval函数后面的sourceMappingURL中,热更新时不必全量生成map数据,从而拥有更快的编译速度。(官网管这叫rebuild速度快)

对于开发调试,eval-source-map模式就完美了吗,如果追求更快的编译速度而不求追求的出现bug时精准的行列信息,只提供bug所在行信息就行,应该用什么?答案是'eval-cheap-source-map'。

devtool为'eval-cheap-source-map'和'eval-cheap-module-source-map'有啥区别

eval-source-map可以在出现bug时准确的定位到出错代码在源码的行和列。但如果你不需要列映射,只需要知道bug所在的行,那可以考虑eval-cheap-source-map,它比eval-source-map开销小,编译的快。

观察devtool为'eval-cheap-source-map'时

1, 在dist/main.js中

这里不贴代码了,相比于eval-source-map,sourceMappingURL后的内容少很多。

2,在浏览器中

与eval-source-map相同,更多细节暂不研究。

3,eval-cheap-source-map的问题

我们增加js代码babal专义的环节,安装 babel

 npm install babel-loader @babel/core @babel/preset-env -D

添加代码

// src/b.js
export default class B {
  constructor() {
    this.str = 'hell b'
  }
  sayHello() {
    console.log(this.str)
  }
}
// index.js
import a from './a';
+ import B from './b';
console.log(`hello index`);
a();
+ const b = new B();
+ b.sayHello();

查看在浏览器中的表现

坏了,浏览器中展示点代码是经过loader编译后的代码,不是我们手写的代码了。

经实验,如果设置成eval-source-map,不会有这个问题,浏览器中仍然可以看到源码。

有没有什么设置,既可以没有列映射,又能在浏览器中看到源码的呢?答案是eval-cheap-module-source-map。

观察devtool为'eval-cheap-module-source-map'时

在这种情况下,源自 loader 的 source map 会得到更好的处理结果。既没有列映射,又能在浏览器中看到源码。

小结

在开发模式下,为方便我们的开发调试。

  • 如果你想要最全的源码,bug精准定位到哪行哪列,使用eval-source-map。
  • 如果只需要将错误定位到哪行,使用eval-cheap-module-source-map。

开发模式下其他配置

inline-source-map,inline-cheap-source-map等inline开头的

就是把map文件内容放打包js代码文件中。看起来没多大用处。

eval-nosources-cheap-source-map 等有nosources关键字的

源码信息不再map文件中,浏览器通常会尝试从 web 服务器或文件系统加载源代码。目前不了解其使用场景。

生产环境的source map配置

(none)

生产环境不配置等同于写了devtool: false。默认不生成 source map,这是个不错的选择。因为别人可以通过 source map看到我们的源码,影响安全。

source-map

在线上环境不必使用eval-*了,没有热更新的情况。也没必要使用cheap-*了,只要发布的时候编译一次,慢点就慢点。

显然使用source-map有个问题,会让用户看到源码。我们可以通过服务器配置,禁止普通用户访问 source map 文件。只让固定IP(开发者的电脑的IP)的用户可以访问到。

hidden-source-map

hidden-source-map - 与 source-map 相同,都会生成.map文件。但不会为 bundle 添加引用注释。

目前,各大监控平台均有针对错误监控的Source Map的解析功能。例如开源监控平台Sentry支持Webpack插件和自身的CLI工具上传map文件后进行解析。

使用hidden-source-map,当线上报错时,将错误堆栈跟踪信息上报给监控平台,监控平台结合map文件就可以告诉我们源码级别的错误信息了。

总结

通过这次配置研究,我们要学习到

  • eval配置的作用和原理。
  • source-map配置的作用和原理。
  • 开发环境和生产环境视情况选择devtool的值。

以上就是Webpack中Source Map配置深入解析的详细内容,更多关于Webpack Source Map配置的资料请关注我们其它相关文章!

(0)

相关推荐

  • Webpack devServer中的 proxy 实现跨域的解决

    Webpack dev server使用http-proxy解决跨域问题 文档资料 webpack关于webpack-dev-server开启proxy的官方介绍 Vue-cli proxyTable 解决开发环境的跨域问题--虽然这篇是写vue的,不过用在webpack-dev-server上也是一样的 http-proxy-middleware--webpack-dev-server的实现方法其实是对这个的封装 配置http-proxy 在webpack的配置文件(webpack.confi

  • webpack中的代理配置详解

    目录 作用: 使用场景一: 使用场景二 使用场景三 使用场景四: 使用场景五: 解决跨域原理 vue-cli中proxyTable配置接口地址代理示例 更多参数 作用: 1.解决开发环境跨域问题(不用再去配置nginx和host) 2.如果你有单独的后端开发服务器API,并希望在同域名下发送API请求,那么代理某些URL会很有用 下面介绍一下五种经常使用的场景 使用场景一: 请求到 /api/xxx 现在会被代理到请求 http://localhost:3000/api/xxx, 例如 /api

  • webpack5之output和devServer的publicPath区别示例详解

    目录 一. output的publicPath 二. devServer的publicPath 一. output的publicPath 我们知道output中的path的作用是打包后文件输出的目录:比如静态资源的js.css等输出,常见的会设置为dist.build文件夹等: output中还有一个publicPath属性,该属性是指定index.html文件打包引用的一个基本路径: 它的默认值是一个空字符串,所以我们打包后引入js文件时,路径是 bundle.js: 在开发中,我们也将其设置

  • webpack介绍使用配置教程详解

    目录 一.webpack介绍 1.由来 2.介绍 3.作用 4.拓展说明 5.webpack整体认知 二.webpack安装 1.安装node 2.安装cnpm 3.安装nrm的两种方法 4.安装webpack 三.webpack配置 0.搭建项目结构 1.初始化一个项目(会创建一个package.json文件) 2.在当前的项目中安装Webpack作为依赖包 3.当前项目结构 4.实现CSS打包 5.实现SCSS打包 6.实现Less打包 7.实现打包url资源(图片.gif.图标等)功能 8

  • vue cli3配置image-webpack-loader方式

    目录 vue cli3配置image-webpack-loader 使用image-webpack-loader压缩图片报错 vue cli3配置image-webpack-loader vue cli3配置image-webpack-loader对图片进行压缩优化 安装 npm install image-webpack-loader --save-dev 配置vue.config.js chainWebpack: config => {     config.plugins.delete('

  • webpack5之devServer的常用配置详解

    目录 前言 一. contentBase 二. hotOnly.hot.host配置 1. hotOnly.hot 2. host设置主机地址 三. port.open.compress 四. Proxy代理 五. historyApiFallback 前言 devServer是为开发过程中, 开启的一个本地服务,在此总结一些常用的配置.供大家学习,相互成长,相互进步! 一. contentBase devServer中contentBase对于我们直接访问打包后的资源其实并没有太大的作用,但如

  • Webpack中Source Map配置深入解析

    目录 为什么需要Source Map devtool选项 devtool为false和'eval'有啥区别 准备工作 1,创建项目 安装依赖 2,添加文件 3,写配置 webpack.config.js 4,在package.json中添加 5,执行 npm run build,打包文件生成到了dist文件夹中,至此,准备工作完毕. 观察devtool为false时 1, 在dist/main.js中 2,在浏览器中,观察开发者工具中的Sources. 小结 观察devtool为'eval'时

  • Spring如何利用@Value注解读取yml中的map配置

    目录 @Value注解读取yml中的map配置 下边是我在yml中的map写法 使用时候注解的写法 举个例子 spring注解@Value通过yml文件注入map yml文件 java代码注入 @Value注解读取yml中的map配置 网上查了好多资料,都是.properties文件中读取,而且又是几个人抄来抄去,找了半天功夫不负有心人,终于找到了详尽的用法介绍. 下边是我在yml中的map写法 test:   map: '{"test1":"12345",&quo

  • Pycharm中Python环境配置常见问题解析

    本文实例讲述了Pycharm中Python环境配置常见问题.分享给大家供大家参考,具体如下: 1.问题的发现 最近在用Pycharm下的命令行工具安装.运行jupyter notebook时kernal一直报错,报错最下面两行如下所示 import win32api ImportError: DLL load failed: 找不到指定的模块. 经过网络搜索发现是无法正确解析python的路径,可能是python解释器的路径可能冲突,后来我发现有"两个"python路径,一个是我之前安

  • Spring中Xml属性配置的解析全过程记录

    1 工程概述 1.1 pom文件 <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring.ver

  • 深入理解Webpack 中路径的配置

    前言 Webpack2 中有很多涉及路径参数配置,若不知其所以然,很容易混淆出错.本文尽可能的汇集了 Webpack2 中涉及路径的配置,力争深入浅出. context context 是 webpack 编译时的基础目录,入口起点(entry)会相对于此目录查找. 默认值为当前目录,webpack设置 context 默认值代码 可以本地下载: this.set("context", process.cwd()); process.cwd()即webpack运行所在的目录(等同pac

  • Yii框架中sphinx索引配置方法解析

    本文实例讲述了Yii框架中sphinx索引配置方法.分享给大家供大家参考,具体如下: 请先将var/test/documents.sql导入数据库,并配置好以下的MySQL用户密码数据库 #源定义 source mysql { type = mysql sql_host = localhost sql_user = root sql_pass = root sql_db = yii2 sql_port = 3306 sql_query_pre = SET NAMES utf8 sql_query

  • Webpack中使用环境变量的各种正确姿势

    目录 写在前边 业务代码使用环境变量 使用webpack.DefinePlugin插件在业务代码中注入环境变量 webpack.DefinePlugin引发的思考 definePlugin所谓的"环境变量"实现方式 JSON.stringify()处理环境变量 构建过程中使用环境变量 传统环境变量方法使用webpack构建过程环境变量. 总结 写在前边 你还在为Webpack中各种打包配置而烦恼吗? 今天我们来聊聊webpack中注入环境变量的各种姿势,或者你会觉得注入环境变量通过命令

  • Webpack source map实战分析详解

    目录 一.webpack基础 二.source-map 2.1 认识source-map 2.2 如何使用source-map 2.3 source-map文件分析 2.4 source-map常见值 2.5 source-map不常见值 2.6 source-map最佳实践 一.webpack基础 推荐我的另一篇文章:Webpack基础 二.source-map 2.1 认识source-map 代码通常运行在浏览器上时,是通过打包压缩的: 真实跑在浏览器上的代码,和我们编写的代码其实是有差异

  • Vue项目中配置pug解析支持

    Vue 的用法没有变化: <template lang="pug"> transition(name="sider") div.hello h3 {{msg}} p(:style="{color:'#000'}", :htmlData="msg") p label button(@click="clickMe") clickTest </template> 要注意的一点是: 标签后面

随机推荐