Wie sich Chakra auch außerhalb des Browser nutzen lässt

Chakra: Microsofts JavaScript Engine außerhalb des Browsers
Kommentare

JavaScript ist schon lange kein reines Browserthema mehr. Spätestens seit der Welle an Beliebtheit, die Node.js und der dabei zum Einsatz kommenden Google V8 JavaScript Engine entgegenschwappt, ist klargeworden, dass JavaScript auch außerhalb des Browsers von großer Bedeutung ist. Gleichzeitig kam mit Windows 10 Edge ein brandneuer Browser von Microsoft, bei dem sich in Sachen JavaScript eine Menge getan hat. Doch wie kann man von diesen Entwicklungen außerhalb der Browsergrenzen profitieren?

JavaScript (aka ECMAScript) ist die Programmiersprache des Webs. Durch die Standardisierung steht sie in allen praxisrelevanten Browsern auf allen nennenswerten Plattformen zur Verfügung. Auch wenn es da oder dort Kritikpunkte gibt, die breite Verfügbarkeit ist ein großes Argument für JavaScript.

Wofür JavaScript außerhalb des Browsers?

Die wenigsten Webseiten stehen aber für sich alleine. Die Mehrzahl setzt serverseitigen Code voraus, mit dem über REST, WebSockets oder Ähnlichem kommuniziert wird. Wenn man für das Web sowieso zum JavaScript-Profi werden muss, warum nicht dieses Wissen in anderen Bereichen wiederverwenden? Dieser Gedanke hat dazu geführt, dass JavaScript heute längst die Grenzen der Browser gesprengt hat. Andere Hosts betten eine JavaScript Engine ein und ermöglichen dadurch Scripting mit der Sprache des Webs. Hier zwei Beispiele:

  • Node.js bringt JavaScript auf den Server sowie auf IoT-Devices und erlaubt es außerdem, plattformunabhängige Kommandozeilenwerkzeuge (CLI, Command Line Interfaces) zu schreiben. Auch Microsoft hat in den letzten Jahren speziell bei der Cloud-Computing-Plattform Microsoft Azure Node.js ins Herz geschlossen, nutzt es selbst und bietet Entwicklerinnen und Entwicklern hervorragende Node.js-Unterstützung.
  • Mit DocumentDB hat Microsoft eine hoch skalierbare dokumentenorienterte NoSQL-Datenbank für Azure entwickelt. DocumentDB erlaubt serverseitige Logik geschrieben in JavaScript.

Viele kommerzielle Standardsoftwareprodukte bieten Endbenutzern die Möglichkeit, den vorhandenen Funktionsumfang zu erweitern. Die Popularität von JavaScript hat dazu geführt, dass dafür immer häufiger diese Sprache in Betracht gezogen wird. Eine moderne JavaScript Engine wie Chakra darf daher nicht mehr fest mit dem Browser als Host verbunden sein. Sie braucht ein allgemeines Hosting-API, mit dem JavaScript in beliebige Programme eingebunden werden kann. Bevor wir aber einen genaueren Blick auf das Hosting-API von Chakra werfen, ein paar Worte über die Entstehung von Chakra und den Stand der Dinge bei Edge und Windows 10.

Chakra-Entwicklung

Chakra ist der Codename der JavaScript Engine von Microsoft, die erstmals in Internet Explorer 9 das Licht der Welt erblickt hat. Mit Edge hat Microsoft einen harten Schnitt gemacht. Die alte Chakra Engine, die in IE9, 10 und 11 ihren Dienst tut, wurde eingefroren. Der Code wurde in ein neues Projekt übernommen (und natürlich stark überarbeitet, dazu später mehr) und die Strategie für Versionierung wurde grundlegend verändert. Microsoft beschloss, alte Zöpfe abzuschneiden und Schluss zu machen mit Dingen wie Document Modes und proprietären Erweiterungen wie ActiveXObjects. Außerdem wurde festgelegt, dass es in Zukunft unter Windows eine einzige, so genannte „living“ Version von Chakra geben sollte. Statt von IE zu IE neue Versionen oben drauf zu packen, wird eine Version aktualisiert. Dinge wie Innovation, kontinuierliche Verbesserung und Konformität zu Standards werden von jetzt an höher bewertet als Rückwärtskompatibilität um jeden Preis.

