Webpack讲解:devTool中SourceMap模式详解


一:什么是SourceMap?

我们在项目进行打包后,会将开发中的多个文件代码打包到一个文件中,并且经过压缩,去掉多余的空格,且babel编译化后,最终会用于线上环境,那么这样处理后的代码和源代码会有很大的差别,当有bug的时候,我们只能定位到压缩处理后的代码位置,无法定位到开发环境中的代码,对于开发不好调式,因此sourceMap出现了,它就是为了解决不好调式代码问题的。官网devtool https://webpack.docschina.org/configuration/devtool/

我们首先看下项目中的目录结构如下:

### 目录结构如下:
demo1                                       # 工程名
|   |--- dist                               # 打包后生成的目录文件             
|   |--- node_modules                       # 所有的依赖包
|   |--- js                                 # 存放所有js文件
|   | |-- demo1.js  
|   | |-- main.js                           # js入口文件
|   |
|   |--- webpack.config.js                  # webpack配置文件
|   |--- index.html                         # html文件
|   |--- styles                             # 存放所有的css样式文件                              
|   |--- .gitignore  
|   |--- README.md
|   |--- package.json
|   |--- .babelrc                           # babel转码文件

main.js 代码如下:

import demo1Func from './demo1.js';

console.log('main.js');

demo1.js 代码如下:

export default function printMe() {
 console.log('11111111');
}

webpack.config.js 代码配置如下:

const path = require('path');
// 提取css的插件
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ClearWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
  entry: './js/main.js',
  output: {
    filename: 'bundle.js',
    // 将输出的文件都放在dist目录下
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/dist'
  },
  mode: 'development',
  module: {
    rules: [
      {
        // 使用正则去匹配要用该loader转换的css文件
        test: /\.css$/,
        loaders: ExtractTextPlugin.extract({
          // 转换 .css文件需要使用的Loader
          use: ['css-loader']
        })
      },
      {
        test: /\.(png|jpg)$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: '[name].[ext]'
        }
      },
      {
        test: /\.js$/,
        exclude: /(node_modules)/, // 排除文件
        loader: 'babel-loader'
      }
    ]
  },
  resolve: {
    // modules: ['plugin', 'js']
  },
  externals: {
    jquery: 'jQuery'
  },
  devtool: 'eval',
  devServer: {
    // contentBase: path.join(__dirname, "dist"),
    port: 8081,
    host: '0.0.0.0',
    headers: {
      'X-foo': '112233'
    },
    // hot: true,
    inline: true,
    open: true,
    overlay: true,
    stats: 'errors-only'
  },
  plugins: [
    // new ClearWebpackPlugin(['dist']),
    new ExtractTextPlugin({
      // 从js文件中提取出来的 .css文件的名称
      filename: `main.css`
    })
  ]
};

基本结构如上,现在我们可以来理解 webpack中的SourceMap的几种常见方式了。

二:理解webpack中的SourceMap的配置项

2.1. eval
eval 会将每一个module模块,执行eval,执行后不会生成sourcemap文件,仅仅是在每一个模块后,增加sourceURL来关联模块处理前后对应的关系。在webpack中配置devtool: 'eval', 如下打包后的代码:

(function(modules) { // webpackBootstrap
  "use strict";
  eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return printMe; });\n\nfunction printMe() {\n  console.log('11111111');\n}\n\n//# sourceURL=webpack:///./js/demo1.js?");

  /***/ "./js/main.js":
  /*!********************!*\
    !*** ./js/main.js ***!
    \********************/
  /*! no exports provided */
  /***/ 
  (function(module, __webpack_exports__, __webpack_require__) {
    "use strict";
    eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _demo1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./demo1.js */ \"./js/demo1.js\");\n\n\nconsole.log('main.js');\n\n//# sourceURL=webpack:///./js/main.js?");
  })
})

如上打包后的代码,每一个打包后的模块后面都增加了包含sourceURL的注释,sourceURL的值是压缩前存放的代码的位置,这样就通过sourceURL关联了压缩前后的代码。并没有为每一个模块生成相对应的sourcemap。

优点是:打包速度非常快,因为不需要生成sourcemap文件。
缺点是:由于会映射到转换后的代码,而不是映射到原始代码,所以不能正确的显示行数。

2.2 source-map

在webpack中配置加上 devtool: 'source-map' 配置完成后,source-map会为每一个打包后的模块生成独立的sourcemap文件,比如在package.json文件中 这样配置:

"scripts": {
  "build": "webpack --progress --colors --devtool source-map"
}

然后运行 npm run build 后,会在dist目录下生产map文件。我们继续打包后的代码如下:

(function(module, __webpack_exports__, __webpack_require__) {

  "use strict";
  __webpack_require__.r(__webpack_exports__);
  /* harmony import */ var _demo1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./demo1.js */ "./js/demo1.js");
  __webpack_require__(/*! ../styles/main.css */ "./styles/main.css");
  console.log('main.js');
/***/ }),

  /***/ "./styles/main.css":
  /*!*************************!*\
    !*** ./styles/main.css ***!
    \*************************/
  /*! no static exports found */
  /***/ (function(module, exports) {

  // removed by extract-text-webpack-plugin

  /***/ })

  /******/ });
  //# sourceMappingURL=bundle.js.map

如上打包后的代码最后面一句代码是 //# sourceMappingURL=bundle.js.map ,同时在dist目录下会针对每一个模块生成响应的 .map文件,
比如我们在dist目录中会生成 bundle.js.map文件,我们可以打开看下这个文件代码会如下:

{
  "version":3,
  "sources":[
    "webpack:///webpack/bootstrap","webpack:///./js/demo1.js",
    "webpack:///./js/main.js","webpack:///./styles/main.css"
  ],
  "names":["printMe","console","log","require"],
  "mappings":";AAAA;AACA;;AAEA;AACA...",
  "file":"bundle.js",
  "sourcesContent":[],
  "sourceRoot": ""
}

上面生成后的map文件是一个javascript对象,可以被解析器读取,它主要有以下几个属性:

version:e Map 的版本,目前为3.
sources: 转换前的文件,该项是一个数组,表示可能存在多个文件合并.
names: 转换前的所有变量名和属性名。
mappings: 记录位置信息的字符串。
sourcesContent: 转换前的文件内容列表,与sources列表依次对应。
sourceRoot: 转换前的文件所在的目录,如果与转换前的文件在同一个目录,该项为空。

chrome和firefox如何使用Source Map呢?

1. 开启开发者工具

使用快捷键 option + command + i; 或者在 菜单栏选择视图 -> 开发者 -> 开发者工具。

2. 打开设置

点击右上角的三个点的图标,选择Settings, 如下图所示:

Webpack讲解:devTool中SourceMap模式详解

 

3. 开启Source Map
在Sources中,选中 Enable Javascript source maps 如下图所示

Webpack讲解:devTool中SourceMap模式详解
 

开启完成后,我们在 package.json 配置如下代码:

scripts: {
  "dev": "webpack-dev-server --progress --colors --devtool source-map --hot --inline",
}

然后在main.js 代码中,添加如下代码:

require('../styles/main.css');
import demo1Func from './demo1.js';

console.log('main.js');
console.log(a)

如上a未定义,直接打印a,肯定会报错的。我们在命令行中 运行 npm run dev 后,打开页面会发现报错,报错如下:

Webpack讲解:devTool中SourceMap模式详解
 

然后我们点击 main.js:5 后,会进入main.js代码内,如下图:

Webpack讲解:devTool中SourceMap模式详解
 

2.3 inline(比如 inline-source-map)
该属性不会生成独立的 .map文件,而是将 .map文件以dataURL的形式插入。

如下代码:

/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _demo1_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./demo1.js */ "./js/demo1.js");
__webpack_require__(/*! ../styles/main.css */ "./styles/main.css");


console.log('main.js');
console.log(a);

/***/ }),

/***/ "./styles/main.css":
/*!*************************!*\
  !*** ./styles/main.css ***!
  \*************************/
/*! no static exports found */
/***/ (function(module, exports) {

// removed by extract-text-webpack-plugin

/***/ })

/******/ });
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2Vz.....

inline-source-map 使用缺点:它会使得bundle.js文件变得非常大,因为它需要把 sourceMappingURL 以dataurl的形式插入到bundle.js里面去。如下图所示:

Webpack讲解:devTool中SourceMap模式详解
 

2.4 cheap(如:cheap-source-map)

该属性在打包后同样会为每一个文件模块生成 .map文件,但是与source-map的区别在于cheap生成的 map文件会忽略原始代码中的列信息;
比如生成后的bundle.js.map中的mappings的代码如下:

"mappings":";AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AClFA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;

如上可以看到,它不会生成列的信息,有逗号就表示包含了列信息。增加该属性后,cheap就不会生成列信息,调式代码列信息没有什么用,因此使用cheap后,文件大小相对于source-map来讲,bundle.js 文件会变得更小。

如下图使用的是 source-map 生成的bundle.js.map 文件, 会包含列的信息,如下图所示:

Webpack讲解:devTool中SourceMap模式详解

使用cheap属性后,也不会有loader模块之间对应的sourcemap,因为webpack打包最终会将所有的非js资源,通过loader形式转换成js资源,比如 vue 中的文件,xx.vue -> vue-loader转换 -> js -> 压缩 -> 压缩后的js

所以说如果没有loader之间的sourcemap文件的话,那么在debug的时候,定义到压缩前的js中的时候,不能跟踪到vue中。

2.5 module(如:cheap-module-source-map)
该属性的配置也是生成一个没有列的信息的sourceMaps文件,同时loader的sourcemap也被简化成为只包含对应行的。

三:开发环境和线上环境如何选择sourceMap?

从上面的eval, inline, source-map, cheap, module中可以看到,各自属性值代表打包后的具体含义,因此我们可以分析下开发环境和正式环境要如何选择sourceMap;我们可以从如下几个方面考虑:

1. 源代码中的列信息是没有任何作用,因此我们打包后的文件不希望包含列相关信息,只有行信息能建立打包前后的依赖关系。因此不管是开发环境或生产环境,我们都希望添加cheap的基本类型来忽略打包前后的列信息。
2. 不管是开发环境还是正式环境,我们都希望能定位到bug的源代码具体的位置,比如说某个vue文件报错了,我们希望能定位到具体的vue文件,因此我们也需要module配置。
3. 我们需要生成map文件的形式,因此我们需要增加 source-map属性。
4. 我们介绍了eval打包代码的时候,知道eval打包后的速度非常快,因为它不生成map文件,但是可以对eval组合使用 eval-source-map 使用会将map文件以DataURL的形式存在打包后的js文件中,比如如下:

Webpack讲解:devTool中SourceMap模式详解
 

它的效果类似于inline的效果,因此在正式环境中不要使用 eval-source-map, 因为它会增加文件的大小,但是在开发环境中,可以试用下,因为他们打包的速度很快。

因此我们可以总结如下:

**在开发环境中我们可以使用 **

module.exports = {
  devtool: 'cheap-module-eval-source-map'
}

**在正式环境中我们可以使用 **

module.exports = { 
  devtool: 'cheap-module-source-map';
}

如上是总结的在开发环境和正式环境使用的sourcemap进行打包的简单思路。

 

 

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
张国生
上一篇:Element-UI省市区选择组件city-picker
下一篇:JSON.stringify 输出JSON字符串时对日期Date类型的处理
评论列表

发表评论

评论内容
昵称:
验证码:
验证码
关联文章

Webpack讲解devToolSourceMap模式详解
熔断和降级的初步详解实现(NET Core控制台输出讲解Polly)
如何使用webpack打包你的项目
如何在 Vue 2 使用 Webpack 构建时为 favicon.ico 设置自定义根路径前缀
vue结合qiankun无法使用vue devtools调试子项目
Linq to SQL语句基础讲解
数据绑定模式
jQuery.cropper中文API详解
GIT Bash 简单讲解-git如何推/拉代码
.Net 下高性能分表分库组件-连接模式原理
CodeX默认推理模式为高
.NETCore-winform 判断是否设计模式
SAP PP 与 PP-PI 详解:从一辆自行车到一批果汁
wifnorm处于设计模式校验 (.NET6)
重新认识Docker Compose之Sidecar模式
CSS backdrop-filter 属性详解及使用方法
C# WPF MVVM模式Prism框架从零搭建(经典)
2.网络聊天程序的三种模式
VMWare CentOS桥接模式配置IP地址
SAP S/4HANA MM模块培训 16 - MRP控制参数:处理键、计划模式与过程控制

热门标签
.NET Core .NET Reactor ag-grid AI发布 api安全 ASP.NET Core C#DLL加密 C#播放声音 C#代码混淆 C#代码加密 ChromeDriver Codex DateTime DBeaver devexpress devTool DLL混淆 edge.js EF EFCore Electron element-ui el-form el-table excel FastReport FileStream FolderBrowerDialog FolderSelectDialog form提交 git gridcontrol gridview input javascript json字符串 JS转换对象JSON jwt JWT授权 linq log Math MCP mitmproxy MVC MySQL Navicat netstat nginx node_modules NSwag Nuget Nuget镜像 number PowerShell pyinstaller python pythoncom python爬虫 python抓包 pywin32 redis Requests-html RestSharp Selenium sql SQL Server Swagger to-cms Visual Studio VSCode vue VueRouter vue路由 VUE页面通讯 Webpack Windows Windows服务 winform wmi xlrd yaml YESCMS YESWEB开发框架 白象 表单提交 播放声音 打开URL 代码混淆 弹窗提醒 端口占用 对象转换 分布式 公共字典 机器码 进程排查 静态资源 开发指南 路由参数 密钥 配置教程 配置文件 权限 人工智能 任务 任务调度 日期间隔 日志 日志记录 省市区 授权验证 数据库 四舍五入 文案 文件读取 文件夹选择 文件目录选择 问题排查 行政区域数据 页面通讯 中间件 CSharp 事务锁 工单系统 并发控制 重复提交 CMS Markdig Markdown markdown-it marked 技术选型 VS Code 开发工具 源代码管理 版本控制 Docker PostgreSQL 时区 部署排查 CMS架构 EF Core 主题系统 二次开发 插件系统 容器 运维命令 镜像清理 Linux NAS 远程挂载 飞牛 fnOS S/4HANA SAP GUI SAP HANA SAP R/3 SAP入门 SAP版本 ERP SAP SAP MM 库存管理 物料管理 采购管理 入门教程 SAP S/4HANA SPRO 企业结构 采购组织 MM01 物料主数据 物料类型 BP分组 业务伙伴 供应商主数据 ME41 RFQ 库存物料 采购流程 ME51 消耗性物料 科目分配 采购申请 AC03 ML81N 外部服务 服务主数据 Business Partner SAP培训 ME51N MM模块 Lean Services MM-SRV 外部服务采购 PIR 供应来源 采购主数据 采购信息记录 ME31K 框架协议 计划协议 采购合同 ME01 供应来源确定 货源清单 MEQ1 供应源确定 配额安排 配额评分 MD04 MD21 MRP 计划文件 需求计划 批量程序 MD01N MD02 MRP Live MD05 MM 物料计划 优化采购 供应源 采购订单 ME2A 供应商确认 采购监控 Flexible Workflow 凭证释放 采购审批 释放策略 实地盘点 物料凭证 货物移动 MIGO 收货 移动类型 已撤回 供应商退货 货物发出 STO 库存转储 转移过账 生产订单 预留 GR/IR MIRO 供应商发票 物流发票校验 OMR2 税码 FI PP SD 实操教程 MRBR OMR6 发票差异 交货成本 后续借记 MI01 实物盘点 盘点差异 公司代码 工厂 组织结构 OMS2 主数据定制 自动科目确定 BP角色 CVI 伙伴确定 编号范围 凭证类型 字段选择 FBN1 OMBT OMC2 会计凭证 OMJJ BOM 委外加工 项目类别L MRKO 供应商寄售 特殊库存K MRKON PIPE Pipeline 特殊库存P ERS MRIS 发票计划 周期性结算 里程碑付款 变更追踪 版本管理 采购凭证 SFTP WebDAV 网盘 飞牛fnOS AMPL HERS MPN 中文教程 库存确定 可用性检查 缺件检查 Output Management 消息确定 输出确定 分割评估 库存计价 评估类别 评估类型 PB00 RM0000 条件技术 采购定价 MM-FI集成 OBYC 库存估价 文本类型 文本采用 EFB EVO MSV SU3 用户参数 发票校验 合同参照 履约保留款 特别总账 预付款 Fiori Launchpad SAP Fiori 应用导航 用户体验 LSMW LTMC Migration Cockpit 数据迁移 BRFplus OPD Output Control My Inbox 审批流程 灵活工作流 SAP PP 外部加工 SAP QM 检验批 质量信息记录 采购收货 SAP PM 维护BOM 维护订单 SAP SD SAP Service 端到端流程 MM模块培训 FI-MM集成 供应商管理 审批配置 FICO入门 SAP FICO 财务配置 供应商税务 预扣税 House Bank 银行对账 客户清账 应收账款 FI控制 验证与替代 印度 GST 税务配置 F110 FBZP EWM入门 SAP EWM 仓库管理 OX14 成本核算 物料评估 后勤配置 物料组 价值更新 数量更新 PP-PI 流程制造 生产计划 容差配置 SAP事务码 SAP基础 TCODE Basis 事务代码 MMNR 编号区间 采购实操 组织架构 OMSF SAP实操 FI配置
联系我们
联系电话:15090125178(微信同号)
电子邮箱:garson_zhang@163.com
站长微信二维码
微信二维码