Markdown ist in der Tat ein großartiges Format. Es ist nah genug an einfachem Text, dass jeder schnell lernen kann, und es ist gut strukturiert genug, um analysiert und schließlich in das gewünschte Format umgewandelt zu werden.
Allerdings: Analyse, Verarbeitung, Verbesserung und Konvertieren erfordert Code. Die Bereitstellung all dieser Code im Client hat einen Preis. Es ist an sich nicht riesig, aber es ist immer noch ein paar Dutzend KB Code, die nur zur Behandlung von Markdown und keinem anderen Zweck verwendet werden.
In diesem Artikel werde ich erklären, wie ich in einer nächsten.js -Anwendung mit dem Unified/Bemerkung -Ökosystem aus dem Kunden ferngehalten werden kann (ich weiß wirklich nicht, welchen Namen zu verwirrend ist).
Die Idee ist, nur die Markdown -Funktion in der getStaticProps
-Funktion in Next.js zu verwenden, um dies während des Erstellungsprozesses zu tun (wenn Sie den inkrementellen Build von Vercel verwenden, wird dies in der nächsten serverlosen Funktion durchgeführt), wird jedoch keineswegs auf der Client -Seite verwendet. Ich denke, getServerSideProps
ist auch in Ordnung, aber ich denke, getStaticProps
ist eher ein häufiger Anwendungsfall.
Dies gibt einen AST zurück, der durch Parsen und Verarbeitung von Markdown -Inhalten ( abstrakter Syntaxbaum , dh ein großes verschachteltes Objekt, das unseren Inhalt beschreibt) erzeugt wird, und der Kunde ist nur dafür verantwortlich, den AST in eine React -Komponente zu verwandeln.
Ich denke, wir können sogar als HTML direkt in getStaticProps
Markdown machen und es zurückgeben, um es mit dangerouslySetInnerHtml
zu rendern, aber wir sind nicht so Menschen. Sicherheit ist wichtig. Auch die Flexibilität, den Markdown so zu machen, wie wir es mit unseren eigenen Komponenten gewünscht haben, anstatt es als reines HTML zu machen. Ernsthaft, Freunde, tu das nicht. ?
Export const GetstaticProps = async () => { // Erhalten Sie Markdown -Inhalte von irgendwoher, z. B. CMS oder so. In diesem Artikel ist dies nicht wichtig. Es kann auch aus der Datei gelesen werden. const markdown = Warten Sie GetmarkdownContentFromomewhere () const ast = parSemarkdown (Markdown) return {props: {ast}} } const page = props => { // Dies umfasst normalerweise Ihr Layout und so weiter, aber es wird hier zum Einfachheit halber weggelassen. Zurückkehren<markdownrenderer ast="{props.ast}"></markdownrenderer> } Standardseite exportieren
Wir werden das Unified/Bemerkung -Ökosystem verwenden. Wir müssen einheitlich und bemerkenswertig installieren, das war's. Es ist relativ einfach, den Markdown selbst zu analysieren:
Import {Unified} aus 'Unified' Importierendurchdringung aus "Bemerkung-Parse" const parSemarkdown = content => Unified (). Verwendung (RemindParse) .Parse (Inhalt) Exportieren Sie den Standard -Parsemarkdown
Was mich lange gebraucht habe, um zu verstehen, ist, warum meine zusätzlichen Plugins wie Bemerkung-Prism oder Bemerkung nicht so funktionieren. Dies liegt daran, dass die Unified .parse(..)
-Methode AST mit dem Plugin nicht verarbeitet. Wie der Name schon sagt, analysiert es nur den Markdown -String -Inhalt in einen Baum.
Wenn wir möchten, dass Unified unsere Plugins anwendet, müssen wir Unified einheitlich machen, was sie als "Auslauf" -Phase bezeichnen. Normalerweise erfolgt dies mit .process(..)
anstelle .parse(..)
-Methode. Leider analysiert .process(..)
nicht nur Markdown und wendet Plugins an, sondern auch in ein anderes Format (z. Und das wollen wir nicht, weil wir das AST behalten wollen, sondern nachdem es vom Plugin verarbeitet wurde.
<code>| ........................ process ........................... | | .......... parse ... | ... run ... | ... stringify ..........| -------- ----------输入->- | 解析器| ->- 语法树->- | 编译器| ->- 输出-------- | ---------- X | -------------- | 变换器| --------------</code>
Daher müssen wir nur die Analyse- und Ausführenphasen ausführen, aber nicht die Stringungsphase. Unified bietet keine Methode zur Ausführung von zwei dieser drei Stufen, bietet jedoch eine separate Methode für jede Phase, damit wir es manuell tun können:
Import {Unified} aus 'Unified' Importierendurchdringung aus "Bemerkung-Parse" Import BemerkungPrismus aus "Bemerkung-Prismus" const parSemarkdown = content => { const Engine = Unified (). Verwendung (Remarkse). const ast = Engine.Parse (Inhalt) // Unified's * Process * enthält drei verschiedene Phasen: Parsen, Ausführen und Stringung. Wir wollen die String -Phase nicht durchgehen, weil wir AST behalten wollen, damit wir nicht ".Process (..)` nennen können. Das Aufrufen von ".Parse (..)` reicht jedoch nicht aus, da das Plugin (und daher Prisma) während der Laufphase ausgeführt wird. Daher müssen wir die Laufphase manuell anrufen (zum Einfachheit halber synchron). // Siehe: https://github.com/unifiedjs/unified#description Return Engine.Runsync (AST) }
Sehen! Wir haben den Markdown in einen Syntaxbaum analysiert. Wir führen dann unser Plugin auf diesem Baum aus (er wird so leicht synchron, aber Sie können es asynchron mit .run(..)
tun). Wir haben unseren Baum jedoch nicht in andere Syntaxen wie HTML oder JSX umgewandelt. Wir können es selbst im Rendering tun.
Jetzt, wo wir unseren coolen Baum bereit haben, können wir ihn nach Absicht machen. Lassen Sie uns eine MarkdownRenderer
-Komponente erstellen, die den Baum als ast
-Eigenschaft nimmt und ihn mit der React -Komponente macht.
const getComponent = node => { Switch (node.type) { Fall 'Wurzel': return ({Kinder}) => {Kinder} > Fall 'Absatz': return ({Kinder}) =><p> {Kinder}</p> Fall "Betonung": return ({Kinder}) => <em>{Kinder}</em> Fall 'Überschrift': return ({Kinder, Tiefe = 2}) => { const hading = `H $ {Tiefe}` Zurückkehren<heading> {Kinder}</heading> } Fall 'Text': return ({value}) => {value} > / * Gehen Sie hier alle Typen um ... */// Standard: console.log ('unverarbeiteter Knotentyp', Knoten) return ({Kinder}) => {Kinder} > } } const node = ({node}) => { const component = getComponent (Knoten) const {Kinder} = Knoten Kinder zurückgeben? <component> {Kinder.Map ((Kind, Index) => ( <node key="{index}" node="{child}"></node> ))} </component> ): ( <component></component> ) } const markdownrenderer = ({ast}) =><node node="{ast}"></node> Exportieren Sie Standard -React.Memo (Markdownrenderer)
Der größte Teil der Logik unseres Renderers befindet sich in Node
. Es findet heraus, was auf type
des AST -Knotens rendern zu werden (dies ist unsere getComponent
-Methode, die mit jedem Knotentyp befasst) und dann es dann rendert. Wenn der Knoten Kinder hat, tritt er rekursiv in den Kinderknoten ein.
Abhängig vom von uns verwendeten Bemerkung -Plugin können wir auf die folgenden Probleme stoßen, wenn wir versuchen, die Seite zu rendern:
Fehler: Ein Fehler beim Serialisieren .Content [0] .Content.Children [3] .Data.hchildren [0] .Data.hchildren [0] .Data.hchildren [0] .data.hchildren [0] .data.hname (von getstaticProps in '/'). Ursache: undefined kann nicht mit JSON serialisiert werden. Bitte verwenden Sie NULL oder lassen Sie diesen Wert weg.
Dies geschieht, weil unser AST Schlüssel mit undefinierten Werten enthält, was nicht sicher mit JSON serialisiert werden kann. Als nächstes gibt wir eine Lösung: Wir können den Wert insgesamt weglassen oder ihn durch Null ersetzen, wenn wir ihn mehr oder weniger benötigen.
Wir werden jedoch nicht jeden Pfad manuell reparieren, daher müssen wir das rekursiv über das ASTRAVES durchqueren und aufräumen. Ich habe festgestellt, dass dies bei der Verwendung von Bemerkung-Prismus (ein Plugin, das die Codeblocksyntax-Hervorhebung ermöglicht) geschieht. Das Plugin fügt dem Knoten ein [data]
Objekt hinzu.
Was wir tun können, ist, diese Knoten zu beseitigen, bevor wir AST zurückgeben:
const cleanNode = node => { if (node.value === undefiniert) Knoten löschen.Value if (node.tagname === undefiniert) Knoten löschen.tagname if (node.data) { löschen node.data.hname löschen node.data.hchildren löschen node.data.hproperties } if (node.children) node.children.foreach (CleanNode) Return Node } const parSemarkdown = content => { const Engine = Unified (). Verwendung (Remarkse). const ast = Engine.Parse (Inhalt) const processedast = motor.runsync (AST) CleanNode (Processedast) Processedast zurückgeben }
Das Letzte, was wir tun können, ist, das position
zu löschen, das auf jedem Knoten vorhanden ist, der die ursprüngliche Position in der Markdown -Zeichenfolge enthält. Es ist kein großes Objekt (es hat nur zwei Schlüssel), aber es sammelt sich schnell an, wenn der Baum größer wird.
const cleanNode = node => { Node löschen.position // ... andere Reinigungslogik}
Das war's! Wir haben es geschafft, die Markdown -Verarbeitung auf Erstellen/Server -Seitencode zu begrenzen, sodass wir keine unnötigen Markdown -Runtimes an den Browser senden, was die Kosten unnötig erhöht. Wir übergeben den Datenbaum an den Client, und wir können ihn über ihn iterieren und in jede gewünschte React -Komponente umwandeln.
Hoffe das hilft. :)
Das obige ist der detaillierte Inhalt vonVerantwortungsbewusstes Abschluss in Next.js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!