一、Mode配置

这里要简单讲一下,后面还会提到它的其他用法。

Mode配置选项,可以告知webpack使用相应模式的内置优化:

  • 默认值是production
  • 可选值有:’none’ | ‘development’ | ‘production’

这几个选项有什么样的区别呢?

4、webpack-模块化&source map - 图1

  1. const path = require('path');
  2. const { CleanWebpackPlugin } = require('clean-webpack-plugin');
  3. const HtmlWebpackPlugin = require('html-webpack-plugin');
  4. module.exports = {
  5. mode: 'development',
  6. entry: './src/main.js',
  7. output: {
  8. filename: 'bundle.js',
  9. //__dirname,当前文件的上级目录的绝对路径
  10. path: path.resolve(__dirname, './build'),
  11. // assetModuleFilename: 'img/[name].[hash:6][ext]',
  12. },
  13. plugins: [
  14. new CleanWebpackPlugin(),
  15. new HtmlWebpackPlugin({
  16. title: 'webpack项目',
  17. }),
  18. ],
  19. };

mode: 'development',这样编译完的代码不会进行压缩丑化。

Mode配置代表更多 ,后续再了解。

二、模块化原理

webpack支持CommoJS原理

  1. // 定义了一个对象
  2. // 模块的路径(key): 函数(value)
  3. var __webpack_modules__ = {
  4. "./src/js/format.js":
  5. (function (module) {
  6. const dateFormat = (date) => {
  7. return "2020-12-12";
  8. }
  9. const priceFormat = (price) => {
  10. return "100.00";
  11. }
  12. // 将我们要导出的变量, 放入到module对象中的exports对象
  13. module.exports = {
  14. dateFormat,
  15. priceFormat
  16. }
  17. })
  18. }
  19. // 定义一个对象, 作为加载模块的缓存
  20. var __webpack_module_cache__ = {};
  21. // 是一个函数, 当我们加载一个模块时, 都会通过这个函数来加载
  22. function __webpack_require__(moduleId) {
  23. // 1.判断缓存中是否已经加载过
  24. if (__webpack_module_cache__[moduleId]) {
  25. return __webpack_module_cache__[moduleId].exports;
  26. }
  27. // 2.给module变量和__webpack_module_cache__[moduleId]赋值了同一个对象
  28. var module = __webpack_module_cache__[moduleId] = { exports: {} };
  29. // 3.加载执行模块
  30. __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  31. // 4.导出module.exports {dateFormat: function, priceForamt: function}
  32. return module.exports;
  33. }
  34. // 具体开始执行代码逻辑
  35. !function () {
  36. // 1.加载./src/js/format.js
  37. const { dateFormat, priceFormat } = __webpack_require__("./src/js/format.js");
  38. console.log(dateFormat("abc"));
  39. console.log(priceFormat("abc"));
  40. }();

