摘要:文件就是記錄了從源代碼文件到壓縮文件的一個代碼對應關系記錄表,通過壓縮文件和文件可以原原本本找出源代碼文件。
細說 js 壓縮、sourcemap、通過 sourcemap 查找原始報錯信息 1. js 壓縮
js 壓縮對前端開發者來說是一門必修課。
一般來說,壓縮 js 主要出于以下兩個目的:
減小代碼體積,加快前端資源加載速度
保護源代碼不被別人獲取
壓縮 js 使用的工具庫:
UglifyJS2: 壓縮 es5
uglify-es: 壓縮 es6+
closure-compiler、closure-compiler-js: google 的 js 壓縮、優化工具
壓縮 js 的主要過程:
移除無用代碼
混淆代碼中變量名稱、函數名稱等
預編譯代碼
對結構進行扁平化處理
1. 移除無用代碼去掉所有對解析引擎來說無用的字符,包括空格、注釋、換行、沒有用的變量聲明、函數聲明等。
2. 混淆代碼中變量名稱、函數名稱等把一些局部變量名稱、函數名稱等用 a, b, ...、$1, $2, ...、_1, _2, ... 之類的簡略字符進行替換,達到混淆的目的。
源代碼
(function () { var hello = "hi"; var print = function (str) { console.log(str); }; print(hello); })();
壓縮后的代碼(僅演示混淆功能)
(function () { var a = "hi"; var b = function (c) { console.log(c); }; b(a); })();3. 預編譯代碼
把不依賴外部環境的邏輯提前進行運算,并把運算結果替換到相應的源碼處,然后從源碼中移除這段邏輯。
源代碼
(function () { var hello = "hi" + " everyone, "; var count = 3 * 5; console.log(hello + count + " girls"); })();
壓縮后的代碼(僅演示預編譯功能)
(function () { var hello = "hi everyone, "; var count = 15; console.log(hello + count + " girls"); })();4. 對結構進行扁平化處理
對于 js 來說,嵌套越深,執行越慢,對代碼進行扁平化處理也是優化代碼的一種方式。
源代碼
(function () { var say = { hello: function (str) { console.log("hello " + str); } }; say.hello("everyone"); })();
壓縮后的代碼(僅演示扁平化結構功能)
!function(str){console.log("hello "+str)}("everyone");完整示例
源代碼
(function () { var say = { hello: function (str) { console.log("hello " + str); } }; say.hello("everyone"); })();
壓縮后的代碼
!function(l){console.log("hello "+l)}("50 girls");2. sourcemap
通常 js 壓縮后只有一行代碼,并且里面的變量名與函數名等都是混淆了的,這在實際運行中會有一個問題,就是 js 的報錯信息將會失真,無法追蹤到是在源代碼哪一行哪一列報的錯。
sourcemap 便是為了解決這個問題而生的。
sourcemap 文件就是記錄了從源代碼文件到壓縮文件的一個代碼對應關系記錄表,通過壓縮文件和 sourcemap 文件可以原原本本找出源代碼文件。
查看阮一峰老師的 JavaScript Source Map 詳解 了解 sourcemap 的原理與格式。
一般在壓縮 js 的過程中,會生成相應的 sourcemap 文件,并且在壓縮的 js 文件末尾追加 sourcemap 文件的鏈接 //# sourceMappingURL=bundle-file-name.js.map。這樣,瀏覽器在加載這個壓縮 js 的時候,就知道還有一個相應的 sourcemap 文件,也一并加載下來,運行的過程中如果 js 報錯,也會給出相應源代碼的行號與列號,而非壓縮文件的。
比如,對下面的源碼進行壓縮:
(function () { var say = { hi: function () { console.log("hi"); } }; say.hello(); return say; })();
未加 sourcemap 文件時,報錯信息是:
加上 sourcemap 文件時,報錯信息是:
sourcemap 擴展webpack 對 sourcemap 做了擴展,定義在 devtool 配置項中:
eval: 每個模塊都使用 eval() 執行,并且都有 //@ sourceURL,構建很快,但無法正確顯示行號
eval-source-map: 每個模塊使用 eval() 執行,并且 source map 轉換為 DataUrl 后添加到 eval() 中,一般開發模式中使用這種方式
cheap-eval-source-map: 類似 eval-source-map,但只映射行,不映射列,并忽略源自 loader 的 source map,僅顯示轉譯后的代碼
cheap-module-eval-source-map: 類似 cheap-eval-source-map,但會保留源自 loader 的 source map
inline-source-map: source map 轉換為 DataUrl 后添加到 bundle 中
cheap-source-map: 只映射行,不映射列,并忽略源自 loader 的 source map,僅顯示轉譯后的代碼
inline-cheap-source-map: inline-source-map 與 cheap-source-map 的結合
cheap-module-source-map: 類似 cheap-module-eval-source-map,但不使用 eval() 執行
inline-cheap-module-source-map: inline-source-map 與 cheap-module-source-map 的結合
source-map: 整個 source map 作為一個多帶帶的文件生成,產品環境一般使用這種模式
hidden-source-map: 類似 source-map,但不會把 //# sourceMappingURL=bundle-file-name.js.map 追加到壓縮文件后面
nosources-source-map: 類似 source-map,但只有堆棧信息,沒有源碼信息
更詳細信息可以參考:
webpack devtool(英文)
webpack devtool(中文)
使用建議對于使用 webpack 來構建項目,建議在開發時使用 eval-source-map,產品環境使用 source-map。
因為用壓縮文件與 sourcemap 文件是可以原原本本的找到源代碼的,所以,為了保護源代碼,可以這樣隱藏 sourcemap 文件:
在 web 服務器設置外部不能訪問 sourcemap 文件,只能內部訪問
直接把 sourcemap 文件存放到其他地方
3. 通過 sourcemap 查找原始報錯信息一般而言,在產品階段,我們會用 window.onerror 來捕獲 js 報錯,然后上報到服務器,以此來收集用戶使用時發生的 bug:
window.onerror = function(message, source, lineno, colno, error) { // message: 錯誤信息 // source: 報錯腳本的 url 地址 // lineno: 行號 // colno: 列號 // error: 錯誤對象 // 上報必要的信息到服務器 }
但產品環境的代碼都是壓縮的,行號和列號都是失真的,所以就需要用 sourcemap 文件來找到錯誤對應源代碼的行號與列號,以及其他的信息。
使用工具: mozilla/source-map
源代碼
(function () { var say = { hi: function () { console.log("hi"); } }; say.hello(); return say; })();
壓縮后報錯信息
window.onerror = function(message, source, lineno, colno, error) { console.log(`message: ${message}`); console.log(`source: ${source}`); console.log(`lineno: ${lineno}`); console.log(`colno: ${colno}`); console.log(`error: ${error}`); } // message: Uncaught TypeError: e.hello is not a function // source: url/to/bundle.min.js // lineno: 1 // colno: 982 // error: TypeError: e.hello is not a function
通過 source-map 查找原始報錯信息
const fs = require("fs"); const SourceMap = require("source-map"); const { readFileSync } = fs; const { SourceMapConsumer } = SourceMap; const rawSourceMap = JSON.parse(readFileSync("path/to/js/map/file", "utf8")); SourceMapConsumer.with(rawSourceMap, null, consumer => { const pos = consumer.originalPositionFor({ line: 1, column: 982 }); console.log(pos); });
查找到的原始信息
{ source: "path/to/index.js", line: 8, column: 7, name: "hello" }
這樣,便找到了原始報錯信息:
原始報錯文件:path/to/index.js
原始報錯行號:8
原始報錯列號:7
原始對象名稱:hello
如此,便能一下子就找到錯誤在哪里了。
更多用法,參考 mozilla/source-map
后續更多博客,查看 https://github.com/senntyou/blogs
作者:深予之 (@senntyou)
版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99228.html
摘要:從到再到搭建編寫構建一個前端項目選擇現成的項目模板還是自己搭建項目骨架搭建一個前端項目的方式有兩種選擇現成的項目模板自己搭建項目骨架。使用版本控制系統管理源代碼項目搭建好后,需要一個版本控制系統來管理源代碼。 從 0 到 1 再到 100, 搭建、編寫、構建一個前端項目 1. 選擇現成的項目模板還是自己搭建項目骨架 搭建一個前端項目的方式有兩種:選擇現成的項目模板、自己搭建項目骨架。 ...
摘要:從到再到搭建編寫構建一個前端項目選擇現成的項目模板還是自己搭建項目骨架搭建一個前端項目的方式有兩種選擇現成的項目模板自己搭建項目骨架。使用版本控制系統管理源代碼項目搭建好后,需要一個版本控制系統來管理源代碼。 從 0 到 1 再到 100, 搭建、編寫、構建一個前端項目 1. 選擇現成的項目模板還是自己搭建項目骨架 搭建一個前端項目的方式有兩種:選擇現成的項目模板、自己搭建項目骨架。 ...
摘要:從到再到搭建編寫構建一個前端項目選擇現成的項目模板還是自己搭建項目骨架搭建一個前端項目的方式有兩種選擇現成的項目模板自己搭建項目骨架。使用版本控制系統管理源代碼項目搭建好后,需要一個版本控制系統來管理源代碼。 從 0 到 1 再到 100, 搭建、編寫、構建一個前端項目 1. 選擇現成的項目模板還是自己搭建項目骨架 搭建一個前端項目的方式有兩種:選擇現成的項目模板、自己搭建項目骨架。 ...
摘要:另外這樣的異常捕獲不能捕獲的異常錯誤信息,這點需要注意。最終大致的流程圖如下結語前端異常捕獲與上報是前端異常監控的前提,了解并做好了異常數據的收集和分析才能實現一個完善的錯誤響應和處理機制,最終達成數據可視化。 關于 微信公眾號:前端呼啦圈(Love-FED) 我的博客:勞卜的博客 知乎專欄:前端呼啦圈 前言 Hello,大家好,又與大家見面了,這次給大家分享下前端異常監控中需...
閱讀 1574·2021-09-23 11:21
閱讀 2345·2021-09-07 10:13
閱讀 834·2021-09-02 10:19
閱讀 1125·2019-08-30 15:44
閱讀 1720·2019-08-30 13:18
閱讀 1913·2019-08-30 11:15
閱讀 1105·2019-08-29 17:17
閱讀 2017·2019-08-29 15:31