Chakra in IE11 vs. Chakra unter Windows 10

Auf jedem Windows-System, auf dem Internet Explorer 11 installiert ist, findet man die „alte“ Chakra Engine in der DLL jscript9.dll. Nachdem IE 11 unter Windows 10 aus Kompatibilitätsgründen ebenfalls installiert ist, ist jscript9.dll auch dort im Windows-Systemverzeichnis vorhanden. Gemeinsam mit mshtml.dll bildet sie das rückwärtskompatible Herzstück der Rendering und Execution Engine von Internet Explorer. Mit dem Edge-Browser ist Chakra übersiedelt. Man findet sie gemeinsam mit der Edge HTML Engine edgehtml.dll im Windows-Systemverzeichnet als chakra.dll. Zukünftige Erweiterungen und Verbesserungen werden nur noch hier geschehen.

Als Entwickler hat man unter Windows 10 die Wahl zwischen alter und neuer Welt. Frühere Betriebssysteme werden nicht mehr in den Genuss von Edge und der neuen Chakra-Version kommen. Insofern empfiehlt es sich auf jeden Fall, neue Anwendungen, die Chakra verwenden und Windows 10 voraussetzen können, auf der „living“ Edge-Version von Chakra aufzubauen. Zum Glück ist – wie wir gleich sehen werden – selbst eine parallele Unterstützung beider Versionen der Microsoft JavaScript Engine mit überschaubarem Aufwand denkbar. 

Schnell und überall: Datenzugriff mit Entity Framework Core 2.0

Dr. Holger Schwichtenberg (www.IT-Visions.de/5Minds IT-Solutions)

C# 7.0 – Neues im Detail

Christian Nagel (CN innovation)

Das Chakra-Hosting-API

Unter Windows 8 hat Microsoft mit Internet Explorer 11 ein öffentliches Hosting-API namens JavaScript Runtime API (kurz JSRT) herausgebracht. Mit ihm konnten Entwicklerinnen und Entwickler die Chakra Engine in eigenen Programmen einbetten und dadurch JavaScript-Skripte ausführen. Mit Edge und Windows 10 wurde JSRT deutlich aufgewertet. Es ist jetzt möglich, JSRT nicht nur in klassischen Win32-Anwendungen zu verwenden. Die „living“ Edge-Version von Chakra kann auch in Universal-Windows-Plattform-(UWP-)Apps und damit von Phone über PC bis zur Xbox verwendet werden. Die JavaScript-Skripte, die so betrieben werden, können, sofern es die Hostanwendung erlaubt, auf die nativen UWP-APIs zugreifen. Dass die Skripte dabei die neuesten JavaScript-Features wie ECMAScript-2015-Unterstützung verwenden können, versteht sich von selbst. Wenn man sich das Leben in UWP-Apps erleichtern will, kann man einen Blick auf ChakraBridge werfen. Es handelt sich um eine fertige WinRT-Komponente für das Hosting der Chakra Engine unter UWP.

Das Chakra-Hosting-API ist eine native Windows DLL. Die Dokumentation der angebotenen Funktionen findet man in der MSDN Library. Als .NET-Entwicklerin oder Entwickler braucht man also P/Invoke (DllImport-Attribut), um JSRT von C# aus verwenden zu können. Zum Glück gibt es jedoch ein Open-Source-Projekt auf GitHub und verschiedene Beispiele von Microsoft, auf denen man aufbauen kann. Man bekommt von ihnen leicht verwendbare C#-Klassen, die im Hintergrund-JSRT aufrufen. In diesem Artikel werde ich Codebeispiele zeigen, die auf der Win32/Edge-Version des Microsoft-Beispiels auf GitHub aufbauen. Entwicklerinnen und Entwickler, die sowieso C++ statt C# verwenden, können natürlich JSRT direkt ohne den Umweg über P/Invoke nutzen (das GitHub-Repository enthält auch dafür Codebeispiele).

