Next.js ist eine sehr gute Möglichkeit, um eine Full-stack Anwendung auf Basis des React-Frameworks in Javascript oder Typescript aufzubauen. Größter Vorteil ist, dass die Komponenten serverseitig vorbereitet (“gerendert”) werden, so dass die Webseite auch von Suchmaschinen gefunden werden kann.
Genau diese Methode kann aber auch gelegentlich zu Problemen führen, insbesondere, wenn man fertige Module einbinden möchte, die nur im Browser ausgeführt werden können. In meinem Fall war dies das Modul “swagger-ui-react”, mit dem ich die Beschreibung meiner REST-API in anschaulicher Form als Webseite bereitstellen kann. Dieses fertige Modul lässt sich in der aktuellen Version nicht auf dem Server rendern.
Mein erster Versuch war also, das Modul als einfache Komponente bereitzustellen, die Daten meiner API liegen dabei als JSON Datei vor. Hier meine Komponente, wie sie bei klassischen React Webseiten funktioniert:
import SwaggerUI from "swagger-ui-react";
import "swagger-ui-react/swagger-ui.css";
import swaggerDocument from "../meine-api.json";
export default function ApiDocs() {
return <SwaggerUI spec={swaggerDocument} />;
}
Im Next.JS Framework versucht das System nun aber, diese Komponente vor der Auslieferung an den Browser bereits auf dem Server aufzubereiten. Das schlägt fehl, da die fertige Komponente nicht dafür ausgelegt ist.
Es kommt zu einer sehr umfangreichen Fehlermeldung, deren hervorgehobene Kernaussage ist: “Cannot use import statement outside a module” – kann außerhalb eines Moduls keinen Import verwenden.
Leider ist diese Formulierung nicht wirklich zielführend. Bei meiner Suche bin ich zwar häufig auf die gleiche Fehlermeldung gestoßen, aber die vorgeschlagenen Lösungswege waren oft wenig bis gar nicht hilfreich.
Nach längerer Suche und Studium der Next Dokumentation bin ich auf die “dynamic” Bibliothek in Next gestoßen, die schlussendlich die Lösung gebracht hat. Durch diese Methode wird das Laden der eigentlichen SwaggerUI Bibliothek verzögert, mit zusätzlichem Parameter { ssr: false }
sogar ganz auf die Client-Seite verlagert, so dass der Code nun – wie erwünscht – auf dem Browser des Anwenders ausgeführt wird.
Der Clou ist also, die Bibliothek “SwaggerUI” nicht direkt in der Kopfzeile des Moduls zu importieren, sondern erst zur Laufzeit – und dem System dann noch ausdrücklich mitzuteilen, dass die Ausführung bitte nicht auf dem Server, sondern beim Anwender stattfinden soll.
Hier ist die funktionierende Lösung:
import dynamic from "next/dynamic";
import swaggerDocument from "../meine-api.json";
import "swagger-ui-react/swagger-ui.css";
const SwaggerUI = dynamic(
() => import("swagger-ui-react"), { ssr: false }
);
export default function ApiDocs() {
return <SwaggerUI spec={swaggerDocument} />;
}
Fazit: Der größte Vorteil der Next.JS Bibliothek, die Aufbereitung der dynamischen Webseiten auf dem Server, kann auch zum Nachteil werden, wenn man eine Bibliothek aus fremder Quelle einbindet, die dafür nicht vorgesehen ist. Hier hilft nur, die Ausführung wieder auf den Browser des Anwenders zu verlegen. Kleine, aber effektive Lösung nach langer Suche.
Links:
Offizielle Next.js Dokumentation zu “dynamic”: https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr
Swagger-UI webseite: https://swagger.io/tools/swagger-ui/
NPM Modul: https://www.npmjs.com/package/swagger-ui
Der Blogbeitrag hat wirklich Licht ins Dunkel des “Cannot use import statement outside a module” Fehlers in Next.js gebracht. Gerade die serverseitige Vorbereitung in Next.js ist einerseits ein großer Vorteil, kann aber auch zu Fallstricken führen, wie das Einbinden von Bibliotheken, die nicht dafür vorgesehen sind. Ihre Anleitung zur Verwendung der “dynamic” Bibliothek in Next scheint wie ein Lebensretter für Entwickler, die mit dieser kniffligen Situation konfrontiert sind. Mit diesem Wissen im Hinterkopf sollte die Integration spezieller Module wie Swagger-UI in Next.js Projekte viel weniger Kopfschmerzen bereiten. Die praktische Lösung, die Ausführung von bestimmten Modulen wieder auf den Browser des Anwenders zu verlagern, ist ein cleverer Workaround, der sicherlich vielen Entwicklern viel Zeit sparen wird. Besonders ansprechend finde ich den Abschluss mit dem klaren Fazit. Es hilft, die zentrale Botschaft des Artikels hervorzuheben und zu verinnerlichen.
Da ich aus dem IT-Dienstleistungsbereich komme und mein Unternehmen sich auf individuelle Softwarelösungen spezialisiert hat, weiß ich, wie wichtig solche detaillierten Anleitungen für Entwickler sein können. Haben Sie auch Erfahrung damit, wie gut dieser Ansatz skaliert, wenn mehrere solcher ‘nicht serverseitig renderbaren’ Module in einer Anwendung eingesetzt werden?
Hallo Thomas,
SwaggerUI war das einzige Modul, das bisher eine solche Sonderbehandlung verlangte. Über die Skalierung würde ich mir aber keine Gedanken machen, denn letztlich macht das Modul jetzt genau das, wofür es gebaut wurde: Es läuft auf dem Client. Viele klassische React-Webseiten mit REST-API binden das Modul ein, es läuft dort immer auf dem Client. NEXT.JS wird jetzt lediglich “gezwungen”, sich wie ein klassisches React zu verhalten.
Herzliche Grüße, Joe
Wow, was für ein toller Artikel! Jetzt kann ich die Vorteile dieses Rahmens voll ausschöpfen.
Als Entwickler schätze ich Ihre Arbeit sehr. Vielen Dank dafür!
Ich möchte mich herzlich bedanken für diesen Blog Artikel! Der Artikel hat mir nun neue Erkenntnisse gebracht. Ich freue mich schon darauf, weitere Artikel von euch zu lesen.
LG
Dieser Artikel hat viele meiner Fragen zum Thema „wie man den “Cannot use import statement outside a module” – Fehler in Next.js behebt“ beantwortet. Ich habe den Artikel sehr gerne gelesen und interessante Ideen daraus schöpfen können. Macht weiter so und schreibt interessante Artikel über IT-Themen.