Das SSG bauen, das ich mir schon immer gewünscht habe: Ein Sandwich aus 11ty, Vite und JAM

Veröffentlicht: 2022-03-10
Kurze Zusammenfassung ↬ Im Januar 2020 machte sich Ben Holmes daran, das zu tun, was fast jeder Webentwickler jedes Jahr tut: seine persönliche Website neu zu erstellen. In diesem Artikel erzählt er seine Geschichte, wie er begann, seine eigene Build-Pipeline vom absoluten Nullpunkt aus zu bauen und Slinkity zu erschaffen.

Ich weiß nicht, wie es Ihnen geht, aber ich war überwältigt von all den Webentwicklungstools, die wir heutzutage haben. Egal, ob Sie Markdown, einfaches HTML, React, Vue, Svelte, Pug-Vorlagen, Handlebars, Vibranium mögen – Sie können es wahrscheinlich mit einigen CMS-Daten mischen und einen schönen statischen Website-Cocktail erhalten.

Ich werde Ihnen nicht sagen, nach welchen UI-Entwicklungstools Sie greifen sollten, da sie alle großartig sind – abhängig von den Anforderungen Ihres Projekts. In diesem Beitrag geht es darum, den perfekten Static-Site-Generator für jeden Anlass zu finden; etwas, mit dem wir JS-lose Vorlagen wie Markdown verwenden können, um zu beginnen, und nach Bedarf „Inseln“ komponentengesteuerter Interaktivität einbringen können.

Ich destilliere hier die Erkenntnisse eines Jahres in einem einzigen Beitrag. Wir werden nicht nur über Code sprechen (auch bekannt als Duct Taping 11ty und Vite zusammen), sondern wir werden auch untersuchen, warum dieser Ansatz so universell für Jamstack-Probleme ist. Wir werden ansprechen:

  • Zwei Ansätze zur Generierung statischer Sites und warum wir diese Lücke schließen sollten;
  • Wo sich Vorlagensprachen wie Pug und Nunjucks immer noch als nützlich erweisen;
  • Wenn Komponenten-Frameworks wie React oder Svelte ins Spiel kommen sollen;
  • Wie uns die neue Hot-Reloading-Welt von Vite hilft, JS-Interaktivität mit fast null Konfigurationen in unser HTML zu bringen;
  • Wie dies die Datenkaskade von 11ty ergänzt und CMS-Daten in jedes beliebige Komponenten-Framework oder jede gewünschte HTML-Vorlage bringt.

Also, ohne weitere Umschweife, hier ist meine Geschichte von schrecklichen Build-Skripten, Bundler-Durchbrüchen und Spaghetti-Code-Klebeband, das mir (schließlich) das SSG gab, das ich immer wollte: ein 11ty, Vite and Jam-Sandwich namens Slinkity!

Eine große Kluft bei der Generierung statischer Websites

Bevor ich eintauche, möchte ich diskutieren, was ich zwei „Lager“ bei der Generierung statischer Sites nennen möchte.

Im ersten Camp haben wir den „einfachen“ Static-Site-Generator. Diese Tools bringen keine JavaScript-Bundles, Single-Page-Apps und andere Schlagworte, die wir erwarten. Sie bringen einfach die Jamstack-Grundlagen auf den Punkt: Ziehen Sie Daten aus dem JSON-Blob des CMS, das Sie bevorzugen, und schieben Sie diese Daten in einfache HTML-Vorlagen + CSS. Tools wie Jekyll, Hugo und 11ty dominieren dieses Lager und lassen Sie ein Verzeichnis mit Markdown- und Liquid-Dateien in eine voll funktionsfähige Website verwandeln. Hauptvorteile:

  • Flache Lernkurve
    Wenn Sie sich mit HTML auskennen, können Sie loslegen!
  • Schnelle Bauzeiten
    Wir verarbeiten nichts Komplexes, sodass jede Route im Handumdrehen erstellt wird.
  • Sofortige Zeit für Interaktivität
    Auf dem Client muss kein (oder nur sehr wenig) JavaScript analysiert werden.

Jetzt im zweiten Lager haben wir den „dynamischen“ statischen Site-Generator. Diese führen Komponenten-Frameworks wie React, Vue und Svelte ein, um Ihrem Jamstack Interaktivität zu verleihen. Diese erfüllen das gleiche Kernversprechen der Kombination von CMS-Daten mit den Routen Ihrer Website zur Erstellungszeit. Hauptvorteile:

  • Gebaut für Interaktivität
    Benötigen Sie ein animiertes Bildkarussell? Mehrstufiges Formular? Fügen Sie einfach ein komponentenbasiertes Nugget aus HTML, CSS und JS hinzu.
  • Staatliche Verwaltung
    Etwas wie React Context von Svelte Stores ermöglicht einen nahtlosen Datenaustausch zwischen Routen. Zum Beispiel der Warenkorb auf Ihrer E-Commerce-Website.

