在生產環境中除錯 Angular 應用程式而不顯示源對映
當我們的 Angular 應用程式部署到生產環境時,我們經常會遇到與我們在開發過程中編輯的不同的程式碼。我們的程式碼在構建過程中會以各種方式進行修改和優化。
TypeScript 被 transpiled, minified 和 uglifed。生成的 JavaScript 包儘可能小,並且能夠在瀏覽器中執行。
所有這些概念都很棒,因為它們提高了我們應用程式的效能。但是,這也給生產系統的故障排查帶來了一些困難。
SourceMap 是一個解決方案。
從本質上講,源對映是一個 JSON 檔案,其中包含將轉譯後的程式碼映射回原始源所需的所有資訊。很酷!
從技術上講,源對映只是一個包含以下欄位的 JSON 檔案:
- version : 表示源對映規範版本
- file : 此源對映所屬的轉譯檔案的名稱
- sourceRoot : basePath — 源相對於這裡
- sources : 原始原始檔的路徑(例如 TypeScript 檔案)
- sourcesContent : 可選屬性,可以包含您的整個原始碼。當原始碼在此屬性中內聯時,無需託管原始碼即可檢索。
- names:程式碼中找到的方法或變數名稱
- mappings:這是整個魔術發生的地方。從技術上講,對映屬性是一個非常大的字串,其中包含Base64 VLQ(可變長度數量)值。這些值有助於找到原始檔中的原始位置。
如何檢索源對映?
要檢索源對映,我們需要告訴瀏覽器它們所在的位置。我們可以通過新增以下行在檔案末尾指定
sourceMappingURL:
例子:
//# sourceMappingURL=pathToSourceMaps
有了這些資訊,瀏覽器就可以下載源對映檔案並解釋其內容以建立對映。
注意:瀏覽器僅在開發者工具開啟時下載源地圖。對於普通使用者,沒有效能影響。
除了在檔案末尾添加註釋之外,您還可以SourceMap在獲取 minified 的 JavaScript 檔案的響應中將路徑作為HTTP 標頭的值傳送。
SourceMap: pathToSourceMap
第二種可能性使您可以在伺服器端切換源對映,而無需更改 minified 之後的 JavaScript 檔案。
開發和生產期間的源對映
開發和生產版本不同。
在開發過程中,擁有完整的源圖是有意義的,因為我們專注於工具、開發經驗或 hot module 替換。
另一方面,在生產中,我們專注於效能——使用 small bundles 快速初始載入。
應該在生產過程中啟用源對映嗎?
這個問題的答案很大程度上取決於您的專案。如果您正在從事開源專案,那麼肯定是這樣。
但是我們大多數人在日常工作中並不從事開源專案。在企業專案中,您有充分的理由不想公開您的原始碼。
- 我們不想暴露易於閱讀的應用程式程式碼給外界。
- 更快的構建
- 不想暴露 source map 的提供源頭
下面介紹如何在生產環境啟用 Source Map,但是不暴露其來源。
Angular CLI 允許我們配置是否需要源對映。然後它將這些資訊傳遞給底層的 Webpack。
要探索 Angular 中的源對映,讓我們從一個由 Angular CLI 生成的全新 Angular 專案開始。
ng new sourceMapInspector
Component 實現很簡單:
public changeTitle(): void {
this.title = 'awesome app';
}
模板裡的消費程式碼:
<button (click)="changeTitle()">Change title</button>
使用 ng serve 命令。
源對映幫助我們在開發工具中顯示我們的原始源。
我們現在可以開啟app.component.ts並在changeTitle函式內放置一個斷點。通過單擊“更改標題”按鈕,我們然後點選了我們的斷點。
如果我們檢視 main.js 檔案的最後一行,我們可以看到瀏覽器獲取源對映的位置。
//# sourceMappingURL=main.js.map
這對開發非常有用。我們有完整的源對映,可以輕鬆除錯我們的程式碼。
讓我們檢查一下 Angular 中的生產構建在源對映方面的行為。我們可以使用以下命令執行 prod 構建。
ng build --prod
該 dist 資料夾現在包含沒有 source map 的捆綁檔案。讓我們切換到該dist資料夾並在 HTTP 伺服器上執行該應用程式,以瞭解它在生產中的外觀。
可以使用 npm 模組http-server作為本地 Web 伺服器。
http-server 是一個簡單的、零配置的命令列 http 伺服器,可以安裝 npm i -g http-server
因此,讓我們執行我們的生產版本並開啟開發工具來除錯我們的功能。
在生產模式下,沒有來源,也沒有可供點選的 Webpack 選單項。
我們在哪裡設定斷點?我們需要手動在轉換後的 JavaScript 檔案中找到我們的函式,這很麻煩。
我們在第 7841 行設定了斷點,即使我們的應用程式只包含幾行程式碼。
將源對映新增到 Angular 生產構建
angular.json 檔案包含一個 architect 屬性,允許我們指定是否要為我們的生產構建使用源對映。
要啟用源對映,我們需要將 sourceMap 屬性更改為 true或通過傳遞 --source-map 給我們的 ng build 命令來覆蓋它。
這種方法會將源對映新增到我們的生產構建中並在生產中獲取它們,以便每個人都可以訪問我們的源。
對源對映的細粒度控制️
Angular 7.2 為我們提供了對源對映的更細粒度控制。該 sourceMap 屬性現在接受具有以下屬性的物件,而不是一個簡單的 boolean 值。
"sourceMap": {
"hidden": true,
"scripts": true,
"styles": true
}
scripts 和 styles 屬性允許我們只為 scripts 或者 styles 生成 source map.
而 hidden 屬性,顧名思義,可以生成隱藏的 source map.
源對映本身對於常規構建或帶有隱藏源對映的構建沒有區別。只有生成的包在一行中有所不同——webpack 新增的用於檢索源對映的註釋。
讓我們看一下使用源對映生成的包。
注意最後的一行註釋語句。當我們開啟開發工具時,瀏覽器將解釋此註釋並嘗試獲取源對映。現在讓我們看一下使用隱藏源對映生成的包。
我們可以看到檔案末尾沒有添加註釋。因此瀏覽器不會嘗試獲取源對映。如果有一種方法可以使用一些簡單的 npm 指令碼來處理生產環境中的源對映呢?
上傳本地源地圖
我們總是可以在本地重新生成源對映並在以後上傳它們。
"sourceMap": {
"hidden": true,
"scripts": true,
"styles": true
}
接下來,我們需要建立一個 postbuild 指令碼,該指令碼僅刪除我們剛剛生成的源對映。
"postbuild": "rm dist/sourceMapInspector/*.map"
該 postbuild 指令碼是必需的,否則我們將提供源對映。由於缺少 comment,它們不會被解析。但他們仍然被提供。
為了在生產中進行除錯,我們手動上傳源對映。但是我們從哪裡得到它們呢?我們剛剛刪除了它們。
答案很簡單,我們需要重新生成它們。
"build:sourcemaps": "ng build --prod --output-path=localSourceMaps"
我們現在可以使用 Chrome 開發工具從本地檔案系統上傳源對映。因此,開啟開發工具並右鍵單擊您的main[hash].js. 現在輸入上面指令碼生成的源對映的路徑。
必須按以下方式新增路徑:file///pathToFile.
更多Jerry的原創文章,盡在:"汪子熙":