Skip to content

サーバースクリプトに使える言語の比較 ​

第1版作成 最終更新 (日本時間)
確認バージョン1.5.1.01.5.8.1

1.5.8.1 のプリザンターでは、サーバースクリプトは ClearScript(V8)で動く JavaScript だけです。このページは、JavaScript 以外の言語を足す場合にどれが現実的かを比べた設計メモで、本体の標準機能ではありません。調査は 1.5.1.0 を対象に行いました。

Python は サーバースクリプトを Python で書けるようにする、C# スクリプトは C# スクリプト(Roslyn)をサーバースクリプトに使う にあります。

評価の基準 ​

図を読み込み中…

基準内容
ホストオブジェクトを渡せるAddHostObject 相当で context・model・items などを渡せる
OS 操作を遮断できるファイル I/O・プロセス実行・直接のネットワーク接続ができない
タイムアウトを制御できる無限ループを ContinuationCallback 相当で止められる
依存が NuGet だけネイティブ DLL や外部プロセスを必須にしない
後方互換既存の JavaScript のスクリプトに影響しない

結論 ​

言語実行方式サンドボックス評価
TypeScriptJavaScript に変換して既存の V8 で実行V8 と同じ(原理的保証)推奨
Lua(MoonSharp)純粋 C# の Lua VM設計上サンドボックス前提中優先
Python(IronPython)DLR4 層で封鎖(実装的保証)別ページ
C# スクリプト(Roslyn).NET CLR検査のみ(不完全)条件付き
F# Scripting.NET CLRC# スクリプトと同じ課題低優先
Ruby(MRuby)ネイティブ VM を P/Invokeビルド時に標準ライブラリを外せる低優先
PHP(PeachPie)PHP を IL にコンパイルC# スクリプトと同じ課題不推奨
PowerShellPowerShell SDKOS 操作が前提の言語不可
Groovy・Kotlin Script(IKVM.NET)JVM を .NET 上で模倣Java の SecurityManager が廃止済み不可
VBScript・VB.NET ScriptCOM・Roslyn.NET 10 非対応・C# と同じ課題不可
言語追加の依存実装コスト
TypeScripttypescript.js を埋め込むだけ低
LuaMoonSharp(約 1 MB)中
PythonIronPython 3.4.x高
Ruby公式 NuGet なし・libmruby をプラットフォーム別にビルド高
PHPPeachpie.Runtime など高
C#・F#Microsoft.CodeAnalysis.CSharp.Scripting・FSharp.Compiler.Service高
Groovy・KotlinIKVM と jar(合計 55 MB 以上)非常に高

進める順は、IScriptEngine の抽出 → TypeScript → Python → Lua → その他(MRuby など)です。TypeScript は抽出さえ済めば新しいエンジンが要らず、安全性も変わらないので、Python より先に着手できます。

TypeScript ​

TypeScript は JavaScript のスーパーセットで、型注釈は JavaScript への変換時にすべて消えます。変換後の JavaScript を既存の V8 で実行するので、セキュリティモデルは今と同じで、JavaScript でできないことは TypeScript でもできません。既存の JavaScript はそのまま TypeScript として通り、型定義ファイルを配れば VS Code の補完・型チェックが使えます。

変換方式 ​