Beide Ansätze haben unterschiedliche Vorteile. Aber was ist, wenn Sie sich für ein SSG aus dem ersten Lager wie Jekyll entscheiden, nur um nach sechs Monaten Ihres Projekts festzustellen, dass Sie eine gewisse Interaktivität der Komponenten benötigen? Oder wählen Sie etwas wie NextJS für diese leistungsstarken Komponenten, nur um mit der Lernkurve von React zu kämpfen, oder unnötige KB von JavaScript in einem statischen Blogbeitrag?

Nur wenige Projekte passen meiner Meinung nach direkt in das eine oder andere Lager. Sie existieren in einem breiten Spektrum und bevorzugen ständig neue Feature-Sets, wenn sich die Anforderungen eines Projekts weiterentwickeln. Wie finden wir also eine Lösung, die es uns ermöglicht, mit den einfachen Tools des ersten Lagers zu beginnen und nach und nach Funktionen aus dem zweiten Lager hinzuzufügen, wenn wir sie brauchen?

Nun, lassen Sie uns ein bisschen durch meine Lernreise gehen.

Hinweis: Wenn Sie bereits von statischen Vorlagen mit 11ty überzeugt sind, um Ihre statischen Websites zu erstellen, können Sie sich gerne die saftige Code-Komplettlösung ansehen.

Mehr nach dem Sprung! Lesen Sie unten weiter ↓

Von Komponenten zu Vorlagen und Web-APIs

Im Januar 2020 machte ich mich daran, das zu tun, was fast jeder Webentwickler jedes Jahr tut: meine persönliche Website neu zu erstellen. Aber dieses Mal sollte es anders sein. Ich habe mich selbst herausgefordert, eine Website mit auf dem Rücken gefesselten Händen zu bauen, keine Frameworks oder Pipelines erlaubt!

Das war keine einfache Aufgabe als React-Anhänger. Aber mit erhobenem Kopf machte ich mich daran, meine eigene Build-Pipeline vom absoluten Nullpunkt aus zu bauen. Es gibt eine Menge schlecht geschriebenen Codes, den ich von v1 meiner persönlichen Seite teilen könnte … aber ich lasse Sie auf diese README klicken, wenn Sie so mutig sind. Stattdessen möchte ich mich auf die höherwertigen Imbissbuden konzentrieren, die ich gelernt habe, als ich mich von meinen JS-Guild Pleasures verhungerte.

Vorlagen gehen viel weiter, als Sie vielleicht denken

Ich kam zu diesem Projekt als genesender JavaScript-Junkie. Es gibt ein paar Anforderungen im Zusammenhang mit statischen Websites, die ich gerne mit komponentenbasierten Frameworks erfüllt habe:

  1. Wir möchten meine Website in wiederverwendbare UI-Komponenten aufteilen , die JS-Objekte als Parameter (auch bekannt als „Props“) akzeptieren können.
  2. Wir müssen zur Bauzeit einige Informationen abrufen, um sie in eine Produktionsstätte zu stecken.
  3. Wir müssen eine Reihe von URL-Routen entweder aus einem Dateiverzeichnis oder aus einem dicken JSON-Inhaltsobjekt generieren .

Liste aus diesem Beitrag in meinem persönlichen Blog.

Aber Sie haben vielleicht bemerkt … keines davon benötigt wirklich clientseitiges JavaScript. Komponenten-Frameworks wie React werden hauptsächlich entwickelt, um Probleme der Zustandsverwaltung zu bewältigen, wie die Facebook-Webanwendung, die React überhaupt erst inspiriert hat. Wenn Sie Ihre Website nur in mundgerechte Komponenten oder Designsystemelemente aufteilen, funktionieren Vorlagen wie Pug auch ziemlich gut!

Nehmen Sie zum Beispiel diese Navigationsleiste. In Pug können wir ein „Mixin“ definieren, das Daten als Requisiten erhält:

 // nav-mixins.pug mixin NavBar(links) // pug's version of a for loop each link in links a(href=link.href) link.text

Dann können wir dieses Mixin überall auf unserer Website anwenden.

 // index.pug // kinda like an ESM "import" include nav-mixins.pug html body +NavBar(navLinksPassedByJS) main h1 Welcome to my pug playground

Wenn wir diese Datei mit einigen Daten „rendern“, erhalten wir eine schöne index.html , die wir unseren Benutzern zur Verfügung stellen können.

 const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] }) // use the NodeJS filesystem helpers to write a file to our build await writeFile('build/index.html', html)

Sicher, das gibt keine Feinheiten wie bereichsbezogenes CSS für Ihre Mixins oder zustandsbehaftetes JavaScript, wo Sie es wollen. Aber es hat einige sehr starke Vorteile gegenüber etwas wie React:

  1. Wir brauchen keine ausgefallenen Bundler, die wir nicht verstehen.
    Wir haben diesen pug.render -Aufruf gerade von Hand geschrieben und haben bereits die erste Route einer einsatzbereiten Site.
  2. Wir versenden kein JavaScript an den Endbenutzer.
    Die Verwendung von React bedeutet oft, dass eine große alte Laufzeitumgebung für die Ausführung der Browser der Benutzer gesendet wird. Durch den Aufruf einer Funktion wie pug.render zur Build-Zeit behalten wir alle JS auf unserer Seite, während wir am Ende eine saubere .html -Datei senden.