Struktur des Chakra API

Der erste Schritt beim Hosting von Chakra ist das Erstellen der Runtime (JsCreateRuntime-Funktion). Jede Runtime hat ihren eigenen Heap, Just-in-Time-(JIT-)Compiler-Thread und Garbage-Collector-(GC-)Thread.

Innerhalb der Runtime erstellt man als Nächstes einen oder mehrere Execution Contexts (JsCreateContext-Funktion). Jeder Execution Context hat sein eigenes, globales JavaScript-Objekt. Mehrere Execution Contexts können sich also eine Runtime (d. h. einen JIT-Compiler, einen GC etc.) teilen, können aber keine Daten direkt austauschen. Wenn Execution Contexts kommunizieren wollen, muss das über den Host geschehen. Über den Execution Context kann der Host dem Skript Objekte, Funktionen etc. zur Verfügung stellen. Auf diese Weise greift das Skript auf Funktionalität zu, die der jeweilige Host anbieten möchte.

Beispiel

Listing 1 soll die Struktur eines einfachen Hostprogramms zeigen (Abb. 1). Es setzt das Vorhandensein der Hilfsklassen aus dem erwähnten Microsoft-Beispiel voraus. Achten Sie auf die Kommentare, die im Listing enthalten sind. Sie erklären, was Schritt für Schritt gemacht wird.

public static void Main(string[] arguments)
{
  // Anlegen der JSRT Runtime
  // (verwendet im Hintergrund JSRT-Funktion JsCreateRuntime)
  using (JavaScriptRuntime runtime = JavaScriptRuntime.Create())
  {
    // Anlegen des Execution Context
    // (verwendet JsCreateContext)
    var context = runtime.CreateContext();

    // Execution Context für den aktuellen Thread festlegen
    // (verwendet JsSetCurrentContext und JsGetCurrentContext)
    using (new JavaScriptContext.Scope(context))
    {
      // Anlegen eines JavaScript Host Object
      // (verwendet JsCreateObject)
      var hostObject = JavaScriptValue.CreateObject();

      // Host Object am JavaScript Global Object unter "host" zugaenglich machen
      // (verwendet JsGetPropertyIdFromName, JsGetGlobalObject und JsSetProperty)
      var hostPropertyId = JavaScriptPropertyId.FromString("host");
      var globalObject = JavaScriptValue.GlobalObject;
      globalObject.SetProperty(hostPropertyId, hostObject, true);

      // Methode "echo" am Host Object zugaenglich machen
      // (verwendet JsCreateFunction)
      var methodPropertyId = JavaScriptPropertyId.FromString("echo");
      var function = JavaScriptValue.CreateFunction(echoDelegate, IntPtr.Zero);
      hostObject.SetProperty(methodPropertyId, function, true);

      const string script = @"
        host.echo('Hello World!');
        throw new Error('Something bad happened');
        42.0;";

      JavaScriptValue result;
      try
      {
        // Skript ausfuehren
        // (verwendet JsRunScript)
        result = JavaScriptContext.RunScript(script, JavaScriptSourceContext.None, "MyScript.js");

        // Ergebnis des Skripts verarbeiten
        var numberResult = result.ConvertToNumber();
        var doubleResult = numberResult.ToDouble();
        Console.WriteLine($"The result was {doubleResult}");
      }
      catch (JavaScriptScriptException e)
      {
        // JavaScript-Fehlermeldung ermitteln und ausgeben
        var messageName = JavaScriptPropertyId.FromString("message");
        var messageValue = e.Error.GetProperty(messageName);
        var message = messageValue.ToString();
        Console.Error.WriteLine($"chakrahost: exception: {message}");
      }
      catch (Exception e)
      {
        Console.Error.WriteLine("chakrahost: failed to run script: {0}", e.Message);
      }
    }
  }
}
Abb. 1: Ausgabe des Beispielprogramms aus Listing 1

Abb. 1: Ausgabe des Beispielprogramms aus Listing 1

