Maison > interface Web > tutoriel CSS > Marqueur responsable dans Next.js

Marqueur responsable dans Next.js

Joseph Gordon-Levitt
Libérer: 2025-03-21 10:57:11
original
822 Les gens l'ont consulté

Marque responsable dans Next.js

Markdown est en effet un grand format. Il est assez proche du texte brut que n'importe qui peut apprendre rapidement, et il est assez structuré pour être analysé et finalement converti au format que vous voulez.

Cependant: l'analyse, le traitement, l'amélioration et la conversion de la marque nécessitent du code. Le déploiement de tout ce code sur le client a un prix. Ce n'est pas énorme en soi, mais c'est encore quelques dizaines de KB de code qui n'est utilisé que pour gérer Markdown et aucun autre objectif.

Dans cet article, je vais expliquer comment garder Markdown hors du client dans une application Next.js, en utilisant l'écosystème unifié / remarque (je ne sais vraiment pas quel nom utiliser, ce qui est trop déroutant).

Idées principales

L'idée est d'utiliser uniquement Markdown dans la fonction getStaticProps dans Next.js pour ce faire pendant le processus de construction (si vous utilisez la version incrémentielle de Vercel, cela se fait dans la prochaine fonction sans serveur), mais elle n'est en aucun cas utilisée du côté client. Je suppose que getServerSideProps est également OK aussi, mais je pense que getStaticProps est plus susceptible d'être un cas d'utilisation courant.

Cela renvoie un AST généré par l'analyse et le traitement du contenu de marque ( arborescence de syntaxe abstraite , c'est-à-dire un grand objet imbriqué qui décrit notre contenu), et le client n'est responsable que du rendu l'AST en un composant React.

Je suppose que nous pouvons même rendre Markdown en tant que HTML directement dans getStaticProps et le rendre dangereux avec dangerouslySetInnerHtml , mais nous ne sommes pas ce genre de personnes. La sécurité est importante. En outre, la flexibilité pour rendre Markdown comme nous le souhaitons avec nos propres composants au lieu de le rendre pur HTML. Sérieusement, amis, ne fais pas ça. ?

 export const getStaticProps = async () => {
  // Obtenez du contenu de Markdown de quelque part, comme CMS ou quelque chose comme ça. En ce qui concerne cet article, ce n'est pas important. Il peut également être lu à partir du fichier.
  const Markdown = attendre getMarkdownContentFromsomewhere ()
  const ast = parsemarkdown (Markdown)

  return {accessoires: {ast}}
}

const page = props => {
  // Cela inclut généralement votre mise en page et ainsi de suite, mais c'est omis ici pour simplifier.
  Retour<markdownrenderer ast="{props.ast}"></markdownrenderer>
}

Exporter la page par défaut
Copier après la connexion

Analyser la marque

Nous utiliserons l'écosystème unifié / Remarque. Nous devons installer unifié et remarquable, c'est tout. Il est relativement simple de analyser la marque elle-même:

 import {Unified} de 'unifié'
Importer un remarquable à partir de «remarque-parse»

const parsemarkdown = contenu => unifié (). Utilisation (Rocucherse) .Parse (Content)

Exporter PARSEMARKDOWN par défaut
Copier après la connexion

Maintenant, ce qui m'a pris beaucoup de temps à comprendre, c'est pourquoi mes plugins supplémentaires comme les remarques ou les remarques ne fonctionnent pas comme ça. En effet, la méthode .parse(..) unifiée ne gère pas AST à l'aide du plugin. Comme son nom l'indique, il analyse uniquement le contenu de la chaîne de marque dans une arborescence.

Si nous voulons que Unified applique nos plugins, nous avons besoin d'Unified pour passer par ce qu'ils appellent la phase "en cours d'exécution". En règle générale, cela se fait en utilisant .process(..) au lieu de .parse(..) . Malheureusement, .process(..) Analyse non seulement Markdown et applique des plugins, mais il met également l'AST dans un autre format (par exemple, en utilisant HTML via Remark-HTML, ou en utilisant JSX via Remark-React). Et ce n'est pas ce que nous voulons parce que nous voulons garder l'AST, mais après avoir été traité par le plugin.

 <code>| ........................ process ........................... | | .......... parse ... | ... run ... | ... stringify ..........| -------- ----------输入->- | 解析器| ->- 语法树->- | 编译器| ->- 输出-------- | ---------- X | -------------- | 变换器| --------------</code>
Copier après la connexion

Par conséquent, tout ce que nous devons faire est d'exécuter les phases d'analyse et d'exécution, mais pas la phase de chaîne. Unified ne fournit pas de méthode pour exécuter deux de ces trois étapes, mais il fournit une méthode distincte pour chaque étape afin que nous puissions le faire manuellement:

 import {Unified} de 'unifié'
Importer un remarquable à partir de «remarque-parse»
Importer un remarquable à la «remarque de la remarque»