Aus diesem Grund denke ich, dass Vorlagen eine großartige „Basis“ für statische Websites sind. Trotzdem wäre es schön, nach Komponenten-Frameworks zu greifen, wo wir wirklich davon profitieren. Dazu später mehr.

Empfohlene Lektüre : So erstellen Sie bessere Winkelvorlagen mit Pug von Zara Cooper

Sie brauchen kein Framework, um Single-Page-Apps zu erstellen

Wo ich gerade dabei war, wollte ich auch ein paar sexy Seitenübergänge auf meiner Seite. Aber wie schaffen wir so etwas ohne Rahmen?

Crossfade mit vertikalem Wipe-Übergang
Crossfade mit vertikalem Wipe-Übergang. (Große Vorschau)

Nun, wir können dies nicht tun, wenn jede Seite eine eigene .html -Datei ist. Der gesamte Browser wird aktualisiert, wenn wir von einer HTML-Datei zur anderen springen, sodass wir diesen netten Überblendungseffekt nicht haben können (da wir beide Seiten kurz übereinander anzeigen würden).

Wir brauchen eine Möglichkeit, den HTML- und CSS-Code für den Ort, zu dem wir navigieren, „abzurufen“ und ihn mithilfe von JavaScript in der Ansicht zu animieren. Das klingt nach einem Job für Single-Page-Apps! Ich habe dafür ein einfaches Browser-API-Medley verwendet:

  1. Fangen Sie alle Ihre Link-Klicks mit einem Ereignis-Listener ab.
  2. fetch API : Rufen Sie alle Ressourcen für die Seite ab, die Sie besuchen möchten, und holen Sie sich das Bit, das ich animieren möchte, ins Blickfeld: den Inhalt außerhalb der Navigationsleiste (der während der Animation stationär bleiben soll).
  3. API für Webanimationen : Animieren Sie den neuen Inhalt als Keyframe zur Ansicht.
  4. history API : Ändern Sie die in der URL-Leiste Ihres Browsers angezeigte Route mit window.history.pushState({}, 'new-route') . Andernfalls sieht es so aus, als hätten Sie die vorherige Seite nie verlassen!

Zur Verdeutlichung hier eine visuelle Veranschaulichung dieses Single-Page-App-Konzepts mit einem einfachen Suchen-und-Ersetzen ( Quellartikel ):

Kundenseitiger Schritt-für-Schritt-Routing-Prozess: 1. Medium-Rare-Hamburger wird zurückgegeben, 2. Wir fordern einen durchgebratenen Burger mit der Abruf-API an, 3. Wir massieren die Antwort, 4. Wir pflücken das „Pastetchen“-Element heraus und wenden es an zu unserer aktuellen Seite.
Kundenseitiger Schritt-für-Schritt-Routing-Prozess: 1. Medium-Rare-Hamburger wird zurückgegeben, 2. Wir fordern einen durchgebratenen Burger mit der Abruf-API an, 3. Wir massieren die Antwort, 4. Wir pflücken das „Pastetchen“-Element heraus und wenden es an zu unserer aktuellen Seite. (Große Vorschau)

Hinweis : Sie können den Quellcode auch auf meiner persönlichen Website besuchen.

Sicher, einige Paarungen von React et al. Und Ihrer bevorzugten Animationsbibliothek können dies tun. Aber für einen so einfachen Anwendungsfall wie einen Fade-Übergang … sind Web-APIs für sich genommen verdammt leistungsfähig. Und wenn Sie robustere Seitenübergänge bei statischen Vorlagen wie Pug oder einfachem HTML wünschen, werden Ihnen Bibliotheken wie Swup gute Dienste leisten.

Was 11ty auf den Tisch brachte

Ich fühlte mich zu diesem Zeitpunkt ziemlich gut mit meiner kleinen SSG. Sicher, es konnte zur Build-Zeit keine CMS-Daten abrufen und unterstützte keine unterschiedlichen Layouts nach Seite oder Verzeichnis, optimierte meine Bilder nicht und hatte keine inkrementellen Builds.

Okay, ich brauche vielleicht etwas Hilfe.

Angesichts all meiner Erkenntnisse aus v1 dachte ich, ich hätte mir das Recht verdient, die Regel „keine Build-Pipelines von Drittanbietern“ fallen zu lassen und nach vorhandenen Tools zu greifen. Es stellt sich heraus, dass 11ty eine Fundgrube an Funktionen hat, die ich brauche!

  • Datenabruf zur Buildtime mit .11ydata.js Dateien;
  • Globale Daten, die für alle meine Vorlagen aus einem _data Ordner verfügbar sind;
  • Heißes Neuladen während der Entwicklung mit Browsersync;
  • Unterstützung für ausgefallene HTML-Transformationen;
  • …und unzählige andere Leckereien.