方式内容評価
A:実行のたびに V8 内で変換リクエストごとに typescript.js(minify 版で約 6 MB)を読み込む見送り。現行はリクエストごとにエンジンを作って破棄する(ServerScriptUtilities.cs#L1217)ため、毎回数百ミリ秒かかる
B:変換専用の V8 を 1 つ持ち、結果をキャッシュ保存時か初回実行時に変換し、実行時はキャッシュした JavaScript を通常の V8 で動かす採用
C:Node.js のプロセスで変換Jering.Javascript.NodeJS など見送り。Node.js のインストールが要る

図を読み込み中…

TypeScriptTranspilerService の要点 ​

  • 新規ファイル Libraries/ServerScripts/TypeScriptTranspilerService.cs。Lazy<T> のシングルトンで、専用の V8ScriptEngine に埋め込みリソースの typescript.min.js を 1 回だけ読み込む。
  • ts.transpileModule() を target: ES2020・module: None・strict: false・reportDiagnostics: true で呼ぶ。module: None なので import・export は構文エラーになる。デコレータのメタデータ出力(emitDecoratorMetadata)は無効にする。
  • 結果はソースの SHA-256 をキーに ConcurrentDictionary に入れる。変換用の V8 はスレッドセーフではないので、変換だけ lock し、キャッシュに当たったときはロックしない。スクリプトの更新時にキャッシュを消す。
  • typescript.min.js は npm の typescript パッケージから取り、.csproj に EmbeddedResource として追加する。新しい NuGet パッケージは要らない。

本体の変更 ​

  • ServerScript の Language(Python 版 で追加する int?)に TypeScript = 2 を足す。
  • ServerScriptUtilities.Execute で、TypeScript のスクリプトは TypeScriptTranspilerService.Instance.Transpile(script.Body) を通してから V8 に渡す。ホストオブジェクトの登録は変えない。
  • ダイアログの言語の選択に TypeScript を足し、コードエディタのモードを typescript にする。
typescript
// TypeScript のサーバースクリプトの例
const title: string = model.Title as string;
if ((context.UserId as number) === 0) {
    context.ErrorData.Type = 1;
}
model.ClassA = `処理済み: ${title}`;

型定義ファイル(declare const context: { readonly UserId: number; ... } など)は補完・型チェック専用で、実行時には使いません。本体には入れず、npm パッケージや VS Code 拡張、ダイアログからのダウンロードで配ります。

項目TypeScriptJavaScript(現行)
変換サービスの初期化1 回だけ約 500 ミリ秒なし
初回の実行変換 約 10〜50 ミリ秒 + V8V8 のみ
2 回目以降キャッシュ 1 ミリ秒未満 + V8V8 のみ

ts.transpileModule() は型チェックをせず構文の変換だけなので、tsc のフルコンパイルよりずっと速く、100 行程度で 5〜20 ミリ秒です。構文エラーは reportDiagnostics の結果をユーザーに見せます。

Lua(MoonSharp) ​

MoonSharp は純粋 C# の Lua 実装(MIT、約 1 MB)で、ゲームの MOD 用に作られたためサンドボックスが設計の中心にあります。Lua VM は OS の API を持たず、io・os モジュールは組み込まないようにでき、.NET のオブジェクトは UserData.RegisterType<T>() で明示的に登録したものだけが見えます。タイムアウトも制御できます。

IronPython より構造的に安全で軽量です。ExpandoObject は IDictionary 経由になるのでラッパーが要り、既存の JavaScript とは互換がありません。

その他の言語 ​

言語評価の理由
PowerShellシステム管理のための言語で、Get-Content・Start-Process・Invoke-WebRequest・[System.IO.File]::ReadAllText() などが中核機能。ConstrainedLanguage モードでも基本のコマンドレットは使え、完全な制御には OS レベルの AppLocker・WDAC が要る。NoLanguage にすると変数の代入もできない
F# Scripting.NET CLR で直接動くので C# スクリプトと同じ課題。ExpandoObject へのアクセスに ? 演算子の拡張などが要り、フォームの値操作という用途と関数型の相性もよくない
VBScriptWSH(COM)ベースで .NET 10 では動かず、Microsoft が廃止を予告している
VB.NET ScriptRoslyn 上で C# スクリプトと同じ課題があり、利用者も少ない
Ruby(MRuby)IronRuby は 2011 年の 1.1.3 で止まり .NET 10 で動かないので、候補は C 実装の MRuby だけ。File・Process をビルド時に外せる点は優れるが、公式の NuGet が無く、プラットフォーム別のネイティブ DLL、P/Invoke と GCHandle によるホストオブジェクトの受け渡し、eval・require の制限が要る
PHP(PeachPie)PHP を IL にコンパイルして CLR で動かすので C# スクリプトと同じ課題に加え、file_get_contents・exec などの PHP 関数も使える。disable_functions 相当の制御はランタイムでは難しく、プロジェクトの更新も散発的
Groovy・Kotlin ScriptIKVM.NET で JVM を模倣する。Java の SecurityManager は Java 17 で非推奨、Java 21 で削除されており、サンドボックスを作る手段が無い。依存は 55 MB 以上で、.NET 10 での動作も確認されていない

関連ページ ​

変更履歴

第1版バックグラウンドサーバースクリプトの仕組みと、サーバースクリプトの他言語対応・DLL 実行・cron スケジュールの改修・設計メモを追加