Falls Sie das Beispiel selbst probieren möchten, achten Sie darauf, dass Sie aus dem Beispiel die „living“ Edge-Version von Chakra, also die chakra.dll, verwenden. Das GitHub Repository enthält auch Code, der mit der alten Chakra-Version, also mit jscript9.dll, arbeitet. Die beiden Varianten unterscheiden sich im Wesentlichen dadurch, dass die DllImport-Attribute einmal auf jscript9.dll und im anderen Fall auf chakra.dll zeigen. Außerdem haben sich die Aufrufsignatur einiger weniger Funktionen der JSRT verändert. Der MSDN Artikel enthält eine komplette Aufzählung aller Änderungen. Diese Unterschiede sind es auch, die beachtet werden müssen, wenn man Code schreiben will, der sowohl mit der alten als auch der neuen JSRT-Version funktionieren soll. Wenn Sie die Methoden nicht anpassen, werden Sie in C#-Laufzeitfehler erhalten, da der Stack durch die falschen Aufrufsignaturen korrupt wird. C++ würde bei Verwendung der entsprechenden Header-Dateien bereits zum Kompilierzeitpunkt Fehler ausgeben.

Zugriff auf UWP-API

Verwendet man chakra.dll unter Windows 10, kann man im Skript wie erwähnt auf das API der Universal Windows Platform zugreifen. Beachten Sie, dass der Zugriff auf die UWP-APIs auch in Win32-Anwendungen funktioniert, sofern diese unter Windows 10 ausgeführt werden. Der Chakra-Host muss mithilfe der JsProjectWinRTNamespace-Funktion den Zugriff auf die gewünschten Namespaces erlauben. Listing 2 zeigt, wie das gemacht wird. Achten Sie speziell auf den JavaScript-Code im Beispiel. Sie sehen, dass das Skript mithilfe des UWP-API die aktuelle Zeitzone und das aktuelle Datum ermittelt und ausgibt. Mehr Arbeit ist notwendig, wenn man den Aufruf asynchroner Funktionen ermöglichen möchte. Ein Beispiel dafür in C++ finden Sie unter im Microsoft Developer Network.

[...]
const string script = @"
  var calendar = Windows.Globalization.Calendar();
  host.echo(calendar.getTimeZone());
  host.echo(calendar.getDateTime());

  42.0;
";
[...]
Native.JsProjectWinRTNamespace("Windows.Globalization");
result = JavaScriptContext.RunScript([...]);
// Will display:
//   America/Los_Angeles
//   Sun Nov 01 2015 10:18:14 GMT-0800 (Pacific Standard Time)
//   The result was 42

Node.js mit Chakra: Anwendungsbeispiel

Ein größeres Beispiel für einen Chakra-Host außerhalb des Browsers ist das Node.js+Chakra-Projekt von Microsoft, das Open Source auf GitHub zur Verfügung steht. Es handelt sich dabei um einen experimentellen Fork des Node.js-Projekts, bei dem Microsoft die V8 JavaScript Engine von Google durch Chakra ersetzt. Erstellt wurde diese Node.js-Variante speziell für IoT-Varianten von Windows, die auf der ARM-Plattform ausgeführt werden.

Microsoft hat betont, dass es nicht die Absicht ist, das Node.js-Projekt an sich zu reißen oder einen Node.js-Klon zu erstellen. Ziel ist es, Node.js so umzubauen, dass man mit verschiedenen JavaScript-Runtimes arbeiten kann. Microsoft hat berichtet, dass Gespräche mit dem Node.js-Team stattfinden, um einen Pull Request vorzubereiten, mit dem die Änderungen zur Austauschbarkeit der JavaScript-Runtime ins Node.js Repository integriert werden. Ein Zeitplan war zum Zeitpunkt des Schreibens dieses Artikels noch nicht bekannt. Bis dahin muss man den Quellcode von GitHub herunterladen und selbst kompilieren (Anleitung ist auf GitHub enthalten), wenn man die Kombination aus Node.js und Chakra nutzen möchte. Fertige Installer für Windows gibt es noch nicht.

