v3.2.1 Streaming-Partials sind stabil

Templates, die zu einfachen Funktionen kompiliert werden

Verso macht aus einem Template beim Build eine JavaScript-Funktion. Kein virtuelles DOM, keine Laufzeitabhängigkeiten, kein Parser im Client — nur eine Funktion, die Daten nimmt und einen String zurückgibt.

7,4 kB minifiziert + gzip 0 Laufzeitabhängigkeiten MIT-Lizenz
greeting.vs
<!-- greeting.vs -->
<section class="cards">
  {{#each items as item, i}}
    <article data-index="{{i}}">
      <h3>{{item.title}}</h3>
      {{#if item.note}}
        <p>{{item.note | truncate: 120}}</p>
      {{/if}}
    </article>
  {{#else}}
    <p>Nothing here yet.</p>
  {{/each}}
</section>
Warum noch eine

Für alle, die HTML auf dem Server rendern

Verso entstand 2021 als 300-Zeilen-Datei in einer Content-Pipeline, die der String-Verkettung entwachsen war und kein Framework wollte. Es ist immer noch bewusst klein.

Kompiliert, nicht interpretiert

Jedes Template wird zu einer eigenständigen Funktion ohne Closure über die Engine. Eine Tabelle mit 2 000 Zeilen rendert auf einem Laptop von 2019 in 1,9 ms — etwa so lange, wie die String-Allokation selbst dauert.

Nichts darunter

Keine Abhängigkeiten zur Laufzeit und insgesamt drei Entwicklungsabhängigkeiten. Das ganze Paket besteht aus vier Dateien, und npm ls gibt nach einer frischen Installation eine einzige Zeile aus.

Streamt von Haus aus

renderToStream() gibt jeden Block der obersten Ebene aus, sobald er fertig ist — ein langsamer Datenbankaufruf verzögert so nur einen Abschnitt statt der ganzen Seite.

Escaped von Haus aus

Jede Interpolation wird HTML-escaped, solange Sie sich nicht ausdrücklich mit {{{ }}} dagegen entscheiden. Das Escaping berücksichtigt den Kontext von Attributen, URLs und Inline-Styles.

Lesbare Fehler

Kompilierfehler enthalten Template-Pfad, Zeile, Spalte und ein Caret unter dem fehlerhaften Token. Laufzeitfehler behalten den Template-Frame im Stacktrace.

Absichtlich stabil

Eine einzige inkompatible Änderung in vier Jahren, sechs Monate vorher angekündigt. Die 2.x-Linie bekommt noch bis Juni 2027 Sicherheitsfixes.

Installation

Dreißig Sekunden bis zum ersten Rendern

Terminal
# npm, pnpm or yarn — all the same package
$ npm install verso

# or try it without installing
$ npx verso render greeting.vs --data data.json

Benötigt Node.js 18 oder neuer. Der Browser-Build heißt verso/browser und enthält nur die Laufzeit-Helfer — der Compiler bleibt auf Ihrer Build-Maschine.

server.js
import { compileFile } from 'verso';

const page = await compileFile('./views/page.vs');

server.get('/', async (req, res) => {
  res.type('html').send(page({
    title: 'Release notes',
    items: await db.releases(20)
  }));
});
Zahlen

Gemessen, nicht behauptet

Benchmarks laufen auf Node 22.11, Apple M1, 50 Iterationen nach 20 Aufwärmdurchläufen. Die Suite liegt in bench/, und die Rohausgabe wird mit jedem Release eingecheckt.

1,9 msTabelle mit 2 000 Zeilen rendern
7,4 kBLaufzeit, minifiziert + gzip
0,4 msTemplate mit 120 Zeilen kompilieren
99,1 %Anweisungsabdeckung auf main
In drei Schritten

Wie aus einem Template eine Funktion wird

1 · Parsen

Ein Scanner mit einem einzigen Durchlauf erzeugt eine flache Token-Liste. Im Parser gibt es nirgends Backtracking regulärer Ausdrücke, also scheitert ein fehlerhaftes Template in linearer Zeit, statt hängenzubleiben.

2 · Aufbauen

Aus den Tokens wird ein kleiner Knotenbaum. Konstante Teilbäume — statisches HTML, literale Attribute — werden an dieser Stelle zu einzelnen String-Blöcken zusammengefaltet.

3 · Ausgeben

Der Baum wird als JavaScript-Quelltext ausgegeben und an new Function übergeben oder von der CLI auf die Platte geschrieben, wenn Sie ihn ansehen oder bündeln wollen.

Zur vollständigen API-Referenz →

Wer es nutzt

Leise, an ein paar Stellen

Verso ist kein populäres Projekt und will auch keins sein. Es wird etwa 40 000-mal im Monat heruntergeladen, meist von denselben Build-Pipelines, und das ist eine Größe, die wir ehrlich pflegen können.

Wenn Sie es gegen etwas Größeres abwägen: Nehmen Sie Verso, wenn Sie HTML auf dem Server rendern, die ganze Engine an einem Nachmittag lesen und keinen Abhängigkeitsbaum prüfen wollen. Nehmen Sie etwas anderes, wenn Sie clientseitige Reaktivität brauchen — Verso hat keine Meinung zum DOM und wird nie eine haben.