webpack支持ES6 Module原理

  1. // 1.定义了一个对象, 对象里面放的是我们的模块映射
  2. var __webpack_modules__ = {
  3. "./src/es_index.js":
  4. (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
  5. // 调用r的目的是记录时一个__esModule -> true
  6. __webpack_require__.r(__webpack_exports__);
  7. // _js_math__WEBPACK_IMPORTED_MODULE_0__ == exports
  8. var _js_math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/js/math.js");
  9. console.log(_js_math__WEBPACK_IMPORTED_MODULE_0__.mul(20, 30));
  10. console.log(_js_math__WEBPACK_IMPORTED_MODULE_0__.sum(20, 30));
  11. }),
  12. "./src/js/math.js":
  13. (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
  14. __webpack_require__.r(__webpack_exports__);
  15. // 调用了d函数: 给exports设置了一个代理definition
  16. // exports对象中本身是没有对应的函数
  17. __webpack_require__.d(__webpack_exports__, {
  18. "sum": function () { return sum; },
  19. "mul": function () { return mul; }
  20. });
  21. const sum = (num1, num2) => {
  22. return num1 + num2;
  23. }
  24. const mul = (num1, num2) => {
  25. return num1 * num2;
  26. }
  27. })
  28. };
  29. // 2.模块的缓存
  30. var __webpack_module_cache__ = {};
  31. // 3.require函数的实现(加载模块)
  32. function __webpack_require__(moduleId) {
  33. if (__webpack_module_cache__[moduleId]) {
  34. return __webpack_module_cache__[moduleId].exports;
  35. }
  36. var module = __webpack_module_cache__[moduleId] = {
  37. exports: {}
  38. };
  39. __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  40. return module.exports;
  41. }
  42. !function () {
  43. // __webpack_require__这个函数对象添加了一个属性: d -> 值function
  44. __webpack_require__.d = function (exports, definition) {
  45. for (var key in definition) {
  46. if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  47. Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  48. }
  49. }
  50. };
  51. }();
  52. !function () {
  53. // __webpack_require__这个函数对象添加了一个属性: o -> 值function
  54. __webpack_require__.o = function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
  55. }();
  56. !function () {
  57. // __webpack_require__这个函数对象添加了一个属性: r -> 值function
  58. __webpack_require__.r = function (exports) {
  59. if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  60. Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  61. }
  62. Object.defineProperty(exports, '__esModule', { value: true });
  63. };
  64. }();
  65. __webpack_require__("./src/es_index.js");

CommonJS与ES6 Module相互导入原理

  1. var __webpack_modules__ = ({
  2. "./src/index.js":
  3. (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
  4. "use strict";
  5. __webpack_require__.r(__webpack_exports__);
  6. var _js_format__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/js/format.js");
  7. var _js_format__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_js_format__WEBPACK_IMPORTED_MODULE_0__);
  8. // es module导出内容, CommonJS导入内容
  9. const math = __webpack_require__("./src/js/math.js");
  10. // CommonJS导出内容, es module导入内容
  11. console.log(math.sum(20, 30));
  12. console.log(math.mul(20, 30));
  13. console.log(_js_format__WEBPACK_IMPORTED_MODULE_0___default().dateFormat("aaa"));
  14. console.log(_js_format__WEBPACK_IMPORTED_MODULE_0___default().priceFormat("bbb"));
  15. }),
  16. "./src/js/format.js":
  17. (function (module) {
  18. const dateFormat = (date) => {
  19. return "2020-12-12";
  20. }
  21. const priceFormat = (price) => {
  22. return "100.00";
  23. }
  24. module.exports = {
  25. dateFormat,
  26. priceFormat
  27. }
  28. }),
  29. "./src/js/math.js":
  30. (function (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
  31. __webpack_require__.r(__webpack_exports__);
  32. __webpack_require__.d(__webpack_exports__, {
  33. "sum": function () { return sum; },
  34. "mul": function () { return mul; }
  35. });
  36. const sum = (num1, num2) => {
  37. return num1 + num2;
  38. }
  39. const mul = (num1, num2) => {
  40. return num1 * num2;
  41. }
  42. })
  43. });
  44. var __webpack_module_cache__ = {};
  45. // The require function
  46. function __webpack_require__(moduleId) {
  47. // Check if module is in cache
  48. if (__webpack_module_cache__[moduleId]) {
  49. return __webpack_module_cache__[moduleId].exports;
  50. }
  51. // Create a new module (and put it into the cache)
  52. var module = __webpack_module_cache__[moduleId] = {
  53. // no module.id needed
  54. // no module.loaded needed
  55. exports: {}
  56. };
  57. // Execute the module function
  58. __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  59. // Return the exports of the module
  60. return module.exports;
  61. }
  62. !function () {
  63. // getDefaultExport function for compatibility with non-harmony modules
  64. __webpack_require__.n = function (module) {
  65. var getter = module && module.__esModule ?
  66. function () { return module['default']; } :
  67. function () { return module; };
  68. __webpack_require__.d(getter, { a: getter });
  69. return getter;
  70. };
  71. }();
  72. /* webpack/runtime/define property getters */
  73. !function () {
  74. // define getter functions for harmony exports
  75. __webpack_require__.d = function (exports, definition) {
  76. for (var key in definition) {
  77. if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  78. Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  79. }
  80. }
  81. };
  82. }();
  83. /* webpack/runtime/hasOwnProperty shorthand */
  84. !function () {
  85. __webpack_require__.o = function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
  86. }();
  87. /* webpack/runtime/make namespace object */
  88. !function () {
  89. // define __esModule on exports
  90. __webpack_require__.r = function (exports) {
  91. if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  92. Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  93. }
  94. Object.defineProperty(exports, '__esModule', { value: true });
  95. };
  96. }();
  97. __webpack_require__("./src/index.js");