Unabhängig davon, ob diese Variante von Node.js mit Chakra in der Zukunft Praxisrelevanz haben wird, ist es auf jeden Fall ein gutes Beispiel dafür, wie weit man mit JSRT gehen kann.

Warum überhaupt JSRT, wenn es V8 gibt?

Wir haben gesehen, dass das Hosting von Chakra nicht sonderlich schwierig ist. Die Möglichkeit, Scripting in eigene Win32- oder UWP-Apps einzubauen, hat inhaltlich für viele Anwendungen Charme. Warum aber zu Chakra greifen und nicht gleich den Vorreiter, also V8 von Google, verwenden? Die Frage ist berechtigt, da es einige Nachteile gibt. Hier einige Beispiele:

  • V8 gibt es länger als JSRT, und das Ökosystem an Tools ist daher reichhaltiger.
  • V8 ist Open Source, Chakra Stand heute nicht.
  • V8 ist plattformunabhängig, Chakra auf die neuesten Versionen von Windows beschränkt.
  • Microsoft hat sich in der Vergangenheit nicht immer mit Ruhm bekleckert, wenn es um Webtechnologien ging.
  • Node.js ist auf V8 schon lange verfügbar, die Version mit Chakra ist erst als experimentelle Variante vorhanden.

Trotzdem lohnt es sich aus meiner Sicht, Chakra und JSRT in Betracht zu ziehen, sofern man Windows als Zielplattform im Auge hat. Hier einige Argumente, die dafür sprechen:

  • Mit dem Edge-Browser ist Microsoft ein guter Wurf gelungen. Die neue Chakra Engine ist vielen Tests und Benchmarks zufolge im Moment die schnellste am Markt. Channel 9 enthält ein empfehlenswertes Video, indem die Optimierungen und Verbesserungen der Chakra Engine unter Windows 10 im Detail erklärt werden.
  • Microsoft hat versprochen, sich mit Edge und Chakra auch in Zukunft so exakt wie möglich an Standards zu halten. Die Zeiten Microsoft-spezifischer Erweiterungen sind vorbei.
  • Chakra ist, was ECMAScript-Weiterentwicklungen betrifft, sehr gut aufgestellt.
  • Will man UWP-Apps mit JavaScript-Fähigkeiten ausstatten, führt kaum ein Weg an Chakra und JSRT vorbei, da die Brücken von JavaScript zum UWP-API einfach und gut funktionieren.
  • Auf IoT-Geräten, die unter Windows 10 IoT Core laufen, sind die vorhandenen Ressourcen beschränkt. Die Chakra Engine ist von Haus aus vorhanden, während V8 mitgebracht werden muss. Hinzu kommt, dass Node.js mit V8 unter Windows on ARM (WoA) nicht funktioniert, Node.js mit Chakra jedoch schon.

Zusammenfassung

Scripting ist nicht nur im Browser interessant. Standardprogramme werden aufgewertet, wenn sie es Benutzern erlauben, den Funktionsumfang über Skripte zu erweitern, Routinetätigkeiten zu automatisieren, individuelle Schnittstellen zu implementieren u. v. m. Mit JSRT hat Microsoft ein Hosting-API veröffentlicht, mit dem es relativ einfach ist, die Chakra Engine zu hosten. Leider gibt es für dase API von Microsoft keine fertige .NET-Bibliothek. Open-Source-Projekte und Beispiele von Microsoft füllen diese Lücke aber bis zu einem gewissen Grad.

Als Entwicklerin und Entwickler hat man die Wahl, auf V8 oder Chakra zu setzen. In manchen Situationen fällt die Entscheidung nicht schwer. Plattformunabhängigkeit notwendig? Dann steht die Entscheidung für V8 fest. Soll es eine Universal-Windows-Platform-App werden? Unbedingt zu JSRT und Chakra greifen. Dazwischen gibt es immer Argumente für und wider. Hoffentlich hat dieser Artikel neue Möglichkeiten aufgezeigt und bietet eine Entscheidungshilfe für Ihr konkretes Projekt.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -