js
壓縮js
壓縮對前端開發者來講是一門必修課。javascript
通常來講,壓縮 js
主要出於如下兩個目的:html
壓縮 js
使用的工具庫:前端
es5
es6+
google
的 js
壓縮、優化工具壓縮 js
的主要過程:java
去掉全部對解析引擎來講無用的字符,包括空格、註釋、換行、沒有用的變量聲明、函數聲明等。webpack
把一些局部變量名稱、函數名稱等用 a, b, ...
、$1, $2, ...
、_1, _2, ...
之類的簡略字符進行替換,達到混淆的目的。git
源代碼es6
(function () { var hello = 'hi'; var print = function (str) { console.log(str); }; print(hello); })();
壓縮後的代碼(僅演示混淆功能)github
(function () { var a = 'hi'; var b = function (c) { console.log(c); }; b(a); })();
把不依賴外部環境的邏輯提早進行運算,並把運算結果替換到相應的源碼處,而後從源碼中移除這段邏輯。web
源代碼瀏覽器
(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'); })();
對於 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");
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 來構建項目,建議在開發時使用 eval-source-map
,產品環境使用 source-map
。
由於用壓縮文件與 sourcemap
文件是能夠原本來本的找到源代碼的,因此,爲了保護源代碼,能夠這樣隱藏 sourcemap
文件:
web
服務器設置外部不能訪問 sourcemap
文件,只能內部訪問sourcemap
文件存放到其餘地方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
hello
如此,便能一會兒就找到錯誤在哪裏了。
更多用法,參考 mozilla/source-map
更多博客,查看 https://github.com/senntyou/blogs
版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證)