Sie haben wahrscheinlich viel über eines der neuesten Frameworks gehört, Remix. Es mag überraschend sein, dass es bereits 2019 begann, aber es war ursprünglich nur als kostenpflichtiges Premium-Framework verfügbar. Im Jahr 2021 sammelten die Gründer Seed-Finanzierung und machten das Framework Open Source, damit Benutzer Remix kostenlos nutzen können. Die Tore öffneten sich und jeder scheint darüber zu reden, ob positiv oder negativ. Tauchen wir ein und betrachten einige der Grundlagen von Remix.
Remix ist ein serverseitiges „Edge“-First-JavaScript-Framework. Es verwendet React, zumindest vorerst, für das Frontend und priorisiert das serverseitige Rendering der Anwendung am Edge. Plattformen können den serverseitigen Code nehmen und ihn als Serverless- oder Edge-Funktionen ausführen, was günstiger ist als ein traditioneller Server und näher an Ihren Benutzern liegt. Die Gründer von Remix bezeichnen es gerne als „Center Stack“-Framework, da es die zwischen Server und Client gesendeten Anfragen und Antworten für die Plattform, auf der es ausgeführt wird, anpasst.

Remix bereitstellen
Da Remix einen Server benötigt, sprechen wir darüber, wie Sie ihn bereitstellen können. Remix stellt den Server nicht selbst bereit – Sie bringen den Server mit – und können ihn in jeder Node.js- oder Deno-Umgebung ausführen, einschließlich Netlify Edge und DigitalOcean App Platform. Remix selbst ist ein Compiler, ein Programm, das die Anfragen für die Plattform, auf der es läuft, übersetzt. Dieser Prozess verwendet esbuild, um Handler für die Anfragen an den Server zu erstellen. Die verwendeten HTTP-Handler basieren auf der Web Fetch API und werden auf dem Server ausgeführt, indem sie für die Plattform, auf der sie bereitgestellt werden, *angepasst* werden.
Remix Stacks
Remix Stacks sind Projekte, die einige gängige Tools vorab konfiguriert haben. Es gibt drei offizielle Stacks, die vom Remix-Team gepflegt werden und alle nach Musikgenres benannt sind. Es gibt auch eine Reihe von Community-Remix-Stacks, darunter den K-Pop Stack, der vom Templates Team bei Netlify erstellt wurde. Dieser Stack ist ein Kraftpaket und beinhaltet eine Supabase-Datenbank und Authentifizierung, Tailwind für Styling, Cypress für End-to-End-Tests, Prettier für Codeformatierung, ESLint für Linting und TypeScript für statische Typisierung. Lesen Sie den Beitrag von Tara Manicsic über die Bereitstellung des K-Pop Stacks.
Routen cachen
Auch wenn Remix einen Server benötigt, kann es die Vorteile von Jamstack nutzen, indem es Routen cacht. Eine statische Website oder statische Seitengenerierung (SSG) bedeutet, dass Ihr gesamter Inhalt zur Build-Zeit gerendert wird und bis zu einem weiteren Neubau *statisch* bleibt. Der Inhalt wird vorkompiliert und kann auf einem CDN gespeichert werden. Dies bietet viele Vorteile und schnelle Seitenladezeiten für den Endbenutzer. Remix führt jedoch kein typisches SSG wie andere beliebte React-Frameworks, einschließlich Next.js und Gatsby, durch. Um einige der Vorteile von SSG zu nutzen, können Sie den nativen Cache-Control HTTP-Header in einer Remix Headers-Funktion verwenden, um eine bestimmte Route zu cachen, oder direkt in der Datei root.tsx.
[[headers]]
for = "/build/*"
[headers.values]
"Cache-Control" = "public, max-age=31536000, s-maxage=31536000"
Fügen Sie dann Ihre Headers-Funktion hinzu, wo Sie sie benötigen. Dies cacht für eine Stunde
export function headers() {
return {
"Cache-Control": "public, s-maxage=360",
};
};
Routing neu gestalten
Viele Frameworks haben sich dem Dateisystem-basierten Routing verschrieben. Dies ist eine Technik, bei der ein bestimmter Ordner verwendet wird, um Routen für Ihre Anwendung zu definieren. Sie haben typischerweise eine spezielle Syntax für die Deklaration von dynamischen Routen und Endpunkten. Der größte Unterschied zwischen Remix und anderen beliebten Frameworks ist derzeit die Möglichkeit, verschachteltes Routing zu verwenden.
Jede Remix-App beginnt mit der Datei root.tsx. Hier wird die gesamte Basis der App gerendert. Sie finden hier einige der üblichen HTML-Layouts wie das <html>-Tag, das <head>-Tag und dann das <body>-Tag mit den Komponenten, die zum Rendern der App benötigt werden. Das Einzige, was hier hervorzuheben ist, ist die <Scripts>-Komponente, die JavaScript auf der Website aktiviert; einige Dinge funktionieren auch ohne sie, aber nicht alles. Die Datei root.tsx fungiert als übergeordnetes Layout für alles innerhalb des routes-Verzeichnisses. Alles in den Routen wird dort gerendert, wo sich die <Outlet/>-Komponente in root.tsx befindet. Dies ist die Basis des verschachtelten Routings in Remix.
Verschachteltes Routing
Remix wurde nicht nur von einigen Mitgliedern des Teams von React Router gegründet, sondern *verwendet* auch React Router. Tatsächlich bringen sie einige der guten Dinge von Remix zurück zu React Router. Ein komplexes Problem, das die Maintainer von Next.js und SvelteKit derzeit zu lösen versuchen, ist verschachteltes Routing.
Verschachteltes Routing unterscheidet sich vom traditionellen Routing. Wo eine neue Route einen Benutzer zu einer neuen Seite bringt, ist jede verschachtelte Route ein separater Abschnitt derselben Seite. Es ermöglicht die Trennung von Belangen, indem die Geschäftslogik nur mit den Dateien verknüpft wird, die sie benötigen. Remix kann Fehler lokalisieren, die nur den Abschnitt der Seite betreffen, auf dem sich die verschachtelte Route befindet. Die anderen Routen auf der Seite sind weiterhin nutzbar und die Route, die abgestürzt ist, kann relevante Kontextinformationen zum Fehler liefern, ohne dass die gesamte Seite abstürzt.
Remix macht dies, wenn eine Root-Datei in app/routes denselben Namen hat wie ein Verzeichnis von Dateien, die innerhalb der Basisdatei geladen werden. Die Root-Datei wird zu einem *Layout* für die Dateien im Verzeichnis, indem sie eine <Outlet />-Komponente verwendet, um Remix mitzuteilen, wo die anderen Routen geladen werden sollen.
Outlet-Komponente
Die <Outlet />-Komponente ist ein Signal für Remix, wo Inhalte für verschachtelte Routen gerendert werden sollen. Sie wird in der Datei am Root des app/routes-Verzeichnisses mit demselben Namen wie die verschachtelten Routen platziert. Der folgende Code befindet sich in einer Datei app/routes/about.tsx und enthält den Outlet für die Dateien innerhalb des app/routes/about-Ordners
import { Outlet } from "@remix-run/react";
export default function About() {
return (
<>
<section>
I am the parent layout. I will be on any page inside of my named directory.
</section>
{ /* All of my children, the files in the named directory, will go here. */ }
<Outlet />
</>
)
}
Ordnerstruktur
Jede Datei im Verzeichnis app/routes/ wird zu einer Route unter der URL ihres Namens. Ein Verzeichnis kann auch mit einer Datei index.tsx hinzugefügt werden.
app/
├── routes/
│ │
│ └── blog
| | ├── index.tsx ## The /blog route
│ └── about.tsx ## The /about route
│ ├── index.tsx ## The / or home route
└── root.tsx
Wenn eine Route denselben Namen wie ein Verzeichnis hat, wird die benannte Datei zu einer Layoutdatei für die Dateien im Verzeichnis und die Layoutdatei benötigt eine Outlet-Komponente, um die verschachtelte Route darin zu platzieren.
app/
├── routes/
│ │
│ └── about
│ │ ├── index.tsx
│ ├── about.tsx ## this is a layout for /about/index.tsx
│ ├── index.tsx
└── root.tsx
Layouts können auch erstellt werden, indem ihnen ein doppelter Unterstrich (__) vorangestellt wird.
app/
├── routes/
│ │
│ └── about
│ │ ├── index.tsx
│ ├── index.tsx
│ ├── about.tsx
│ ├── __blog.tsx ## this is also a layout
└── root.tsx
https://your-url.com/about rendert weiterhin die Datei app/routes/about.tsx, rendert aber auch alles, was sich in app/routes/about/index.tsx befindet, wo sich die Outlet-Komponente im Markup von app/routes/about.tsx befindet.
Dynamische Routen
Eine dynamische Route ist eine Route, die sich basierend auf Informationen in der URL ändert. Das kann ein Blogpost-Name oder eine Kunden-ID sein, aber egal was es ist, die $-Syntax, die dem Präfix der Route hinzugefügt wird, signalisiert Remix, dass sie dynamisch ist. Der Name spielt keine Rolle, abgesehen vom $-Präfix.
app/
├── routes/
│ │
│ └── about
│ │ ├── $id.tsx
│ │ ├── index.tsx
│ ├── about.tsx ## this is a layout for /about/index.tsx
│ ├── index.tsx
└── root.tsx
Daten abrufen!
Da Remix alle seine Daten auf dem Server rendert, sehen Sie in Remix viele Dinge nicht, die zum Standard einer React-App geworden sind, wie z. B. die Hooks useState() und useEffect(). Es gibt weniger Bedarf an clientseitigem State, da dieser bereits auf dem Server ausgewertet wurde.
Es spielt auch keine Rolle, welchen Server Sie zum Abrufen von Daten verwenden. Da Remix zwischen Anfrage und Antwort sitzt und diese entsprechend übersetzt, können Sie die Standard Web Fetch API verwenden. Remix macht dies in einer loader-Funktion, die *nur* auf dem Server ausgeführt wird, und verwendet den Hook useLoaderData(), um die Daten in der Komponente zu rendern. Hier ist ein Beispiel, das die Cat as a Service API verwendet, um ein zufälliges Katzenbild anzuzeigen.
import { Outlet, useLoaderData } from '@remix-run/react'
export async function loader() {
const response = await fetch('<https://cataas.com/cat?json=true>')
const data = await response.json()
return {
data
}
}
export default function AboutLayout() {
const cat = useLoaderData<typeof loader>()
return (
<>
<img
src={`https://cataas.com/cat/${cat}`}
alt="A random cat."
/>
<Outlet />
</>
)
}
Routenparameter
In dynamischen Routen müssen Routen, denen ein $ vorangestellt ist, auf den URL-Parameter zugreifen können, um die zu rendernden Daten zu verarbeiten. Die loader-Funktion hat über ein params-Argument Zugriff darauf.
import { useLoaderData } from '@remix-run/react'
import type { LoaderArgs } from '@remix-run/node'
export async function loader({ params }: LoaderArgs) {
return {
params
}
}
export default function AboutLayout() {
const { params } = useLoaderData<typeof loader>()
return <p>The url parameter is {params.tag}.</p>
}
Andere Remix-Funktionen
Remix bietet einige weitere Hilfsfunktionen, die normalen HTML-Elementen und Attributen in der Route-Modul-API zusätzliche Funktionalität verleihen. Jede Route kann ihre eigenen dieser Arten von Funktionen definieren.
Action-Funktion
Eine action-Funktion ermöglicht es Ihnen, einem Formular-Action zusätzliche Funktionalität hinzuzufügen, indem Sie die Standard-Web- FormData API verwenden.
export async function action({ request }) {
const body = await request.formData();
const todo = await fakeCreateTodo({
title: body.get("title"),
});
return redirect(`/todos/${todo.id}`);
}
Headers-Funktion
Beliebige Standard-HTTP-Header können in einer headers-Funktion platziert werden. Da jede Route einen Header haben kann, gewinnt zur Vermeidung von Konflikten mit verschachtelten Routen die am tiefsten liegende Route – oder die URL mit den meisten Schrägstrichen (/). Sie können auch die übergebenen Header abrufen: actionHeaders, loaderHeaders oder parentHeaders.
export function headers({
actionHeaders,
loaderHeaders,
parentHeaders,
}) {
return {
"Cache-Control": loaderHeaders.get("Cache-Control"),
};
}
Meta-Funktion
Diese Funktion legt die Meta-Tags für das HTML-Dokument fest. Standardmäßig ist einer in der Datei root.tsx festgelegt, aber er kann für jede Route aktualisiert werden.
export function meta() {
return {
title: "Your page title",
description: "A new description for each route.",
};
};
Links-Funktion
HTML-link-Elemente befinden sich im <head>-Tag eines HTML-Dokuments und importieren CSS, unter anderem. Die links-Funktion, nicht zu verwechseln mit der <Link />-Komponente, ermöglicht es Ihnen, nur die Dinge in die Routen zu importieren, die sie benötigen. CSS-Dateien können also eingekapselt und nur auf den Routen importiert werden, die diese spezifischen Dateien benötigen. Die link-Elemente werden aus einer links()-Funktion als Array von Objekten zurückgegeben und können entweder ein HtmlLinkDescriptor aus der link API oder ein PageLinkDescriptor sein, der die Daten für eine Seite vorab abrufen kann.
export function links() {
return [
// add a favicon
{
rel: "icon",
href: "/favicon.png",
type: "image/png",
},
// add an external stylesheet
{
rel: "stylesheet",
href: "<https://example.com/some/styles.css>",
crossOrigin: "true",
},
// add a local stylesheet,
{ rel: "stylesheet", href: stylesHref },
// prefetch a page's data
{ page: "/about/community" }
]
}
Verknüpfung zwischen Routen
Remix bietet eine Komponente, um zwischen den verschiedenen Routen in Ihrer App zu navigieren, die <Link/> genannt wird. Um clientseitiges Routing zu erhalten, verwenden Sie die <Link to="">Name</Link>-Komponente anstelle von <a href="">Name</a>. Die <Link />-Komponente hat auch eine Prop namens prefetch, die standardmäßig auf none gesetzt ist, intent, um die Daten vorab abzurufen, wenn Remix erkennt, dass der Benutzer mit der Maus über den Link fährt oder ihn fokussiert, oder render, was die Daten der Route abruft, sobald der Link gerendert wird.
import { Link } from "@remix-run/react";
export default function Nav() {
return (
<nav>
<Link to="/">Home</Link>{" "}
<Link to="/about">About</Link>{" "}
<Link to="/about/community" prefetch="intent">Community</Link>
</nav>
);
}
Nächste Schritte
Jetzt kennen Sie die Grundlagen von Remix und sind bereit, tatsächlich Anwendungen zu erstellen, richtig? Remix bietet eine Jokes-App und ein Blog-Tutorial, um Ihnen den Einstieg in die Anwendung dieses grundlegenden Wissens zu ermöglichen. Sie können auch von Grund auf neu beginnen und eine brandneue Remix-App erstellen. Oder wenn Sie bereit sind, sich hineinzustürzen, probieren Sie den K-Pop Stack aus. Ich habe meine Zeit mit Remix wirklich genossen und liebe den Fokus auf Webstandards und die Rückkehr zu den Grundlagen. Jetzt sind Sie an der Reihe, mit dem Erstellen zu beginnen!