源码问题,慢慢看吧

三、 source-map

我们的代码通常运行在浏览器上时,是通过打包压缩的:

也就是真实跑在浏览器上的代码,和我们编写的代码其实是有差异的

  • 比如ES6的代码可能被转换成ES5
  • 比如对应的代码行号、列号在经过编译后肯定会不一致
  • 比如代码进行丑化压缩时,会将编码名称等修改
  • 比如我们使用了TypeScript等方式编写的代码,最终转换成JavaScript

但是,当代码报错需要调试时(debug),调试转换后的代码是很困难的,况且我们不能保证代码不出错,那么如何可以调试这种转换后不一致的代码呢?答案就是source-map

  • source-map是从已转换(压缩后的)的代码,映射到原始的源文件(npm run build之前的)一种类型文件
  • 使浏览器可以重构原始源并在调试器中显示重建的原始源

如何使用

第一步:根据源文件,生成source-map文件,webpack在打包时,可以通过配置生成source-map

devtool:'source-map'

第二步:在转换后的代码,最后添加一个注释,它指向sourcemap

//# sourceMappingURL=common.bundle.js.map

浏览器会根据我们的注释,查找相应的source-map,并且根据source-map还原我们的代码,方便进行调试。

正常情况下压缩丑化后,不使用source-map,报错后我们无法准确的找到错误处,尤其项目过大时。

4、webpack-模块化&source map - 图2

4、webpack-模块化&source map - 图3

使用source-map:

entry: './src/main.js',
devtool: 'source-map',

4、webpack-模块化&source map - 图4

此时浏览器报错可以快速定位:

4、webpack-模块化&source map - 图5

4、webpack-模块化&source map - 图6

分析source-map

最初source-map生成的文件带下是原始文件的10倍,第二版减少了约50%,第三版又减少了50%,所以目前一个 133kb的文件,最终的source-map的大小大概在300kb。