Wenn Sie Bare-Bones-SSGs wie Jekyll oder Hugo ausprobiert haben, sollten Sie eine ziemlich gute Vorstellung davon haben, wie 11ty funktioniert. Einziger Unterschied? 11ty verwendet durch und durch JavaScript.

11ty unterstützt im Grunde jede verfügbare Vorlagenbibliothek, daher war es glücklich, alle meine Pug-Seiten in .html Routen zu rendern. Die Layout-Verkettungsoption hat mir auch bei der Einrichtung meiner Faux-Single-Page-App geholfen. Ich brauchte nur ein einziges script für alle meine Routen und ein „globales“ Layout, um dieses Skript zu importieren:

 // _includes/base-layout.html <html> <body> <!--load every page's content between some body tags--> {{ content }} <!--and apply the script tag just below this--> <script src="main.js"></script> </body> </html> // random-blog-post.pug --- layout: base-layout --- article h2 Welcome to my blog p Have you heard the story of Darth Plagueis the Wise?

Solange diese main.js all das von uns untersuchte Link-Abfangen durchführt, haben wir Seitenübergänge!

Oh, und die Datenkaskade

11ty hat also geholfen, meinen gesamten Spaghetti-Code von v1 zu bereinigen. Aber es brachte ein weiteres wichtiges Stück: eine saubere API, um Daten in meine Layouts zu laden. Dies ist das A und O des Jamstack-Ansatzes. Anstatt Daten im Browser mit JavaScript + DOM-Manipulation abzurufen, können Sie:

  1. Rufen Sie Daten zur Build-Zeit mit Node ab.
    Dies könnte ein Aufruf an eine externe API, ein lokaler JSON- oder YAML-Import oder sogar der Inhalt anderer Routen auf Ihrer Website sein (stellen Sie sich vor, Sie aktualisieren ein Inhaltsverzeichnis, wenn neue Routen hinzugefügt werden ).
  2. Fügen Sie diese Daten in Ihre Routen ein. Erinnern Sie sich an die .render Funktion, die wir zuvor geschrieben haben:
 const html = pug.render('/index.pug', { navLinksPassedByJS: [ { href: '/', text: 'Home' }, { href: '/adopt', text: 'Adopt a Pug' } ] })

…aber anstatt jedes Mal pug.render mit unseren Daten aufzurufen, lassen wir 11ty dies hinter den Kulissen erledigen.

Sicher, ich hatte nicht viele Daten für meine persönliche Seite. Aber es fühlte sich großartig an, eine .yaml -Datei für alle meine persönlichen Projekte zu erstellen:

 # _data/works.yaml - title: Bits of Good Homepage hash: bog-homepage links: - href: https://bitsofgood.org text: Explore the live site - href: https://github.com/GTBitsOfGood/bog-web text: Scour the Svelt-ified codebase timeframe: May 2019 - present tags: - JAMstack - SvelteJS - title: Dolphin Audio Visualizer ...

Und greifen Sie über jede Vorlage auf diese Daten zu:

 // home.pug .project-carousel each work in works h3 #{title} p #{timeframe} each tag in tags ...

Aus der Welt des „Clientside Rendering“ mit create-react-app kommend, war dies eine ziemlich große Offenbarung. Kein Senden von API-Schlüsseln oder großen JSON-Blobs mehr an den Browser.

Ich habe auch einige Extras für das Abrufen von JavaScript und Animationsverbesserungen gegenüber Version 1 meiner Website hinzugefügt. Wenn Sie neugierig sind, hier ist, wo mein README an dieser Stelle stand.

Ich war an diesem Punkt glücklich, aber etwas fehlte

Ich bin überraschend weit gegangen, indem ich JS-basierte Komponenten aufgegeben und Vorlagen (mit animierten Seitenübergängen zum Booten) angenommen habe. Aber ich weiß, dass dies meine Bedürfnisse nicht für immer befriedigen wird. Erinnerst du dich an die große Kluft, mit der ich uns gestartet habe? Nun, es gibt eindeutig immer noch diese Schlucht zwischen meinem Build-Setup (fest in Lager Nr. 1) und dem Hafen der JS-ifizierten Interaktivität (The Next, SvelteKit und mehr von Lager Nr. 2). Angenommen, ich möchte hinzufügen:

  • ein Popup-Modal mit einem Öffnen/Schließen-Umschalter,
  • ein komponentenbasiertes Designsystem wie Material UI, komplett mit Scope-Styling,
  • ein komplexes mehrstufiges Formular, das möglicherweise von einer Zustandsmaschine gesteuert wird.

Wenn Sie ein reiner JS-Purist sind, haben Sie wahrscheinlich rahmenlose Antworten auf all diese Anwendungsfälle. Aber es gibt einen Grund, warum JQuery nicht mehr die Norm ist! Das Erstellen diskreter, leicht lesbarer HTML-Komponenten, bereichsbezogener Stile und Teile von JavaScript-„Zustands“-Variablen hat etwas Reizvolles. React, Vue, Svelte usw. bieten so viele Feinheiten zum Debuggen und Testen, dass eine reine DOM-Manipulation nicht ganz mithalten kann.

Hier also meine Millionen-Dollar-Frage:

Können wir zu Beginn einfache HTML-Vorlagen verwenden und nach und nach React/Vue/Svelte-Komponenten dort hinzufügen, wo wir sie haben möchten?

Die Antwort ist ja . Lass es uns versuchen.

11ty + Vite: Ein himmlisches Match ️

Hier ist der Traum, den ich mir hier vorstelle. Überall dort, wo ich etwas Interaktives einfügen möchte, möchte ich ein kleines Flag in meiner Vorlage hinterlassen, um „hier X React-Komponente zu platzieren“. Dies könnte die Shortcode-Syntax sein, die 11ty unterstützt:

 # Super interesting programming tutorial Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example! {% react './components/FancyLiveDemo.jsx' %}

Aber denken Sie daran, dass das einteilige 11ty (absichtlich) vermeidet: eine Möglichkeit, all Ihr JavaScript zu bündeln. Wenn Sie aus der OG-Gilde des Bündelns kommen, springt Ihr Gehirn hier wahrscheinlich zum Erstellen von Webpack-, Rollup- oder Babel-Prozessen. Erstellen Sie eine große alte Einstiegspunktdatei und geben Sie schönen optimierten Code aus, richtig?

Nun ja, aber das kann ziemlich kompliziert werden. Wenn wir zum Beispiel React-Komponenten verwenden, brauchen wir wahrscheinlich einige Loader für JSX, einen ausgefallenen Babel-Prozess, um alles zu transformieren, einen Interpreter für SASS- und CSS-Modulimporte, etwas , das beim Live-Neuladen hilft, und so weiter.

Wenn es nur ein Tool gäbe, das unsere .jsx Dateien sehen und genau wissen könnte, was damit zu tun ist.

Geben Sie ein: Vite

Vite ist in letzter Zeit das Stadtgespräch. Es soll das All-in-One-Tool zum Erstellen von fast allem in JavaScript sein. Hier ist ein Beispiel, das Sie zu Hause ausprobieren können. Lassen Sie uns irgendwo auf unserem Computer ein leeres Verzeichnis erstellen und einige Abhängigkeiten installieren:

 npm init -y # Make a new package.json with defaults set npm i vite react react-dom # Grab Vite + some dependencies to use React

Jetzt können wir eine index.html -Datei erstellen, die als „Einstiegspunkt“ für unsere App dient. Wir halten es ganz einfach:

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>Hello Vite! (wait is it pronounced "veet" or "vight"...)</h1> <div></div> </body> </html>

Das einzig Interessante ist, dass div id="root" in der Mitte steht. Dies wird gleich die Wurzel unserer React-Komponente sein!

Wenn Sie möchten, können Sie den Vite-Server starten, um unsere einfache HTML-Datei in Ihrem Browser anzuzeigen. Führen Sie einfach vite aus (oder npx vite , wenn der Befehl nicht in Ihrem Terminal konfiguriert wurde), und Sie werden diese hilfreiche Ausgabe sehen:

 vite vX.XX dev server running at: > Local: http://localhost:3000/ > Network: use `--host` to expose ready in Xms.

Ähnlich wie bei Browsersync oder anderen beliebten Entwicklungsservern entspricht der Name jeder .html -Datei einer Route auf unserem Server. Wenn wir also index.html in about.html , würden wir http://localhost:3000/about/ aufrufen (ja, Sie benötigen einen abschließenden Schrägstrich!)

Lassen Sie uns jetzt etwas Interessantes tun. Fügen Sie neben dieser index.html -Datei eine Art grundlegende React-Komponente hinzu. Wir verwenden hier den useState von React, um die Interaktivität zu demonstrieren:

 // TimesWeMispronouncedVite.jsx import React from 'react' export default function TimesWeMispronouncedVite() { const [count, setCount] = React.useState(0) return ( <div> <p>I've said Vite wrong {count} times today</p> <button onClick={() => setCount(count + 1)}>Add one</button> </div> ) }

Lassen Sie uns nun diese Komponente auf unsere Seite laden. Das ist alles, was wir zu unserer index.html hinzufügen müssen:

 <!DOCTYPE html> ... <body> <h1>Hello Vite! (wait is it pronounced "veet" or "vight"...)</h1> <div></div> <!--Don't forget type="module"! This lets us use ES import syntax in the browser--> <script type="module"> // path to our component. Note we still use .jsx here! import Component from './TimesWeMispronouncedVite.jsx'; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('root'); ReactDOM.render(React.createElement(Component), componentRoot); </script> </body> </html>

