在生产环境中调试 Angular 应用程序而不显示源映射
當(dāng)我們的 Angular 應(yīng)用程序部署到生產(chǎn)環(huán)境時(shí),我們經(jīng)常會遇到與我們在開發(fā)過程中編輯的不同的代碼。我們的代碼在構(gòu)建過程中會以各種方式進(jìn)行修改和優(yōu)化。
TypeScript 被 transpiled, minified 和 uglifed。生成的 JavaScript 包盡可能小,并且能夠在瀏覽器中運(yùn)行。
所有這些概念都很棒,因?yàn)樗鼈兲岣吡宋覀儜?yīng)用程序的性能。但是,這也給生產(chǎn)系統(tǒng)的故障排查帶來了一些困難。
SourceMap 是一個(gè)解決方案。
從本質(zhì)上講,源映射是一個(gè) JSON 文件,其中包含將轉(zhuǎn)譯后的代碼映射回原始源所需的所有信息。很酷!
從技術(shù)上講,源映射只是一個(gè)包含以下字段的 JSON 文件:
- version : 表示源映射規(guī)范版本
- file : 此源映射所屬的轉(zhuǎn)譯文件的名稱
- sourceRoot : basePath — 源相對于這里
- sources : 原始源文件的路徑(例如 TypeScript 文件)
- sourcesContent : 可選屬性,可以包含您的整個(gè)源代碼。當(dāng)源代碼在此屬性中內(nèi)聯(lián)時(shí),無需托管源代碼即可檢索。
- names:代碼中找到的方法或變量名稱
- mappings:這是整個(gè)魔術(shù)發(fā)生的地方。從技術(shù)上講,映射屬性是一個(gè)非常大的字符串,其中包含Base64 VLQ(可變長度數(shù)量)值。這些值有助于找到源文件中的原始位置。
如何檢索源映射?
要檢索源映射,我們需要告訴瀏覽器它們所在的位置。我們可以通過添加以下行在文件末尾指定
sourceMappingURL:
例子:
//# sourceMappingURL=pathToSourceMaps有了這些信息,瀏覽器就可以下載源映射文件并解釋其內(nèi)容以創(chuàng)建映射。
注意:瀏覽器僅在開發(fā)者工具打開時(shí)下載源地圖。對于普通用戶,沒有性能影響。
除了在文件末尾添加注釋之外,您還可以SourceMap在獲取 minified 的 JavaScript 文件的響應(yīng)中將路徑作為HTTP 標(biāo)頭的值發(fā)送。
SourceMap: pathToSourceMap
第二種可能性使您可以在服務(wù)器端切換源映射,而無需更改 minified 之后的 JavaScript 文件。
開發(fā)和生產(chǎn)期間的源映射
開發(fā)和生產(chǎn)版本不同。
在開發(fā)過程中,擁有完整的源圖是有意義的,因?yàn)槲覀儗W⒂诠ぞ摺㈤_發(fā)經(jīng)驗(yàn)或 hot module 替換。
另一方面,在生產(chǎn)中,我們專注于性能——使用 small bundles 快速初始加載。
應(yīng)該在生產(chǎn)過程中啟用源映射嗎?
這個(gè)問題的答案很大程度上取決于您的項(xiàng)目。如果您正在從事開源項(xiàng)目,那么肯定是這樣。
但是我們大多數(shù)人在日常工作中并不從事開源項(xiàng)目。在企業(yè)項(xiàng)目中,您有充分的理由不想公開您的源代碼。
- 我們不想暴露易于閱讀的應(yīng)用程序代碼給外界。
- 更快的構(gòu)建
- 不想暴露 source map 的提供源頭
下面介紹如何在生產(chǎn)環(huán)境啟用 Source Map,但是不暴露其來源。
Angular CLI 允許我們配置是否需要源映射。然后它將這些信息傳遞給底層的 Webpack。
要探索 Angular 中的源映射,讓我們從一個(gè)由 Angular CLI 生成的全新 Angular 項(xiàng)目開始。
ng new sourceMapInspector
Component 實(shí)現(xiàn)很簡單:
public changeTitle(): void {this.title = 'awesome app'; }模板里的消費(fèi)代碼:
<button (click)="changeTitle()">Change title</button>使用 ng serve 命令。
源映射幫助我們在開發(fā)工具中顯示我們的原始源。
我們現(xiàn)在可以打開app.component.ts并在changeTitle函數(shù)內(nèi)放置一個(gè)斷點(diǎn)。通過單擊“更改標(biāo)題”按鈕,我們?nèi)缓簏c(diǎn)擊了我們的斷點(diǎn)。
如果我們查看 main.js 文件的最后一行,我們可以看到瀏覽器獲取源映射的位置。
//# sourceMappingURL=main.js.map
這對開發(fā)非常有用。我們有完整的源映射,可以輕松調(diào)試我們的代碼。
讓我們檢查一下 Angular 中的生產(chǎn)構(gòu)建在源映射方面的行為。我們可以使用以下命令運(yùn)行 prod 構(gòu)建。
ng build --prod
該 dist 文件夾現(xiàn)在包含沒有 source map 的捆綁文件。讓我們切換到該dist文件夾并在 HTTP 服務(wù)器上運(yùn)行該應(yīng)用程序,以了解它在生產(chǎn)中的外觀。
可以使用 npm 模塊http-server作為本地 Web 服務(wù)器。
http-server 是一個(gè)簡單的、零配置的命令行 http 服務(wù)器,可以安裝 npm i -g http-server
因此,讓我們運(yùn)行我們的生產(chǎn)版本并打開開發(fā)工具來調(diào)試我們的功能。
在生產(chǎn)模式下,沒有來源,也沒有可供點(diǎn)擊的 Webpack 菜單項(xiàng)。
我們在哪里設(shè)置斷點(diǎn)?我們需要手動在轉(zhuǎn)換后的 JavaScript 文件中找到我們的函數(shù),這很麻煩。
我們在第 7841 行設(shè)置了斷點(diǎn),即使我們的應(yīng)用程序只包含幾行代碼。
將源映射添加到 Angular 生產(chǎn)構(gòu)建
angular.json 文件包含一個(gè) architect 屬性,允許我們指定是否要為我們的生產(chǎn)構(gòu)建使用源映射。
要啟用源映射,我們需要將 sourceMap 屬性更改為 true或通過傳遞 --source-map 給我們的 ng build 命令來覆蓋它。
這種方法會將源映射添加到我們的生產(chǎn)構(gòu)建中并在生產(chǎn)中獲取它們,以便每個(gè)人都可以訪問我們的源。
對源映射的細(xì)粒度控制?
Angular 7.2 為我們提供了對源映射的更細(xì)粒度控制。該 sourceMap 屬性現(xiàn)在接受具有以下屬性的對象,而不是一個(gè)簡單的 boolean 值。
"sourceMap": {"hidden": true,"scripts": true,"styles": true }scripts 和 styles 屬性允許我們只為 scripts 或者 styles 生成 source map.
而 hidden 屬性,顧名思義,可以生成隱藏的 source map.
源映射本身對于常規(guī)構(gòu)建或帶有隱藏源映射的構(gòu)建沒有區(qū)別。只有生成的包在一行中有所不同——webpack 添加的用于檢索源映射的注釋。
讓我們看一下使用源映射生成的包。
注意最后的一行注釋語句。當(dāng)我們打開開發(fā)工具時(shí),瀏覽器將解釋此注釋并嘗試獲取源映射。現(xiàn)在讓我們看一下使用隱藏源映射生成的包。
我們可以看到文件末尾沒有添加注釋。因此瀏覽器不會嘗試獲取源映射。如果有一種方法可以使用一些簡單的 npm 腳本來處理生產(chǎn)環(huán)境中的源映射呢?
上傳本地源地圖
我們總是可以在本地重新生成源映射并在以后上傳它們。
"sourceMap": { "hidden": true, "scripts": true, "styles": true }接下來,我們需要?jiǎng)?chuàng)建一個(gè) postbuild 腳本,該腳本僅刪除我們剛剛生成的源映射。
"postbuild": "rm dist/sourceMapInspector/*.map"該 postbuild 腳本是必需的,否則我們將提供源映射。由于缺少 comment,它們不會被解析。但他們?nèi)匀槐惶峁?/p>
為了在生產(chǎn)中進(jìn)行調(diào)試,我們手動上傳源映射。但是我們從哪里得到它們呢?我們剛剛刪除了它們。
答案很簡單,我們需要重新生成它們。
我們現(xiàn)在可以使用 Chrome 開發(fā)工具從本地文件系統(tǒng)上傳源映射。因此,打開開發(fā)工具并右鍵單擊您的main[hash].js. 現(xiàn)在輸入上面腳本生成的源映射的路徑。
必須按以下方式添加路徑:file///pathToFile.
更多Jerry的原創(chuàng)文章,盡在:“汪子熙”:
總結(jié)
以上是生活随笔為你收集整理的在生产环境中调试 Angular 应用程序而不显示源映射的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 论文阅读:Siam-RPN
- 下一篇: Cypress 里的 ensureAtt