目前的source-map长什么样子呢?

  • version:当前使用的版本,也就是最新的第三版
  • sources:从哪些文件转换过来的source-map和打包的代码(最初始的文件)
  • names:转换前的变量和属性名称(因为我目前使用的是development模式,所以不需要保留转换前的名 称)
  • mappings:source-map用来和源文件映射的信息(比如位置信息等),一串base64 VLQ(veriablelength quantity可变长度值)编码
  • file:打包后的文件(浏览器加载的文件)
  • sourceContent:转换前的具体代码信息(和sources是对应的关系)
  • sourceRoot:所有的sources相对的根目录
{
  "version": 3,
  "file": "bundle.js",
  "mappings": "kCAkBAA,SAASC,KAAKC,YAlBd,WACE,IAAIC,EAAUH,SAASI,cAAc,OACrCD,EAAQE,UAAY,CAAC,QAAS,WAAWC,KAAK,KAC9CH,EAAQI,UAAY,UAGpB,MAAMC,EAAQ,IAAIC,MAElBN,EAAQD,YAAYM,GAGpB,MAAME,EAAQV,SAASI,cAAc,OAKrC,OAJAM,EAAMC,MAAMC,MAAQ,QACpBF,EAAMC,MAAME,OAAS,QAErBV,EAAQD,YAAYQ,GACbP,EAEiBW,MCjBtBC,EAA2B,GAG/B,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBE,IAAjBD,EACH,OAAOA,EAAaE,QAGrB,IAAIC,EAASN,EAAyBE,GAAY,CAGjDG,QAAS,IAOV,OAHAE,EAAoBL,GAAUI,EAAQA,EAAOD,QAASJ,GAG/CK,EAAOD,S,+BCnBfG,QAAQC,ICCa,S",
  "sources": [
    "webpack://01_webpack_learn/./src/js/component.js",
    "webpack://01_webpack_learn/webpack/bootstrap",
    "webpack://01_webpack_learn/./src/main.js",
    "webpack://01_webpack_learn/./src/js/math.js"
  ],
  "sourcesContent": [
    "function component() {\r\n  let element = document.createElement('div');\r\n  element.innerHTML = ['Hello', 'Webpack'].join(' ');\r\n  element.className = 'content';\r\n\r\n  //创建一个img标签\r\n  const imgEL = new Image();\r\n  // imgEL.src = require('../img/7.jpg').default;\r\n  element.appendChild(imgEL);\r\n\r\n  //创建一个div 设置背景图片\r\n  const divEL = document.createElement('div');\r\n  divEL.style.width = 200 + 'px';\r\n  divEL.style.height = 200 + 'px';\r\n  // divEL.className = 'bg-img';\r\n  element.appendChild(divEL);\r\n  return element;\r\n}\r\ndocument.body.appendChild(component());\r\n",
    "// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n",
    "import { message } from './js/math.js';\r\nimport './js/component.js'\r\nconsole.log(message);",
    "// function sum(n1, n2) {\r\n//   return n1 + n2;\r\n// }\r\nexport const message=\"Hello\""
  ],
  "names": [
    "document",
    "body",
    "appendChild",
    "element",
    "createElement",
    "innerHTML",
    "join",
    "className",
    "imgEL",
    "Image",
    "divEL",
    "style",
    "width",
    "height",
    "component",
    "__webpack_module_cache__",
    "__webpack_require__",
    "moduleId",
    "cachedModule",
    "undefined",
    "exports",
    "module",
    "__webpack_modules__",
    "console",
    "log"
  ],
  "sourceRoot": ""
}

生成source-map

如何在使用webpack打包的时候,生成对应的source-map呢?

  • webpack提供了非常多的选项(目前是26个),来处理source-map https://webpack.docschina.org/configuration/devtool/
  • 选择不同的值,生成的source-map会稍微有差异,打包的过程也会有性能的差异,可以根据不同的情况进行选择

不生成source-map

  • false:不使用source-map,也就是没有任何和source-map相关的内容。
  • none:production模式下的默认值,不生成source-map。
  • eval:development模式下的默认值,不生成source-map
  • 但是它会在eval执行的代码中,添加 //# sourceURL=; 会被浏览器在执行时解析,并且在调试面板中生成对应的一些文件目录,方便我们调试代码;

比如:

eval(
          "function component() {\r\n  let element = document.createElement('div');\r\n  element.innerHTML = ['Hello', 'Webpack'].join(' ');\r\n  element.className = 'content';\r\n\r\n  //创建一个img标签\r\n  const imgEL = new Image();\r\n  // imgEL.src = require('../img/7.jpg').default;\r\n  element.appendChild(imgEL);\r\n\r\n  //创建一个div 设置背景图片\r\n  const divEL = document.createElement('div');\r\n  divEL.style.width = 200 + 'px';\r\n  divEL.style.height = 200 + 'px';\r\n  // divEL.className = 'bg-img';\r\n  element.appendChild(divEL);\r\n  return element;\r\n}\r\ndocument.body.appendChild(component());\r\n\n\n//# sourceURL=webpack://01_webpack_learn/./src/js/component.js?"
        );

4、webpack-模块化&source map - 图7

source-map

生成一个独立的source-map文件,并且在bundle文件中有一个注释,指向source-map文件

bundle文件中有如下的注释: //# sourceMappingURL=bundle.js.map

开发工具会根据这个注释找到source-map文件,并且解析

对应的就是上上面的source-map。

eval-source-map

生成sourcemap,但是source-map是以DataUrl添加到eval函数的后面