Ja, das ist es. Sie müssen unsere .jsx -Datei nicht selbst in eine .js -Datei umwandeln! Überall dort, wo Vite einen .jsx -Import sieht, konvertiert es diese Datei automatisch in etwas, das Browser verstehen können. Es gibt nicht einmal einen dist oder build -Ordner, wenn man in der Entwicklung arbeitet; Vite verarbeitet alles im laufenden Betrieb – komplett mit dem Neuladen des Hot-Moduls jedes Mal, wenn wir unsere Änderungen speichern.

Okay, wir haben also ein unglaublich leistungsfähiges Build-Tool. Wie können wir dies in unsere 11ty-Vorlagen bringen?

Ausführen von Vite neben 11ty

Bevor wir uns den guten Dingen zuwenden, lassen Sie uns darüber sprechen, wie Sie 11ty und Vite nebeneinander betreiben. Fahren Sie fort und installieren Sie 11ty als Dev-Abhängigkeit in dasselbe Projektverzeichnis wie im letzten Abschnitt:

 npm i -D @11ty/eleventy # yes, it really is 11ty twice

Machen wir jetzt einen kleinen Preflight-Check, um zu sehen, ob 11ty funktioniert. Um Verwirrung zu vermeiden, empfehle ich Ihnen:

  1. Löschen Sie diese index.html -Datei von früher;
  2. Verschieben Sie diese TimesWeMispronouncedVite.jsx in ein neues Verzeichnis. Sprich, components/ ;
  3. Erstellen Sie einen src Ordner, in dem unsere Website leben kann;
  4. Fügen Sie diesem src -Verzeichnis eine Vorlage für 11ty zur Verarbeitung hinzu.

Beispielsweise eine blog- blog-post.md -Datei mit folgendem Inhalt:

 # Hello world! It's markdown here

Ihre Projektstruktur sollte in etwa so aussehen:

 src/ blog-post.md components/ TimesWeMispronouncedVite.jsx

Führen Sie nun 11ty von Ihrem Terminal aus wie folgt aus:

 npx eleventy --input=src

Wenn alles gut geht, sollten Sie eine Build-Ausgabe wie diese sehen:

 _site/ blog-post/ index.html

Wobei _site unser Standard-Ausgabeverzeichnis ist und blog-post/index.html unsere Markdown-Datei ist, die wunderbar zum Durchsuchen konvertiert wurde.

Normalerweise würden wir npx eleventy --serve , um einen Dev-Server hochzufahren und diese /blog-post Seite zu besuchen. Aber wir verwenden jetzt Vite für unseren Dev-Server! Das Ziel hier ist:

  1. Lassen Sie elfzig unsere Abschriften, Mops, Nunjucks und mehr in das _site Verzeichnis erstellen.
  2. Richten Sie Vite auf dasselbe _site Verzeichnis, damit es die React-Komponenten, ausgefallene Stilimporte und andere Dinge verarbeiten kann, die 11ty nicht aufgegriffen hat.

Also ein zweistufiger Build-Prozess, bei dem 11ty das Vite übergeben. Hier ist der CLI-Befehl, den Sie benötigen, um 11ty und Vite gleichzeitig im „Watch“-Modus zu starten:

 (npx eleventy --input=src --watch) & npx vite _site

Sie können diese Befehle auch in zwei separaten Terminals ausführen, um das Debuggen zu vereinfachen.

Mit etwas Glück sollten Sie in der Lage sein, http://localhost:3000/blog-post/ zu besuchen (vergessen Sie auch hier nicht den abschließenden Schrägstrich!), um die verarbeitete Markdown-Datei anzuzeigen.

Teilweise Flüssigkeitszufuhr mit Shortcodes

Lassen Sie uns einen kurzen Überblick über Shortcodes geben. Zeit, diese Syntax von früher zu überdenken:

 {% react '/components/TimesWeMispronouncedVite.jsx' %}

Für diejenigen, die mit Shortcodes nicht vertraut sind: Sie sind ungefähr dasselbe wie ein Funktionsaufruf, bei dem die Funktion eine HTML-Zeichenfolge zurückgibt, die in Ihre Seite eingefügt wird. Die „Anatomie“ unseres Shortcodes ist:

  • {% … %}
    Wrapper, der den Anfang und das Ende des Shortcodes bezeichnet.
  • react
    Den Namen unserer Shortcode-Funktion konfigurieren wir gleich.
  • '/components/TimesWeMispronouncedVite.jsx'
    Das erste (und einzige) Argument für unsere Shortcode-Funktion. Sie können so viele Argumente haben, wie Sie möchten.

