掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
盡管我很喜歡 .NET 生態(tài)系統(tǒng),但有些事情,JavaScript 生態(tài)系統(tǒng)做得更好。其中之一就是任何事情都能找到一個庫,特別是涉及到網(wǎng)絡時。

以語法高亮為例。這可以直接用 C# 來做,但這不是一個特別流暢的體驗。例如,TextMateSharp 項目為 TextMate 語法提供了一個解釋器。這些文件是 VS Code 用來為一種語言添加基本語法高亮的。然而,如果你想部署應用程序,它包裝了一個本地依賴,這就增加了一些復雜性。
相比之下,JavaScript 有大量成熟的語法高亮庫。僅舉幾例,有 highlight.js、Prism.js(在本博客中使用)和 shiki.js。尤其是前兩個,非常成熟,有多個插件和主題,而且有簡單的 API。
作為一個 .NET 開發(fā)者,JavaScript 的明顯問題是,你需要學習并選擇進入一個完整的獨立工具鏈,與 Node.js 和 NPM 一起工作。這似乎是一個很大的開銷,只是為了使用一個小功能。
因此,我們陷入了一個困境。我們要么走 C#(+ Native)路線,要么就得轉(zhuǎn)用 JavaScript。
或者......我們直接從我們的 .NET 應用程序中調(diào)用 JavaScript 。
一旦你決定在你的 .NET 代碼中運行 JavaScript,你就會考慮幾個選擇。你可以借用 JavaScript 引擎,讓它為你運行你的 JavaScript,但你并沒有真正解決問題,你仍然需要安裝 Node.js。
另一個選擇是在你的庫中直接捆綁 JavaScript 引擎。這并不像聽起來那么瘋狂,有幾個 NuGet 包采用了這種方法,然后暴露出一個 C# 層來與引擎進行交互。
下面是你可以使用的一些包的列表。
這個庫采取了上述的第一種方法。它不包括包中的 Node.js。相反,它為執(zhí)行 JavaScript 代碼提供了一個 C# API,并調(diào)用了安裝在你機器上的 Node.js。這在你知道兩者都已安裝的環(huán)境中可能很有用,但它并沒有真正解決我想避免的問題。
ChakraCore 是 Edge 轉(zhuǎn)為基于 Chromium 引擎之前最初使用的 JavaScript 引擎。根據(jù) GitHub 項目的介紹:
ChakraCore 是一個帶有 C 語言 API 的 JavaScript 引擎,你可以用它來為任何 C 語言或 C 語言兼容項目添加對 JavaScript 的支持。它可以在 Linux macOS 和 Windows 上針對 x64 處理器進行編譯。而 x86 和 ARM 只適用于 Windows。
因此,ChakraCore 包括一個本地依賴,但由于 C# 可以 P/Invoke 到本地庫,這本身并不是一個問題。但它會帶來一些部署方面的挑戰(zhàn)。
Node.JS、Chromium、Chrome 和最新的 Edge 使用的都是 V8 JavaScript 引擎。Microsoft.ClearScript 包為該庫提供了一個封裝,為調(diào)用 V8 庫提供了一個 C# 接口。就像 ChakraCore 一樣,V8 引擎本身是一個本地依賴。ClearScript 庫負責 P/Invoke 調(diào)用,提供了一個很好的 C# API,但你仍然要確保你在目標平臺上部署了正確的本地庫。
Jint 很有意思,因為它是一個完全在 .NET 中運行的 JavaScript 解釋器,沒有任何本地的依賴!它完全支持 ECMAScript 5.1 (ES5),并支持 .NET Standard 2.0,所以你可以在你的所有項目中使用它!
Jurassic 是另一個 JavaScript 引擎的 .NET 實現(xiàn),類似于 Jint。也和 Jint 類似,它支持所有的 ES5,而且似乎也部分支持 ES6。與 Jint 不同的是,Jurassic 不是一個解釋器,它將 JavaScript 編譯成 IL,這使得它的速度非??欤宜鼪]有本地的依賴性。
那么,在所有這些選擇中,你應該選擇哪一個?
還有一個偉大的項目可以讓你簡單地嘗試上面其中的任何一個庫。雖然所有的庫都允許你運行 JavaScript,但它們都有略微不同的 C# API 來與之交互。這可能會使比較它們變得有點痛苦,因為你必須為每個庫學習不同的 API。
JavaScriptEngineSwitcher 這個庫為我提到的所有庫和更多的庫提供了封裝:
每個庫都在一個單獨的包中(有本地依賴關(guān)系的引擎需要一個額外的本地包),還有一個 Core 包,它提供通用的 API。即使你不打算切換 JS 引擎,我也傾向于盡可能地使用 JavaScriptEngineSwitcher 封裝庫,這樣你就不必在以后需要切換引擎時弄清楚一個新的 API 了。
在 .NET 項目中改變使用的 JavaScript 引擎在我看來是完全可能的。例如,我開始使用 Jint,但當我需要執(zhí)行更大的腳本時,我遇到了性能問題,于是換成了 Jurassic。JavaScriptEngineSwitcher 讓這一切變得很簡單,只需在我的項目中添加一個新的包并改變一些初始化代碼即可。
我最近才發(fā)現(xiàn) JavaScriptEngineSwitcher 這個庫,但最新版本的下載量已接近一百萬,它被用于 .NET 靜態(tài)網(wǎng)站建設者 Statiq 中。在這篇文章的最后部分,我將舉一個最基本用法的例子。
在這篇文章的開頭,我討論了一個特定的場景--代碼塊的語法高亮。在本節(jié)中,我將展示如何使用 prism.js 高亮一小段代碼,并在一個控制臺應用程序中運行。
開始之前請?zhí)砑?JavaScriptEngineSwitcher.Jurassic NuGet 包的引用。
dotnet add package JavaScriptEngineSwitcher.Jurassic
接下來,下載你想運行的 JavaScript 文件。例如,我從 Prism.js 的官網(wǎng)下載了 prism.js 文件,并將 C# 添加到默認支持高亮的語言集。在把文件放到項目文件夾的根目錄后,我把文件更新為嵌入資源。你可以在你的 IDE 中操作,也可以手動編輯項目文件:
Exe
net6.0
enable
enable
剩下的就是編寫代碼,在我們的程序中運行腳本。下面的代碼段設置了 JavaScript 引擎,從程序集中加載嵌入的 prism.js 庫,并執(zhí)行它。
using JavaScriptEngineSwitcher.Jurassic;
// Create an instance of the JavaScript engine
IJsEngine engine = new JurassicJsEngine();
// Execute the embedded resource called JsInDotnet.prism.js from the provided assembly
engine.ExecuteResource("JsInDotnet.prism.js", typeof(Program).Assembly);
現(xiàn)在我們可以在同一個上下文中運行我們自己的 JavaScript 命令。我們可以通過使用 SetVariableName、Execute 和 Evaluate 從 C# 向 JavaScript 引擎?zhèn)鬟f數(shù)值:
// This is the code we want to highlight
string code = @"
using System;
public class Test : ITest
{
public int ID { get; set; }
public string Name { get; set; }
}";
// set the JavaScript variable called "input" to the value of the c# variable "code"
engine.SetVariableValue("input", code);
// set the JavaScript variable called "lang" to the string "csharp"
engine.SetVariableValue("lang", "csharp");
// run the Prism.highlight() function, and set the result to the "highlighed" variable
engine.Execute($"highlighted = Prism.highlight(input, Prism.languages.csharp, lang)");
// "extract the value of "highlighted" from JavaScript to C#
string result = engine.Evaluate("highlighted");
Console.WriteLine(result);
當你把它們放在一起運行時,高亮的代碼會被打印到控制臺:
using System;
public class Test : ITest
{
public int ID { get; set; }
public string Name { get; set; }
}
渲染后,看起來像這樣:
我對整個過程的簡單程度感到驚訝。啟動一個 JavaScript 引擎,加載 prism.js 文件,并執(zhí)行我們的自定義代碼是如此順利。這是我面臨問題的完美解決方案。
我顯然不建議所有的應用程序都這樣做。如果你需要運行大量的 JavaScript,那么直接使用 Node.js 生態(tài)系統(tǒng)及工具可能更容易。但如果你只是想利用一個小型的、獨立的工具(如 prims.js),那么這是一個不錯的選擇。
在這篇文章中,我展示了如何使用 JavaScriptEngineSwitcher NuGet 包來在 .NET 應用程序中運行 JavaScript。這個包為許多不同的 JavaScript 引擎提供了一個一致的接口。其中一些引擎(如 Chakra Core 和 V8)需依賴一個本地組件,而其他引擎(如 Jint 和 Jurassic)只使用托管代碼。最后,我展示了你如何使用 JavaScriptEngineSwitcher 在 .NET 應用程序內(nèi)部運行 Prims.js 代碼高亮庫。
原文:bit.ly/38awq7W
作者:Andrew Lock
翻譯:精致碼農(nóng)

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流