const parsemarkdown = contenu => {
  Const Engine = Unified (). Utilisation (RemarkParse) .User (RemarkPrism)
  const ast = moteur.parse (contenu)

  // Le processus * d'Unified * contient trois étapes différentes: analyse, fonctionnement et chaîne. Nous ne voulons pas passer par la phase de chaîne parce que nous voulons garder AST afin que nous ne puissions pas appeler `.Process (..) '. Cependant, appeler «.parse (..)» ne suffit pas, car le plugin (et donc prisme) est exécuté pendant la phase d'exécution. Nous devons donc appeler la phase d'exécution manuellement (pour simplicité, de manière synchrone).
  // Voir: https://github.com/Unifiedjs/Unified#description
  RETOUR MOTEUR.RUNSYNC (AST)
}
Copier après la connexion

Regarder! Nous avons analysé Markdown dans un arbre de syntaxe. Nous exécutons ensuite notre plugin sur cet arbre (il est fait de manière synchrone pour la simplicité, mais vous pouvez le faire de manière asynchrone en utilisant .run(..) ). Cependant, nous n'avons pas converti notre arbre en d'autres syntaxes tels que HTML ou JSX. Nous pouvons le faire nous-mêmes dans le rendu.

Render Markdown

Maintenant que nous avons notre arbre cool prêt, nous pouvons le rendre comme nous l'avons l'intention. Créons un composant MarkdownRenderer qui prend l'arbre comme ast et le rend avec le composant React.

 const getComponent = node => {
  switch (node.type) {
    case «racine»:
      return ({enfants}) =>  {enfants} >

    cas «paragraphe»:
      return ({enfants}) =><p> {enfants}</p>

    Cas «accent»:
      return ({enfants}) => <em>{enfants}</em>

    Cas «En-tête»:
      return ({enfants, profondeur = 2}) => {
        constant const = `h $ {de profondeur}`
        Retour<heading> {enfants}</heading>
      }

    case «texte»:
      return ({value}) =>  {valeur} >

    / * Gérer tous les types ici ... * /

    défaut:
      console.log («type de nœud non traité», nœud)
      return ({enfants}) =>  {enfants} >
  }
}

const node = ({node}) => {
  const composant = getComponent (nœud)
  const {enfants} = nœud

  retour des enfants?
    <component>
      {enfants.map ((enfant, index) => (
        <node key="{index}" node="{child}"></node>
      ))}
    </component>
  ): (
    <component></component>
  )
}

const markdownRenderer = ({ast}) =><node node="{ast}"></node>

Exporter par défaut React.Memo (MarkdownRenderer)
Copier après la connexion

La majeure partie de la logique de notre rendu est située dans Node . Il découvre quoi rendre en fonction de type du nœud AST (il s'agit de notre méthode getComponent avec chaque type de nœud), puis le rend. Si le nœud a des enfants, il entre récursivement dans le nœud enfant;

Nettoyer l'arbre

Selon le plugin de remarques que nous utilisons, nous pouvons rencontrer les problèmes suivants lorsque nous essayons de rendre la page:

Erreur: une erreur s'est produite lors de la sérialisation .Content [0] .Content.children [3] .data.hchildren [0] .data.hchildren [0] .data.hchildren [0] .data.hchildren [0] .Data.hname (de GetstaticProps in '/'). Cause: Undefined ne peut pas être sérialisé en JSON. Veuillez utiliser NULL ou omettre cette valeur.

Cela se produit parce que notre AST contient des clés avec des valeurs non définies, ce qui n'est pas quelque chose qui peut être sérialisé en toute sécurité en JSON. Next nous donne une solution: nous pouvons omettre complètement la valeur, ou le remplacer par null si nous en avons besoin plus ou moins.

Cependant, nous ne fixerons pas chaque chemin manuellement, nous devons donc traverser récursivement cette AST et le nettoyer. J'ai trouvé que cela se produit lors de l'utilisation de Remark-Prism (un plugin qui permet la modération de la syntaxe du bloc de code). Le plugin ajoute un objet [data] au nœud.

Ce que nous pouvons faire, c'est la diffuser pour nettoyer ces nœuds avant de retourner AST:

 const CleanNode = node => {
  if (node.value === Undefined) supprimer node.value
  if (node.tagname === Undefined) supprimer node.tagname
  if (node.data) {
    Supprimer Node.Data.hname
    Supprimer Node.data.hchildren
    Supprimer Node.data.hproperties
  }

  if (node.children) node.children.foreach (cleannode)

  Node de retour
}

const parsemarkdown = contenu => {
  Const Engine = Unified (). Utilisation (RemarkParse) .User (RemarkPrism)
  const ast = moteur.parse (contenu)
  const procedast = moteur.runsync (AST)

  CleanNode (processEdast)

  Retour ProcessEtast
}
Copier après la connexion

La dernière chose que nous pouvons faire est de supprimer l'objet position qui existe sur chaque nœud, qui contient la position d'origine dans la chaîne Markdown. Ce n'est pas un grand objet (il n'a que deux clés), mais il s'accumule rapidement lorsque l'arbre grossit.

 const CleanNode = node => {
  supprimer le nœud.position
  // ... autre logique de nettoyage}
Copier après la connexion

Résumer

C'est ça! Nous avons réussi à limiter le traitement de Markdown pour construire / du code côté serveur, nous n'envoyons donc pas des temps de démarrage inutiles au navigateur, ce qui augmente inutilement les coûts. Nous transmettons l'arborescence de données au client, et nous pouvons les itérer et les convertir en n'importe quel composant React que nous voulons.

J'espère que cela aide. :)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal