Rumah > hujung hadapan web > tutorial css > Markdown bertanggungjawab di Next.js

Markdown bertanggungjawab di Next.js

Joseph Gordon-Levitt
Lepaskan: 2025-03-21 10:57:11
asal
807 orang telah melayarinya

Markdown bertanggungjawab di Next.js

Markdown sememangnya format yang hebat. Ia cukup dekat dengan teks biasa bahawa sesiapa sahaja boleh belajar dengan cepat, dan ia cukup berstruktur untuk dihuraikan dan akhirnya ditukar kepada format apa sahaja yang anda inginkan.

Walau bagaimanapun: parsing, pemprosesan, peningkatan, dan penukaran markdown memerlukan kod. Menggunakan semua kod ini pada pelanggan datang pada harga. Ia tidak besar dalam dirinya sendiri, tetapi ia masih beberapa dozen kb kod yang hanya digunakan untuk mengendalikan markdown dan tidak ada tujuan lain.

Dalam artikel ini, saya akan menerangkan bagaimana untuk mengekalkan markdown daripada pelanggan dalam aplikasi Next.js, menggunakan ekosistem bersatu/ucapan (saya tidak tahu nama mana yang hendak digunakan, yang terlalu mengelirukan).

Idea utama

Idea ini hanya menggunakan markdown dalam fungsi getStaticProps di Next.js untuk melakukan ini semasa proses membina (jika anda menggunakan binaan tambahan Vercel, ia dilakukan dalam fungsi tanpa pelayan seterusnya), tetapi ia tidak digunakan di sisi klien. Saya rasa getServerSideProps juga ok, tetapi saya fikir getStaticProps lebih cenderung menjadi kes penggunaan biasa.

Ini mengembalikan AST yang dihasilkan oleh parsing dan pemprosesan kandungan markdown ( Abstrak Sintaks Tree , iaitu, objek bersarang besar yang menggambarkan kandungan kami), dan pelanggan hanya bertanggungjawab untuk menjadikan AST menjadi komponen React.

Saya rasa kita juga boleh menjadikan Markdown sebagai HTML secara langsung di getStaticProps dan mengembalikannya untuk memberi dangerouslySetInnerHtml , tetapi kita bukan orang seperti itu. Keselamatan adalah penting. Juga, fleksibiliti untuk menjadikan Markdown seperti yang kita mahu dengan komponen kita sendiri dan bukannya menjadikannya sebagai HTML tulen. Serius, kawan, jangan buat begitu. ?

 Export const getStaticProps = async () => {
  // Dapatkan kandungan markdown dari suatu tempat, seperti CMS atau sesuatu. Setakat artikel ini, ini tidak penting. Ia juga boleh dibaca dari fail.
  const markdown = menunggu getmarkdownContentFromSomeWhere ()
  const ast = parsemarkdown (markdown)

  kembali {props: {ast}}
}

const page = props => {
  // Ini biasanya termasuk susun atur anda dan sebagainya, tetapi ia ditinggalkan di sini untuk kesederhanaan.
  Kembali<markdownrenderer ast="{props.ast}"></markdownrenderer>
}

halaman lalai eksport
Salin selepas log masuk

Menganalisis markdown

Kami akan menggunakan ekosistem bersatu/ucapan. Kita perlu memasang bersatu dan bersuara-passe, itu sahaja. Ia agak mudah untuk menghuraikan markdown sendiri:

 import {bersatu} dari 'bersatu'
Import Posting dari 'Catatan-Passe'

const parseMarkdown = content => bersatu (). Gunakan (fressparse) .parse (kandungan)

Eksport ParsemarkDown lalai
Salin selepas log masuk

Sekarang, apa yang saya buat masa yang lama untuk memahami adalah mengapa plugin tambahan saya seperti Catatan-Prisma atau Slug tidak berfungsi seperti ini. Ini kerana kaedah bersatu .parse(..) tidak mengendalikan AST menggunakan plugin. Seperti namanya, ia hanya memasangkan kandungan rentetan markdown ke dalam pokok.

Sekiranya kami mahu bersatu untuk memohon plugin kami, kami perlu bersatu untuk melalui apa yang mereka panggil fasa "berjalan". Biasanya, ini dilakukan dengan menggunakan kaedah .process(..) dan bukannya kaedah .parse(..) . Malangnya, .process(..) bukan sahaja parses markdown dan memohon plugin, ia juga menyentuh AST ke dalam format lain (contohnya, menggunakan HTML melalui Catatan-HTML, atau menggunakan JSX melalui RE-REACT). Dan itu bukan apa yang kita mahu kerana kita mahu menyimpan AST, tetapi selepas ia diproses oleh plugin.

 <code>| ........................ process ........................... | | .......... parse ... | ... run ... | ... stringify ..........| -------- ----------输入->- | 解析器| ->- 语法树->- | 编译器| ->- 输出-------- | ---------- X | -------------- | 变换器| --------------</code>
Salin selepas log masuk

Oleh itu, semua yang perlu kita lakukan ialah menjalankan parsing dan menjalankan fasa, tetapi bukan fasa penyerapan. Bersatu tidak menyediakan kaedah untuk melaksanakan dua daripada tiga peringkat ini, tetapi ia menyediakan kaedah yang berasingan untuk setiap peringkat supaya kita dapat melakukannya secara manual:

 import {bersatu} dari 'bersatu'
Import Posting dari 'Catatan-Passe'
Import Ramalan dari 'Catatan-Prisma'

const parsemarkdown = content => {
  enjin const = bersatu (). Penggunaan (fressParse). Gunakan (freakprism)
  const ast = enjin.parse (kandungan)

  // Proses * Unified * mengandungi tiga peringkat yang berbeza: parsing, lari, dan stringification. Kami tidak mahu melalui fasa penyerapan kerana kami mahu menyimpan AST supaya kami tidak dapat memanggil `.process (..)`. Walau bagaimanapun, memanggil `.parse (..)` tidak mencukupi, kerana plugin (dan oleh itu prisma) dilaksanakan semasa fasa larian. Oleh itu, kita perlu memanggil fasa lari secara manual (untuk kesederhanaan, serentak).
  // Lihat: https://github.com/unifiedjs/unified#description
  Kembali Engine.Runsync (AST)
}
Salin selepas log masuk

Lihat! Kami menghuraikan markdown ke dalam pokok sintaks. Kami kemudian menjalankan plugin kami di atas pokok itu (ia dilakukan serentak untuk kesederhanaan, tetapi anda boleh melakukannya secara tidak segerak menggunakan .run(..) ). Walau bagaimanapun, kami tidak menukar pokok kami ke sintaks lain seperti HTML atau JSX. Kita boleh melakukannya sendiri dalam rendering.

Membuat markdown

Sekarang kita mempunyai pokok sejuk kita siap, kita boleh menjadikannya seperti yang kita inginkan. Mari buat komponen MarkdownRenderer yang mengambil pokok itu sebagai harta ast dan menjadikannya dengan komponen React.

 const getComponent = node => {
  suis (node.type) {
    kes 'akar':
      kembali ({Children}) =>  {Children} >

    kes 'perenggan':
      kembali ({anak}) =><p> {anak}</p>

    kes 'penekanan':
      kembali ({anak}) => <em>{anak}</em>

    kes 'tajuk':
      kembali ({kanak -kanak, kedalaman = 2}) => {
        const heading = `h $ {kedalaman}`
        Kembali<heading> {anak}</heading>
      }

    kes 'teks':
      kembali ({value}) =>  {value} >

    / * Mengendalikan semua jenis di sini ... */

    Lalai:
      Console.log ('jenis nod yang tidak diproses', nod)
      kembali ({Children}) =>  {Children} >
  }
}

const node = ({node}) => {
  Const Component = getComponent (node)
  const {children} = node

  Kembali kanak -kanak?
    <component>
      {children.map ((anak, indeks) => (
        <node key="{index}" node="{child}"></node>
      ))}
    </component>
  ): (
    <component></component>
  )
}

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

Eksport React.Memo (MarkDownRenderer)
Salin selepas log masuk

Kebanyakan logik penerima kami terletak di komponen Node . Ia mengetahui apa yang akan diberikan berdasarkan kunci type nod AST (ini adalah kaedah getComponent kami berkaitan dengan setiap jenis nod) dan kemudian menjadikannya. Jika nod mempunyai anak -anak, ia secara rekursif memasuki nod kanak -kanak;

Bersihkan pokok

Bergantung pada plugin Catatan yang kami gunakan, kami mungkin menghadapi isu -isu berikut ketika cuba memberikan halaman:

Ralat: Kesalahan berlaku semasa bersiri. Content [0] .Content.Children [3] .data.hchildren [0] .data.hchildren [0] .data.hchildren [0] .data.hchildren [0] .data.hname (dari getstaticprops dalam '/'). Punca: Undefined tidak boleh diserahkan kepada JSON. Sila gunakan NULL atau isi nilai ini.

Ini berlaku kerana AST kami mengandungi kunci dengan nilai -nilai yang tidak ditentukan, yang bukan sesuatu yang dapat diserahkan dengan selamat kepada JSON. Seterusnya memberi kita penyelesaian: kita boleh menghilangkan nilai sama sekali, atau menggantikannya dengan null jika kita memerlukannya lebih kurang.

Walau bagaimanapun, kami tidak akan membetulkan setiap laluan secara manual, jadi kami perlu melintasi rekursif dan membersihkannya. Saya dapati ini berlaku apabila menggunakan Catatan-Prisma (plugin yang membolehkan penonjolan sintaks blok kod). Plugin tidak menambah objek [data] ke nod.

Apa yang boleh kita lakukan adalah melelehkannya untuk membersihkan nod ini sebelum kembali AST:

 const cleannode = node => {
  jika (node.value === Undefined) Padam Node.Value
  jika (node.tagname === undefined) padam nod.tagname
  jika (node.data) {
    Padam node.data.hname
    Padam node.data.hchildren
    Padam node.data.hproperties
  }

  jika (node.children) node.children.Foreach (CleanNode)

  Node kembali
}

const parsemarkdown = content => {
  enjin const = bersatu (). Penggunaan (fressParse). Gunakan (freakprism)
  const ast = enjin.parse (kandungan)
  Const Processedast = Engine.RunSync (AST)

  CleanNode (diproses)

  pulangan diproses
}
Salin selepas log masuk

Perkara terakhir yang boleh kita lakukan ialah memadam objek position yang wujud pada setiap nod, yang memegang kedudukan asal dalam rentetan markdown. Ia bukan objek besar (ia hanya mempunyai dua kunci), tetapi ia berkumpul dengan cepat apabila pokok itu semakin besar.

 const cleannode = node => {
  padam node.position
  // ... logik pembersihan lain}
Salin selepas log masuk

Meringkaskan

Itu sahaja! Kami berjaya mengehadkan pemprosesan markdown untuk membina/kod sampingan pelayan, jadi kami tidak menghantar runtime markdown yang tidak perlu kepada penyemak imbas, yang tidak perlu meningkatkan kos. Kami lulus pokok data kepada pelanggan, dan kami boleh melangkah ke atasnya dan mengubahnya menjadi komponen reaksi yang kami mahukan.

Harap ini membantu. ""

Atas ialah kandungan terperinci Markdown bertanggungjawab di Next.js. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan