先日副業をしていて、Java Scriptの機能を使う必要があることに気づきました。Node.jsとnpmを再び扱うことを考えたとき、私は完全にあきらめたので、. NETアプリケーションでJava Scriptを実行する可能性を検討することにしました。クレイジーでしょう?実際、それは驚くほど簡単です。
1. なぜこんなことを?
私は. NETエコシステムが大好きですが、Java Scriptエコシステムの方が良いこともあります。1つは、特にネットワークに関しては、何でもライブラリを見つけることができることです。
以语法高亮为例。这可以直接用 C# 来做,但这不是一个特别流畅的体验。例如,TextMateSharp 项目为 TextMate 语法提供了一个解释器。这些文件是 VS Code 用来为一种语言添加基本语法高亮的。然而,如果你想部署应用程序,它包装了一个本地依赖,这就增加了一些复杂性。
相比之下,JavaScript 有大量成熟的语法高亮库。仅举几例,有 highlight.js、Prism.js(在本博客中使用)和 shiki.js。尤其是前两个,非常成熟,有多个插件和主题,而且有简单的 API。
NET開発者としてJava Scriptの明白な問題は、Node.jsとNPMで動作する完全なスタンドアロンツールチェーンを学び、選択する必要があることです。これは、小さな機能を使用するだけで大きなオーバーヘッドのように思えます。
そこで我々は窮地に立たされた。C#(+ Native)ルートを取るか、Java Scriptに切り替える必要があります。
または...。. NETアプリケーションから直接Java Scriptを呼び出します。
2. NETでのJavaScriptの実行
NETコードでJava Scriptを実行することを決めたら、いくつかのオプションを検討する必要があります。Java Scriptエンジンを借りてJava Scriptを実行させることはできますが、実際に問題を解決することはできません。Node.jsをインストールする必要があります。
もう一つのオプションは、ライブラリに直接Java Scriptエンジンをバンドルすることです。これは聞こえるほどクレイジーではなく、いくつかのNuGetパッケージがこのアプローチを採用し、エンジンと対話するためのC#レイヤーを公開しています。
以下は、使用できるパッケージの一部です。
Jering.JavaScript.NodeJS
这个库采取了上述的第一种方法。它不包括包中的 Node.js。相反,它为执行 JavaScript 代码提供了一个 C# API,并调用了安装在你机器上的 Node.js。这在你知道两者都已安装的环境中可能很有用,但它并没有真正解决我想避免的问题。
ChakraCore
ChakraCore 是 Edge 转为基于 Chromium 引擎之前最初使用的 JavaScript 引擎。根据 GitHub 项目的介绍:
ChakraCore是一个带有 C 语言 API 的 JavaScript 引擎,你可以用它来为任何 C 语言或 C 语言兼容项目添加对 JavaScript 的支持。它可以在 Linux macOS 和 Windows 上针对 x64 处理器进行编译。而 x86 和 ARM 只适用于 Windows。
因此,ChakraCore 包括一个本地依赖,但由于 C# 可以 P/Invoke 到本地库,这本身并不是一个问题。但它会带来一些部署方面的挑战。
ClearScript (V8)
Node.JS、Chromium、Chrome 和最新的 Edge 使用的都是 V8 JavaScript 引擎。Microsoft.ClearScript 包为该库提供了一个封装,为调用 V8 库提供了一个 C# 接口。就像 ChakraCore 一样,V8 引擎本身是一个本地依赖。ClearScript 库负责 P/Invoke 调用,提供了一个很好的 C# API,但你仍然要确保你在目标平台上部署了正确的本地库。
Jint
Jint 很有意思,因为它是一个完全在 .NET 中运行的 JavaScript 解释器,没有任何本地的依赖!它完全支持 ECMAScript 5.1 (ES5),并支持 .NET Standard 2.0,所以你可以在你的所有项目中使用它!
Jurassic
Jurassic 是另一个 JavaScript 引擎的 .NET 实现,类似于 Jint。也和 Jint 类似,它支持所有的 ES5,而且似乎也部分支持 ES6。与 Jint 不同的是,Jurassic 不是一个解释器,它将 JavaScript 编译成 IL,这使得它的速度非常快,而且它没有本地的依赖性。
これらの選択肢の中から、あなたはどれを選ぶべきでしょうか。
Java ScriptEngineSwitcher:JSエンジンでは不十分な場合
また、上記のライブラリのいずれかを簡単に試すことができる素晴らしいプロジェクトもあります。すべてのライブラリはJava Scriptを実行できますが、それらと対話するためのC#APIはわずかに異なります。ライブラリごとに異なるAPIを学ぶ必要があるため、比較するのは少し面倒です。
JavaScriptEngineSwitcher 这个库为我提到的所有库和更多的库提供了封装:
- Jering.JavaScript.NodeJS
- ChakraCore
- Microsoft ClearScript.V8
- Jint
- Jurassic
- MSIE JavaScript Engine for .NET
- NiL.JS
- VroomJs
各ライブラリは別々のパッケージ(ローカル依存関係を持つエンジンは追加のローカルパッケージを必要とします)と、共通のAPIを提供するCoreパッケージがあります。JSエンジンを切り替える予定がない場合でも、後でエンジンを切り替える必要があるときに新しいAPIを見つける必要がないように、できるだけJava Script EngineSwitcherパッケージライブラリを使用することをお勧めします。
在 .NET 项目中改变使用的 JavaScript 引擎在我看来是完全可能的。例如,我开始使用 Jint,但当我需要执行更大的脚本时,我遇到了性能问题,于是换成了 Jurassic。JavaScriptEngineSwitcher 让这一切变得很简单,只需在我的项目中添加一个新的包并改变一些初始化代码即可。
我最近才发现 JavaScriptEngineSwitcher 这个库,但最新版本的下载量已接近一百万,它被用于 .NET 静态网站建设者 Statiq 中。在这篇文章的最后部分,我将举一个最基本用法的例子。
4例:コンソールアプリケーションでJava Script EngineSwitcherを使用してprism.jsを実行する
在这篇文章的开头,我讨论了一个特定的场景--代码块的语法高亮。在本节中,我将展示如何使用 prism.js 高亮一小段代码,并在一个控制台应用程序中运行。
开始之前请添加 JavaScriptEngineSwitcher.Jurassic NuGet 包的引用。
dotnet add package JavaScriptEngineSwitcher.Jurassic
接下来,下载你想运行的 JavaScript 文件。例如,我从 Prism.js 的官网下载了 prism.js 文件,并将 C# 添加到默认支持高亮的语言集。在把文件放到项目文件夹的根目录后,我把文件更新为嵌入资源。你可以在你的 IDE 中操作,也可以手动编辑项目文件:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JavaScriptEngineSwitcher.Jurassic" Version="3.17.4" />
</ItemGroup>
<!-- 👇 Make prism.js an embedded resource -->
<ItemGroup>
<None Remove="prism.js" />
<EmbeddedResource Include="prism.js" />
</ItemGroup>
</Project>
剩下的就是编写代码,在我们的程序中运行脚本。下面的代码段设置了 JavaScript 引擎,从程序集中加载嵌入的 prism.js 库,并执行它。
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);
现在我们可以在同一个上下文中运行我们自己的 JavaScript 命令。我们可以通过使用 SetVariableName、Execute 和 Evaluate 从 C# 向 JavaScript 引擎传递数值:
// 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<string>("highlighted");
Console.WriteLine(result);
それらを一緒に実行すると、ハイライトされたコードがコンソールに表示されます。
<span class="token keyword">using</span>
<span class="token namespace">System</span
><span class="token punctuation">;</span>
<span class="token keyword">public</span>
<span class="token keyword">class</span>
<span class="token class-name">Test</span>
<span class="token punctuation">:</span>
<span class="token type-list"><span class="token class-name">ITest</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span>
<span class="token return-type class-name"
><span class="token keyword">int</span></span
>
ID <span class="token punctuation">{</span>
<span class="token keyword">get</span><span class="token punctuation">;</span>
<span class="token keyword">set</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span>
<span class="token return-type class-name"
><span class="token keyword">string</span></span
>
Name <span class="token punctuation">{</span>
<span class="token keyword">get</span><span class="token punctuation">;</span>
<span class="token keyword">set</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
レンダリング後、以下のようになります:

我对整个过程的简单程度感到惊讶。启动一个 JavaScript 引擎,加载 prism.js 文件,并执行我们的自定义代码是如此顺利。这是我面临问题的完美解决方案。
我显然不建议所有的应用程序都这样做。如果你需要运行大量的 JavaScript,那么直接使用 Node.js 生态系统及工具可能更容易。但如果你只是想利用一个小型的、独立的工具(如 prims.js),那么这是一个不错的选择。
5つの概要
在这篇文章中,我展示了如何使用 JavaScriptEngineSwitcher NuGet 包来在 .NET 应用程序中运行 JavaScript。这个包为许多不同的 JavaScript 引擎提供了一个一致的接口。其中一些引擎(如 Chakra Core 和 V8)需依赖一个本地组件,而其他引擎(如 Jint 和 Jurassic)只使用托管代码。最后,我展示了你如何使用 JavaScriptEngineSwitcher 在 .NET 应用程序内部运行 Prims.js 代码高亮库。
原文:andrewlock.net/running-javascript-in-a-dotnet-app-with-javascriptengineswitcher/
著者:アンドリュー·ロック
翻訳:繊細な農家