eval(
          '__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   "message": function() { return /* binding */ message; }\n/* harmony export */ });\n// function sum(n1, n2) {\r\n//   return n1 + n2;\r\n// }\r\nconst message="Hello"//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvanMvbWF0aC5qcy5qcyIsIm1hcHBpbmdzIjoiOzs7O0FBQUE7QUFDQTtBQUNBO0FBQ08iLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8wMV93ZWJwYWNrX2xlYXJuLy4vc3JjL2pzL21hdGguanM/OWMzOSJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBmdW5jdGlvbiBzdW0objEsIG4yKSB7XHJcbi8vICAgcmV0dXJuIG4xICsgbjI7XHJcbi8vIH1cclxuZXhwb3J0IGNvbnN0IG1lc3NhZ2U9XCJIZWxsb1wiIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./src/js/math.js\n'
        );

inline-source-map

会生成sourcemap,但是source-map是以DataUrl添加到bundle文件的后面

!(function () {
    'use strict';
    /*!*********************!*\
  !*** ./src/main.js ***!
  \*********************/
    __webpack_require__.r(__webpack_exports__);
    /* harmony import */ var _js_math_js__WEBPACK_IMPORTED_MODULE_0__ =
      __webpack_require__(/*! ./js/math.js */ './src/js/math.js');
    /* harmony import */ var _js_component_js__WEBPACK_IMPORTED_MODULE_1__ =
      __webpack_require__(/*! ./js/component.js */ './src/js/component.js');
    /* harmony import */ var _js_component_js__WEBPACK_IMPORTED_MODULE_1___default =
      /*#__PURE__*/ __webpack_require__.n(
        _js_component_js__WEBPACK_IMPORTED_MODULE_1__
      );

    console.log(_js_math_js__WEBPACK_IMPORTED_MODULE_0__.message);
  })();
  /******/
})();
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVuZGxlLmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7Ozs7O0FDbEJBO0FBQ0E7QUFDQTtBQUNPOzs7Ozs7VUNIUDtVQUNBOztVQUVBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBOztVQUVBO1VBQ0E7O1VBRUE7VUFDQTtVQUNBOzs7OztXQ3RCQTtXQUNBO1dBQ0E7V0FDQSxlQUFlLDRCQUE0QjtXQUMzQyxlQUFlO1dBQ2YsaUNBQWlDLFdBQVc7V0FDNUM7V0FDQTs7Ozs7V0NQQTtXQUNBO1dBQ0E7V0FDQTtXQUNBLHlDQUF5Qyx3Q0FBd0M7V0FDakY7V0FDQTtXQUNBOzs7OztXQ1BBLDhDQUE4Qzs7Ozs7V0NBOUM7V0FDQTtXQUNBO1dBQ0EsdURBQXVELGlCQUFpQjtXQUN4RTtXQUNBLGdEQUFnRCxhQUFhO1dBQzdEOzs7Ozs7Ozs7Ozs7Ozs7QUNOdUM7QUFDYjtBQUMxQixZQUFZLGdEQUFPLEUiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8wMV93ZWJwYWNrX2xlYXJuLy4vc3JjL2pzL2NvbXBvbmVudC5qcyIsIndlYnBhY2s6Ly8wMV93ZWJwYWNrX2xlYXJuLy4vc3JjL2pzL21hdGguanMiLCJ3ZWJwYWNrOi8vMDFfd2VicGFja19sZWFybi93ZWJwYWNrL2Jvb3RzdHJhcCIsIndlYnBhY2s6Ly8wMV93ZWJwYWNrX2xlYXJuL3dlYnBhY2svcnVudGltZS9jb21wYXQgZ2V0IGRlZmF1bHQgZXhwb3J0Iiwid2VicGFjazovLzAxX3dlYnBhY2tfbGVhcm4vd2VicGFjay9ydW50aW1lL2RlZmluZSBwcm9wZXJ0eSBnZXR0ZXJzIiwid2VicGFjazovLzAxX3dlYnBhY2tfbGVhcm4vd2VicGFjay9ydW50aW1lL2hhc093blByb3BlcnR5IHNob3J0aGFuZCIsIndlYnBhY2s6Ly8wMV93ZWJwYWNrX2xlYXJuL3dlYnBhY2svcnVudGltZS9tYWtlIG5hbWVzcGFjZSBvYmplY3QiLCJ3ZWJwYWNrOi8vMDFfd2VicGFja19sZWFybi8uL3NyYy9tYWluLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImZ1bmN0aW9uIGNvbXBvbmVudCgpIHtcclxuICBsZXQgZWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gIGVsZW1lbnQuaW5uZXJIVE1MID0gWydIZWxsbycsICdXZWJwYWNrJ10uam9pbignICcpO1xyXG4gIGVsZW1lbnQuY2xhc3NOYW1lID0gJ2NvbnRlbnQnO1xyXG5cclxuICAvL+WIm+W7uuS4gOS4qmltZ+agh+etvlxyXG4gIGNvbnN0IGltZ0VMID0gbmV3IEltYWdlKCk7XHJcbiAgLy8gaW1nRUwuc3JjID0gcmVxdWlyZSgnLi4vaW1nLzcuanBnJykuZGVmYXVsdDtcclxuICBlbGVtZW50LmFwcGVuZENoaWxkKGltZ0VMKTtcclxuXHJcbiAgLy/liJvlu7rkuIDkuKpkaXYg6K6+572u6IOM5pmv5Zu+54mHXHJcbiAgY29uc3QgZGl2RUwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuICBkaXZFTC5zdHlsZS53aWR0aCA9IDIwMCArICdweCc7XHJcbiAgZGl2RUwuc3R5bGUuaGVpZ2h0ID0gMjAwICsgJ3B4JztcclxuICAvLyBkaXZFTC5jbGFzc05hbWUgPSAnYmctaW1nJztcclxuICBlbGVtZW50LmFwcGVuZENoaWxkKGRpdkVMKTtcclxuICByZXR1cm4gZWxlbWVudDtcclxufVxyXG5kb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGNvbXBvbmVudCgpKTtcclxuIiwiLy8gZnVuY3Rpb24gc3VtKG4xLCBuMikge1xyXG4vLyAgIHJldHVybiBuMSArIG4yO1xyXG4vLyB9XHJcbmV4cG9ydCBjb25zdCBtZXNzYWdlPVwiSGVsbG9cIiIsIi8vIFRoZSBtb2R1bGUgY2FjaGVcbnZhciBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX18gPSB7fTtcblxuLy8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbmZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG5cdHZhciBjYWNoZWRNb2R1bGUgPSBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX19bbW9kdWxlSWRdO1xuXHRpZiAoY2FjaGVkTW9kdWxlICE9PSB1bmRlZmluZWQpIHtcblx0XHRyZXR1cm4gY2FjaGVkTW9kdWxlLmV4cG9ydHM7XG5cdH1cblx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcblx0dmFyIG1vZHVsZSA9IF9fd2VicGFja19tb2R1bGVfY2FjaGVfX1ttb2R1bGVJZF0gPSB7XG5cdFx0Ly8gbm8gbW9kdWxlLmlkIG5lZWRlZFxuXHRcdC8vIG5vIG1vZHVsZS5sb2FkZWQgbmVlZGVkXG5cdFx0ZXhwb3J0czoge31cblx0fTtcblxuXHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cblx0X193ZWJwYWNrX21vZHVsZXNfX1ttb2R1bGVJZF0obW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cblx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcblx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xufVxuXG4iLCIvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuX193ZWJwYWNrX3JlcXVpcmVfXy5uID0gZnVuY3Rpb24obW9kdWxlKSB7XG5cdHZhciBnZXR0ZXIgPSBtb2R1bGUgJiYgbW9kdWxlLl9fZXNNb2R1bGUgP1xuXHRcdGZ1bmN0aW9uKCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuXHRcdGZ1bmN0aW9uKCkgeyByZXR1cm4gbW9kdWxlOyB9O1xuXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQoZ2V0dGVyLCB7IGE6IGdldHRlciB9KTtcblx0cmV0dXJuIGdldHRlcjtcbn07IiwiLy8gZGVmaW5lIGdldHRlciBmdW5jdGlvbnMgZm9yIGhhcm1vbnkgZXhwb3J0c1xuX193ZWJwYWNrX3JlcXVpcmVfXy5kID0gZnVuY3Rpb24oZXhwb3J0cywgZGVmaW5pdGlvbikge1xuXHRmb3IodmFyIGtleSBpbiBkZWZpbml0aW9uKSB7XG5cdFx0aWYoX193ZWJwYWNrX3JlcXVpcmVfXy5vKGRlZmluaXRpb24sIGtleSkgJiYgIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBrZXkpKSB7XG5cdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywga2V5LCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZGVmaW5pdGlvbltrZXldIH0pO1xuXHRcdH1cblx0fVxufTsiLCJfX3dlYnBhY2tfcmVxdWlyZV9fLm8gPSBmdW5jdGlvbihvYmosIHByb3ApIHsgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIHByb3ApOyB9IiwiLy8gZGVmaW5lIF9fZXNNb2R1bGUgb24gZXhwb3J0c1xuX193ZWJwYWNrX3JlcXVpcmVfXy5yID0gZnVuY3Rpb24oZXhwb3J0cykge1xuXHRpZih0eXBlb2YgU3ltYm9sICE9PSAndW5kZWZpbmVkJyAmJiBTeW1ib2wudG9TdHJpbmdUYWcpIHtcblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgU3ltYm9sLnRvU3RyaW5nVGFnLCB7IHZhbHVlOiAnTW9kdWxlJyB9KTtcblx0fVxuXHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgJ19fZXNNb2R1bGUnLCB7IHZhbHVlOiB0cnVlIH0pO1xufTsiLCJpbXBvcnQgeyBtZXNzYWdlIH0gZnJvbSAnLi9qcy9tYXRoLmpzJztcclxuaW1wb3J0ICcuL2pzL2NvbXBvbmVudC5qcydcclxuY29uc29sZS5sb2cobWVzc2FnZSk7Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9