Lassen Sie uns unseren ersten Shortcode verdrahten! Fügen Sie eine .eleventy.js -Datei zur Basis Ihres Projekts hinzu und fügen Sie diesen Konfigurationseintrag für unseren react -Shortcode hinzu:

 // .eleventy.js, at the base of the project module.exports = function(eleventyConfig) { eleventyConfig.addShortcode('react', function(componentPath) { // return any valid HTML to insert return `<div>This is where we'll import ${componentPath}</div>` }) return { dir: { // so we don't have to write `--input=src` in our terminal every time! input: 'src', } } }

Lassen Sie uns nun unsere blog-post.md mit unserem neuen Shortcode aufpeppen. Fügen Sie diesen Inhalt in unsere Markdown-Datei ein:

 # Super interesting programming tutorial Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example! {% react '/components/TimesWeMispronouncedVite.jsx' %}

Und wenn Sie schnell npx eleventy , sollten Sie diese Ausgabe in Ihrem _site Verzeichnis unter /blog-post/index.html :

 <h1>Super interesting programming tutorial</h1> <p>Writing paragraphs has been fun, but that's no way to learn. Time for an interactive code example!</p> <div>This is where we'll import /components/TimesWeMispronouncedVite.jsx</div>

Schreiben unseres Komponenten-Shortcodes

Lassen Sie uns jetzt etwas Nützliches mit diesem Shortcode machen. Erinnern Sie sich an das script -Tag, das wir beim Ausprobieren von Vite geschrieben haben? Nun, wir können dasselbe in unserem Shortcode tun! Dieses Mal verwenden wir das Argument „ componentPath “, um den Import zu generieren, aber der Rest bleibt ziemlich gleich:

 // .eleventy.js module.exports = function(eleventyConfig) { let idCounter = 0; // copy all our /components to the output directory // so Vite can find them. Very important step! eleventyConfig.addPassthroughCopy('components') eleventyConfig.addShortcode('react', function (componentPath) { // we'll use idCounter to generate unique IDs for each "root" div // this lets us use multiple components / shortcodes on the same page idCounter += 1; const componentRootId = `component-root-${idCounter}` return ` <div></div> <script type="module"> // use JSON.stringify to // 1) wrap our componentPath in quotes // 2) strip any invalid characters. Probably a non-issue, but good to be cautious! import Component from ${JSON.stringify(componentPath)}; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('${componentRootId}'); ReactDOM.render(React.createElement(Component), componentRoot); </script> ` }) eleventyConfig.on('beforeBuild', function () { // reset the counter for each new build // otherwise, it'll count up higher and higher on every live reload idCounter = 0; }) return { dir: { input: 'src', } } }

Nun sollte ein Aufruf unseres Shortcodes (z. {% react '/components/TimesWeMispronouncedVite.jsx' %} ) in etwa so aussehen:

 <div></div> <script type="module"> import Component from './components/FancyLiveDemo.jsx'; import React from 'react'; import ReactDOM from 'react-dom'; const componentRoot = document.getElementById('component-root-1'); ReactDOM.render(React.createElement(Component), componentRoot); </script>

Wenn wir unseren Dev-Server mit (npx eleventy --watch) & vite _site , sollten wir ein schön anklickbares Zählerelement finden.

Buzzword Alert – Partielle Hydratation und Inselarchitektur

Wir haben gerade „Inselarchitektur“ in ihrer einfachsten Form demonstriert. Dies ist die Idee, dass unsere interaktiven Komponentenbäume nicht die gesamte Website verbrauchen müssen. Stattdessen können wir in unserer App Mini-Bäume oder „Inseln“ erstellen, je nachdem, wo wir diese Interaktivität tatsächlich benötigen. Haben Sie eine einfache Zielseite mit Links ohne Status zu verwalten? Toll! Keine Notwendigkeit für interaktive Komponenten. Aber haben Sie ein mehrstufiges Formular, das von der X React-Bibliothek profitieren könnte? Kein Problem. Verwenden Sie Techniken wie den react -Shortcode, um eine Form.jsx Insel hochzufahren.

Dies geht Hand in Hand mit der Idee der „partiellen Hydratation“. Sie haben wahrscheinlich schon den Begriff „Hydration“ gehört, wenn Sie mit Komponenten-y-SSGs wie NextJS oder Gatsby arbeiten. Kurz gesagt, es ist eine Möglichkeit:

  1. Rendern Sie Ihre Komponenten zuerst in statisches HTML.
    Dies gibt dem Benutzer etwas zu sehen, wenn er Ihre Website zum ersten Mal besucht.
  2. „Hydrieren“ Sie dieses HTML mit Interaktivität.
    Hier verbinden wir unsere Status-Hooks und Renderer, um Schaltflächenklicks tatsächlich etwas auszulösen.

Dieser 1-2-Punch macht JS-gesteuerte Frameworks für statische Websites brauchbar. Solange der Benutzer etwas zu sehen hat, bevor Ihr JavaScript mit dem Parsen fertig ist, erhalten Sie eine anständige Punktzahl für diese Leuchtturm-Metriken.

Nun, bis du es nicht tust. Es kann teuer werden, eine ganze Website zu „hydrieren“, da Sie ein JavaScript-Bundle benötigen, das bereit ist, jedes letzte DOM-Element zu verarbeiten . Aber unsere schrottige Shortcode-Technik deckt nicht die gesamte Seite ab! Stattdessen hydratisieren wir den vorhandenen Inhalt „teilweise“ und fügen Komponenten nur dort ein, wo es notwendig ist.

Keine Sorge, es gibt ein Plugin für all dies: Slinkity

Fassen wir zusammen, was wir hier entdeckt haben:

  1. Vite ist ein unglaublich leistungsfähiger Bundler, der die meisten Dateitypen ( jsx , vue und svelte , um nur einige zu nennen) ohne zusätzliche Konfiguration verarbeiten kann.
  2. Shortcodes sind eine einfache Möglichkeit, HTML-Blöcke im Komponentenstil in unsere Vorlagen einzufügen.
  3. Wir können Shortcodes verwenden, um dynamische, interaktive JS-Bundles zu rendern, wo immer wir wollen, mit partieller Hydratation.

Was ist also mit optimierten Produktionsaufbauten? Scoped Styles richtig laden? Verdammt, mit .jsx ganze Seiten erstellen? Nun, ich habe all dies (und noch viel mehr!) in einem Projekt namens Slinkity gebündelt. Ich freue mich über den herzlichen Empfang des Projekts durch die Community und würde mich freuen, wenn Sie, lieber Leser, es selbst ausprobieren würden!

Probieren Sie die Schnellstartanleitung aus

Astro ist auch ziemlich großartig

Leser mit Blick auf Spitzentechnologie haben wahrscheinlich schon mindestens einmal an Astro gedacht. Und ich kann dir keinen Vorwurf machen! Es wurde mit einem ziemlich ähnlichen Ziel erstellt: Beginnen Sie mit einfachem HTML und fügen Sie zustandsbehaftete Komponenten ein, wo immer Sie sie benötigen. Verdammt, sie lassen Sie sogar damit beginnen, React-Komponenten in Vue- oder Svelte-Komponenten in HTML-Vorlagendateien zu schreiben! Es ist wie die MDX Xtreme Edition.

Es gibt jedoch einen ziemlich großen Preis für ihren Ansatz: Sie müssen Ihre App von Grund auf neu schreiben. Das bedeutet ein neues Vorlagenformat auf Basis von JSX (mit dem Sie sich vielleicht nicht wohlfühlen), eine ganz neue Datenpipeline, der im Moment ein paar Feinheiten fehlen, und allgemeine Fehler beim Ausarbeiten der Knicke.

Aber einen 11ty + Vite-Cocktail mit einem Tool wie Slinkity zu drehen? Nun, wenn Sie bereits eine 11ty-Site haben, sollte Vite ohne Umschreibungen funktionieren, und Shortcodes sollten viele der gleichen Anwendungsfälle wie .astro Dateien abdecken. Ich gebe zu, dass es im Moment alles andere als perfekt ist. Aber hey, es war bisher nützlich, und ich denke, es ist eine ziemlich starke Alternative, wenn Sie seitenweite Umschreibungen vermeiden möchten!

Einpacken

Dieses Slinkity-Experiment hat meine Bedürfnisse bisher ziemlich gut erfüllt (und einige von euch auch!). Fühlen Sie sich frei, jeden Stack zu verwenden, der für Ihr JAM funktioniert. Ich freue mich einfach, die Ergebnisse meines Jahres der Build-Tool-Ausschweifung zu teilen, und ich bin so aufgeregt, zu sehen, wie wir die große Jamstack-Kluft überbrücken können.

Weiterführende Lektüre

Möchten Sie tiefer in die partielle Flüssigkeitszufuhr oder ESM oder SSGs im Allgemeinen eintauchen? Guck dir diese an:

  • Architektur der Inseln
    Dieser Blogbeitrag von Jason Format hat wirklich eine Diskussion über „Inseln“ und „partielle Hydratation“ in der Webentwicklung ausgelöst. Es ist vollgepackt mit nützlichen Diagrammen und der Philosophie hinter der Idee.
  • Vereinfachen Sie Ihre Statik mit einem maßgeschneiderten Static-Site-Generator
    Ein weiterer SmashingMag-Artikel, der Sie durch die Erstellung Node-basierter Website-Builder von Grund auf führt. Es war eine große Inspiration für mich!
  • Wie ES-Module die Webentwicklung neu definiert haben
    Ein persönlicher Beitrag darüber, wie ES-Module die Webentwicklung verändert haben. Dies taucht ein wenig weiter in das „Damals und Heute“ der Importsyntax im Web ein.
  • Eine Einführung in Webkomponenten
    Eine hervorragende Anleitung, was Webkomponenten sind, wie das Schatten-DOM funktioniert und wo sich Webkomponenten als nützlich erweisen. Ich habe diese Anleitung verwendet, um benutzerdefinierte Komponenten auf mein eigenes Framework anzuwenden!