Webpack中Source?Map配置深入解析
為什么需要Source Map
通常我們運行在瀏覽器中的代碼是經(jīng)過處理的,處理后的代碼可能與開發(fā)時代碼相差很遠(yuǎn),這就導(dǎo)致開發(fā)調(diào)試和線上排錯變得困難。這時Source Map就登場了,有了它瀏覽器就可以從轉(zhuǎn)換后的代碼直接定位到轉(zhuǎn)換前的代碼。在webpack中,可以通過devtool選項來配置Source Map。
devtool選項
當(dāng)mode為development時,devtool默認(rèn)為‘eval’,當(dāng)mode為production時,devtool默認(rèn)為false。
devtool為false和'eval'有啥區(qū)別
在回答這個問題之前,我們得做點準(zhǔn)備工作。
準(zhǔn)備工作
1,創(chuàng)建項目 安裝依賴
// 1,創(chuàng)建項目 安裝依賴 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設(shè)置為development。因為當(dāng)mode為production時webpack會開啟代碼壓縮,不利于我們觀察現(xiàn)象。 output: { filename: '[name].js', path: path.resolve(__dirname, 'dist'), clean: true, }, devtool: false, // 先配置為false plugins: [new HtmlWebpackPlugin()], };
4,在package.json中添加
"scripts": { "build": "webpack" }
5,執(zhí)行 npm run build,打包文件生成到了dist文件夾中,至此,準(zhǔn)備工作完畢。
觀察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"])(); })();
內(nèi)容分析:
- __webpack_modules__對象對應(yīng)著我們源碼中的js文件, key是路徑,value就是經(jīng)過webpack轉(zhuǎn)換過的模塊。
- 我們寫的 console.log(
hello index
); 這類源碼中的內(nèi)容,基本沒什么變化的被打包到dist/main.js中。
2,在瀏覽器中,觀察開發(fā)者工具中的Sources。
內(nèi)容分析:
- 只能看到webpack打包后的代碼.
小結(jié)
devtool為false,只能看到打包后的代碼,不利于開發(fā)調(diào)試和線上排錯。
觀察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?"); }) });
內(nèi)容分析:
- 模塊中的內(nèi)容被eval包裹。內(nèi)容末尾有// # sourceURL=webpack://sourcemap/./src/index.js。瀏覽器會對eval后面的sourceURL特殊處理。下面看看怎么特殊處理的
2,在瀏覽器中
內(nèi)容分析:
- 所有sourceURL的內(nèi)容會被翻譯成上圖中左側(cè)下方sourcemap-demo節(jié)點的結(jié)構(gòu),點擊某個節(jié)點,會看到其eval對應(yīng)的代碼。從中我們看到了console.log(
hello index
);。
小結(jié)
devtool為'eval',可以在瀏覽器開發(fā)者工具中看到模塊結(jié)構(gòu),通常也就是我們源碼的結(jié)構(gòu)。也能看到被webpack轉(zhuǎn)換過點代碼,在一定程度上能幫助我們調(diào)試代碼和排查問題了。
devtool為'source-map'和'eval-source-map'有啥區(qū)別
觀察devtool為'source-map'時
現(xiàn)在將devtool設(shè)置成source-map,看看效果。
1, 在dist/main.js中
//# sourceMappingURL=main.js.map
內(nèi)容分析:
- 最下面多了一行注釋代碼sourceMappingURL指向main.js.map。同時dist文件夾下多了個main.js.map。
main.js.map文件
源碼和打包后代碼的映射文件,有了它,當(dāng)線上出bug時,瀏覽器可以在控制臺顯示報錯在源碼中的行數(shù)和列數(shù)。
2,在瀏覽器中
內(nèi)容分析:
- 在瀏覽器中可以看到我們的源碼了。
小結(jié)
- devtool為'source-map',會生成映射文件,出bug時可以準(zhǔn)確定位到問題在源碼中的位置,便于開發(fā)調(diào)試和排查問題。
- 它同樣有缺點,一是source-map的生成比較耗時,二是在開發(fā)時,我們會用熱更新,沒有source-map的話只需替換被更改的模塊就行了,但是有source-map時,就要重新生產(chǎn)整個打包文件的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"); }) });
內(nèi)容分析:
- 與devtool為'source-map'的區(qū)別是,不是在文件最底部多了一行//# sourceMappingURL=main.js.map,也沒有生成map文件。而是每個模塊直接跟隨一個sourceMappingURL,其中是源碼和打包后代碼的映射信息。這樣點好處時在webpack因為開發(fā)者的更改要進(jìn)行熱更新時,不必重新生成全局map文件,只需重新生成更改模塊的map信息就好。
2,在瀏覽器中
內(nèi)容分析:
- 在瀏覽器中同樣可以看到源碼,相比于'source-map',熱更新時編譯時間更少。
小結(jié)
- 這里總結(jié)下'eval'的好處,由于Mapping信息被拆分在了每個模塊eval函數(shù)后面的sourceMappingURL中,熱更新時不必全量生成map數(shù)據(jù),從而擁有更快的編譯速度。(官網(wǎng)管這叫rebuild速度快)
對于開發(fā)調(diào)試,eval-source-map模式就完美了嗎,如果追求更快的編譯速度而不求追求的出現(xiàn)bug時精準(zhǔn)的行列信息,只提供bug所在行信息就行,應(yīng)該用什么?答案是'eval-cheap-source-map'。
devtool為'eval-cheap-source-map'和'eval-cheap-module-source-map'有啥區(qū)別
eval-source-map可以在出現(xiàn)bug時準(zhǔn)確的定位到出錯代碼在源碼的行和列。但如果你不需要列映射,只需要知道bug所在的行,那可以考慮eval-cheap-source-map,它比eval-source-map開銷小,編譯的快。
觀察devtool為'eval-cheap-source-map'時
1, 在dist/main.js中
這里不貼代碼了,相比于eval-source-map,sourceMappingURL后的內(nèi)容少很多。
2,在瀏覽器中
與eval-source-map相同,更多細(xì)節(jié)暫不研究。
3,eval-cheap-source-map的問題
我們增加js代碼babal專義的環(huán)節(jié),安裝 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();
查看在瀏覽器中的表現(xiàn)
壞了,瀏覽器中展示點代碼是經(jīng)過loader編譯后的代碼,不是我們手寫的代碼了。
經(jīng)實驗,如果設(shè)置成eval-source-map,不會有這個問題,瀏覽器中仍然可以看到源碼。
有沒有什么設(shè)置,既可以沒有列映射,又能在瀏覽器中看到源碼的呢?答案是eval-cheap-module-source-map。
觀察devtool為'eval-cheap-module-source-map'時
在這種情況下,源自 loader 的 source map 會得到更好的處理結(jié)果。既沒有列映射,又能在瀏覽器中看到源碼。
小結(jié)
在開發(fā)模式下,為方便我們的開發(fā)調(diào)試。
- 如果你想要最全的源碼,bug精準(zhǔn)定位到哪行哪列,使用eval-source-map。
- 如果只需要將錯誤定位到哪行,使用eval-cheap-module-source-map。
開發(fā)模式下其他配置
inline-source-map,inline-cheap-source-map等inline開頭的
就是把map文件內(nèi)容放打包js代碼文件中。看起來沒多大用處。
eval-nosources-cheap-source-map 等有nosources關(guān)鍵字的
源碼信息不再map文件中,瀏覽器通常會嘗試從 web 服務(wù)器或文件系統(tǒng)加載源代碼。目前不了解其使用場景。
生產(chǎn)環(huán)境的source map配置
(none)
生產(chǎn)環(huán)境不配置等同于寫了devtool: false。默認(rèn)不生成 source map,這是個不錯的選擇。因為別人可以通過 source map看到我們的源碼,影響安全。
source-map
在線上環(huán)境不必使用eval-*了,沒有熱更新的情況。也沒必要使用cheap-*了,只要發(fā)布的時候編譯一次,慢點就慢點。
顯然使用source-map有個問題,會讓用戶看到源碼。我們可以通過服務(wù)器配置,禁止普通用戶訪問 source map 文件。只讓固定IP(開發(fā)者的電腦的IP)的用戶可以訪問到。
hidden-source-map
hidden-source-map - 與 source-map 相同,都會生成.map文件。但不會為 bundle 添加引用注釋。
目前,各大監(jiān)控平臺均有針對錯誤監(jiān)控的Source Map的解析功能。例如開源監(jiān)控平臺Sentry支持Webpack插件和自身的CLI工具上傳map文件后進(jìn)行解析。
使用hidden-source-map,當(dāng)線上報錯時,將錯誤堆棧跟蹤信息上報給監(jiān)控平臺,監(jiān)控平臺結(jié)合map文件就可以告訴我們源碼級別的錯誤信息了。
總結(jié)
通過這次配置研究,我們要學(xué)習(xí)到
- eval配置的作用和原理。
- source-map配置的作用和原理。
- 開發(fā)環(huán)境和生產(chǎn)環(huán)境視情況選擇devtool的值。
以上就是Webpack中Source Map配置深入解析的詳細(xì)內(nèi)容,更多關(guān)于Webpack Source Map配置的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript特效實現(xiàn)——當(dāng)前時間和倒計時效果的簡單實例
下面小編就為大家?guī)硪黄猨avascript特效實現(xiàn)——當(dāng)前時間和倒計時效果的簡單實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-07-07echarts圖形x、y坐標(biāo)文字設(shè)置間隔顯示及相關(guān)問題詳解
最近在做一個web的數(shù)據(jù)統(tǒng)計部分用到了Echart,下面這篇文章主要給大家介紹了關(guān)于echarts圖形x、y坐標(biāo)文字設(shè)置間隔顯示及相關(guān)問題的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08Vant+postcss-pxtorem 實現(xiàn)瀏覽器適配功能
這篇文章主要介紹了Vant+postcss-pxtorem 實現(xiàn)瀏覽器適配,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02Webpack?模塊加載動態(tài)引入機(jī)制源碼示例解析
這篇文章主要為大家介紹了Webpack?模塊加載動態(tài)引入機(jī)制源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09