….这老长。

cheap-source-map

会生成sourcemap,但是会更加高效一些(cheap低开销)

因为它没有生成列映射(Column Mapping)

因为在开发中,我们只需要行信息通常就可以定位到错误了

4、webpack-模块化&source map - 图8

cheap-module-source-map

会生成sourcemap,类似于cheap-source-map,但是对源自loader的sourcemap处理会更好

这里有一个很模糊的概念:对源自loader的sourcemap处理会更好,官方也没有给出很好的解释

其实是如果loader对我们的源码进行了特殊的处理,比如babel,代码不贴了,看下cheap-source-map 和cheap-module-source-map生成文件的区别:
4、webpack-模块化&source map - 图9

可以看出,cheap-module-source-map生成的文件更贴近我们的源代码。

hidden-source-map

会生成sourcemap,但是不会对source-map文件进行引用

相当于删除了打包文件中对sourcemap的引用注释

如果我们手动添加进来,那么sourcemap就会生效了

// 被删除掉的 
//# sourceMappingURL=bundle.js.map

nosources-source-map

会生成sourcemap,但是生成的sourcemap只有错误信息的提示,不会生成源代码文件;

4、webpack-模块化&source map - 图10

多个值组合

webpack提供给我们的26个值,是可以进行多组合的。

组合的规则如下:

  • inline-|hidden-|eval:三个值时三选一
  • nosources:可选值
  • cheap可选值,并且可以跟随module的值

那么在开发中,最佳的实践是什么呢?

  • 开发阶段:推荐使用 source-map或者cheap-module-source-map

    • 这分别是vue和react使用的值,可以获取调试信息,方便快速开发
  • 测试阶段:推荐使用 source-map或者cheap-module-source-map

    • 测试阶段我们也希望在浏览器下看到正确的错误提示
  • 发布阶段:false、缺省值(不写)