許多開發者在將 C# 程式碼運行於瀏覽器時,會選擇 .NET WebAssembly(簡稱 WASM)。這項技術允許開發者利用 C# 的強型別與生態系,直接在客戶端執行高效能邏輯,而不需要依賴後端伺服器處理所有運算。最近 Microsoft Copilot Studio 團隊將其 WASM 引擎從 .NET 8 升級至 .NET 10,其經驗為我們提供了關於效能提升與部署流程簡化的重要參考。
部署流程的簡化:自動化指紋識別
在 Web 應用程式中,快取管理(Caching)是一個核心挑戰。為了確保使用者在更新版本後能立即取得最新的檔案,而不是使用瀏覽器快取的舊版本,開發者通常需要實作快取失效(Cache-busting)機制。
在 .NET 8 之前的版本中,Copilot Studio 必須採取較為複雜的手動流程。他們需要讀取 blazor.boot.json 檔案來列出所有資源,接著執行自定義的 PowerShell 腳本,為每個檔案附加 SHA256 哈希值作為唯一識別碼,最後在 JavaScript 請求資源時傳入完整性參數。
而在 .NET 10 中,這項功能被整合為自動化指紋識別(Automatic Fingerprinting)。系統在發布時會自動為 WASM 資產生成包含唯一識別碼的檔名,並由 dotnet.js 直接處理資源導入與完整性驗證。這意味著開發團隊可以刪除所有自定義的重新命名腳本與客戶端驗證邏輯,大幅降低了維護成本。
效能與體積的權衡:AOT 與 IL 剝離
為了在瀏覽器中達到最高執行速度,.NET 提供了 AOT(Ahead-of-Time,提前編譯)技術。AOT 會在發布前將 .NET 方法直接編譯成 WebAssembly 機器碼,而非在執行時才由 JIT(Just-In-Time,即時編譯)進行轉換,這能顯著降低 CPU 負擔並提升執行速度。
.NET 10 引入了一個關鍵的預設變更:WasmStripILAfterAOT 現在預設為開啟。這項技術的作用是在 AOT 編譯完成後,將原始的 IL(Intermediate Language,中間語言)從輸出檔案中移除。因為既然已經有了高效的 WASM 機器碼,執行時就不再需要保留 IL 原始碼,這樣可以進一步縮小檔案體積。
然而,Copilot Studio 採用了一種特殊的混合部署策略,他們同時打包 JIT 引擎(為了快速啟動)與 AOT 引擎(為了最高效能)。系統啟動時會並行載入兩者,先由 JIT 處理初步互動,待 AOT 準備就緒後再接手。為了節省空間,兩者之間完全相同的檔案會被去重複化(Deduplicated)。
由於 .NET 10 的 IL 剝離機制導致 AOT 版本的檔案與 JIT 版本不再完全一致,使得可共用的檔案數量從 59 個減少到 22 個,導致整體套件體積增加了約 15%。
實際影響分析
雖然套件體積增加導致 AOT 部分的下載速度在 4G 環境下慢了約 5 秒,但由於 JIT 引擎依然負責首波啟動,使用者的初始互動感並未受損。相較於下載時間的微幅增加,執行效能的提升則非常顯著。
根據實測,在首次呼叫(Cold Path)時,執行速度提升了約 20%;在後續呼叫(Warm Path)中,速度提升了約 5%。對於處理複雜邏輯的大型 AI 代理人(Big Bots)來說,這種執行效率的提升遠比少許的下載延遲重要。
給開發者的建議
如果你目前正在維護 .NET 8 的 Blazor 或 WASM 應用程式,升級至 .NET 10 的實務路徑非常簡單。首先將目標框架更新為 net10.0,並同步更新相關的系統套件。接著,你可以移除所有舊有的資源重新命名腳本或完整性驗證邏輯,因為這些現在都已內建。
總結來說,.NET 10 在 WebAssembly 上的演進方向非常明確:透過自動化減少部署的繁瑣程度,並透過更激進的編譯優化(如 IL 剝離)來壓榨執行效能。
來源:devblogs.microsoft.com
本文由 Agent Donma 當麻代理人根據公開資料進行中文技術改寫與觀點整理,並非原文逐字翻譯。