Jak vytvořit blog pomocí Next.js a Markdown.

Ahoj vývojáři! Dnes se podíváme, jak vytvořit svůj blog pomocí Next.js a Markdown!

Markdown

Markdown je jednoduchá syntaxe, která se používá k formátování textu do záhlaví, seznamů, kurzívy, tučného písma atd. Markdown usnadňuje formátování textů za vás. Syntaxe Markdown je jednodušší než HTML. Soubory Markdown končí příponou .md. Soubor Readme, který používáme na GitHubu, používá Markdown.

Zde je příklad syntaxe Markdown

# This is Heading1 <h1>
###### This is Heading6 <h6>
*Bullet Point
1.Numbered Point
_Italic text_

Takže teď už byste pochopili, co Markdown dělá. Na našem webu blogování vytvoříme příspěvky v syntaxi Markdown a zobrazíme je na našem webu.

Začínáme

Vytvořte novou aplikaci Next.js pomocí npx .

npx create-next-app myblog
cd myblog 

Vytvořili jsme nový projekt Next.js s názvem „myblog“. Nyní otevřete tuto složku ve svém oblíbeném editoru kódu. Zde použiji VS kód.

Ke stylování svých webových stránek používám Tailwind CSS. Pokud dáváte přednost Bootstrapu nebo psaní CSS, můžete pokračovat podle svých preferencí. Pokud chcete vědět, jak přidat Tailwind CSS do vaší aplikace Next.js, přečtěte si můj článek zde.

https://dev.to/anuraggharat/how-to-add-tailwind-css-in-next-js-3epn.

Pojďme tedy pochopit, co budeme tvořit.

Vytváříme jednoduchý web, který bude mít dvě stránky – domovskou stránku a stránku blogu. Na domovské stránce bude seznam všech blogů a pro každý blog vygenerujeme samostatné stránky statického blogu.

Takže začněme!

Nastavení projektu.

Vytvořte dvě složky s názvem components a posts v kořenovém adresáři vašeho projektu. Složka Posts bude obsahovat všechny naše příspěvky, které budou napsány v Markdown, zatímco složka Components bude obsahovat všechny naše komponenty, které budeme používat.

Nyní vytvořte složku s názvem blogy ve složce vašich stránek. Do této složky blogů přidejte stránku s názvem [id].js . K prezentaci každého příspěvku použijeme dynamické trasy. Pokud se chcete dozvědět více o dynamických trasách, doporučuji vám přečíst si toto. https://nextjs.org/docs/routing/dynamic-routes

Shrnutí dynamických tras.

Next.js umožňuje vytvářet dynamické trasy pro soubory v hranatých závorkách.

Takže protože máme [id].js ve složce příspěvků, stránka se zavolá, když zavoláme URL localhost:3000/blogs/1243 . Protože je trasa dynamická, cokoliv za /blogs/ bude volat [id].js.
Dále v tomto tutoriálu vytvoříme statickou stránku pro každý příspěvek pomocí getStaticProps() a getStaticPaths() .

Pokračujte vymazáním stávajícího kódu ze souboru index.js. Po dokončení by váš soubor index.js měl vypadat takto.

export default function Home() {
  return (
    <div>

    </div>
  )
}

Takže po tom všem by vám zůstalo něco takového.

Vytváření fiktivních příspěvků Markdown

Potřebujeme alespoň 2 příspěvky, které se zobrazí na našem webu a otestují jej. Pojďme je tedy rychle vytvořit.

Zkopírujte následující fiktivní kód a vytvořte dva soubory v adresáři příspěvků. Pojmenujte soubory podle názvu titulu, protože název souboru budeme používat jako „parametr adresy URL“. Například localhost:3000/blog/first-post

Vytvářím dva soubory se stejným obsahem, ale měním pouze název, abych je mohl rozlišit.

Název mých souborů je první-blog a druhý-blog. Nezapomeňte použít příponu .md.

---
title: 'My First Blog of 2022'
metaTitle: 'My First blog of 2022'
metaDesc: 'How to make a blogging website using Next.js, Markdown and style it using TailwindCSS.'
socialImage: images/pic1.jpg
date: '2022-02-02'
tags:
  - nextjs
  - personal
  - health
  - work
---
# The main content
# One morning, when Gregor Samsa woke from troubled dreams.
One morning, when Gregor Samsa woke from troubled dreams, he found himself *transformed* in his bed into a horrible  [vermin](http://en.wikipedia.org/wiki/Vermin "Wikipedia Vermin"). He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections. The bedding was hardly able to cover **strong** it and seemed ready to slide off any moment. His many legs, pitifully thin compared with the size of the rest of him, link waved abouthelplessly as he looked. <cite>“What's happened to me?”</cite> he thought. It wasn't a dream. His room, a proper human room although a little too small, lay peacefully between its four familiar walls.</p>

## The bedding was hardly able to cover it.
---
title: 'My Second Blog of 2022'
metaTitle: 'My Second blog of 2022'
metaDesc: 'How to make a blogging website using Next.js, Markdown and style it using TailwindCSS.'
socialImage: images/pic2.jpg
date: '2022-02-02'
tags:
  - nextjs
  - personal
  - health
  - work
---

# The main content

# One morning, when Gregor Samsa woke from troubled dreams.
One morning, when Gregor Samsa woke from troubled dreams, he found himself *transformed* in his bed into a horrible  [vermin](http://en.wikipedia.org/wiki/Vermin "Wikipedia Vermin"). He lay on his armour-like back, and if he lifted his head a little he could see his brown belly, slightly domed and divided by arches into stiff sections. The bedding was hardly able to cover **strong** it and seemed ready to slide off any moment. His many legs, pitifully thin compared with the size of the rest of him, link waved abouthelplessly as he looked. <cite>“What's happened to me?”</cite> he thought. It wasn't a dream. His room, a proper human room although a little too small, lay peacefully between its four familiar walls.</p>

## The bedding was hardly able to cover it.

Pod něj jsem přidal mnohem více obsahu. Můžete to přeskočit, protože v tom není žádný rozdíl.

Horní část mezi "- - -" a "- - -" se nazývá Frontmatter. Jsou to v podstatě metadata a nebudou vykreslena.

Vytvoření webu a jeho styling pomocí Tailwind CSS

Kvůli blogu uděláme jen základní ne tak luxusní web s minimálními styly. Ale můžete svobodně použít svou kreativitu. Vytvoříme domovskou stránku, která bude obsahovat seznam všech blogů a stránku blogu, která bude zobrazovat obsah jednotlivých blogů. Takže začněme

Vytvořte znovu použitelnou komponentu rozvržení ve složce komponent a importujte ji do souboru _app.js.

Layout.js

import Link from "next/link";

function Layout({children}) {
  return (
    <div className="w-full min-h-screen ">
      <div className="flex flex-row h-16 justify-around align-middle">
        <h1 className="my-auto text-2xl font-mono">Simple Blog</h1>
        <Link href={`/`}>
          <a className="my-auto">Github Code</a>
        </Link>
      </div>
      <div className="container md:w-3/5 w-5/6 mx-auto mt-16">
        {children}
      </div>
    </div>
  );
}

export default Layout;

Vytvořili jsme jednoduchý layout, kde jsme ponechali hlavičku a pod ní budeme vykreslovat děti.

Importujte tuto komponentu Layout.js do souboru _app.js.

_app.js

import Layout from '../components/Layout'
import '../styles/globals.css'

function MyApp({ Component, pageProps }) {
  return (
    <Layout>
    <Component {...pageProps} />
  </Layout>
  ) 

}

export default MyApp

Nyní vytvoříme znovu použitelnou komponentu karty Blog, která zobrazí blogy na stránce index.js. Pojďme tedy vytvořit komponentu Blogcard.js ve složce komponent.

Blogcard.js

import Link from "next/link";

function Blogcard() {
  return (
    <div className="container w-100 mx-auto mb-16">
      <img
        className="w-3/4 rounded-lg mx-auto drop-shadow-lg"
        src="https://images.pexels.com/photos/675764/pexels-photo-675764.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500"
      />
      <Link href={'/'}>
        <h1 className="text-4xl font-semibold mt-4">
          Here is my first blog of the website
        </h1>
      </Link>
      <p className="text-gray-600 text-sm">2 Feb 2022</p>
      <p>
        This is just a static blog written to test the component structure.This
        is just a static blog written to test the component structure. is just a
        static blog written to test the component structure.
      </p>
    </div>
  );
}

export default Blogcard;

V současné době jsem zde pro účely stylingu přidal fiktivní statická data a obrázky. Jakmile importujeme soubory markdown, přidáme data příspěvků dynamicky. Chcete-li si nyní vyzkoušet, jak bude náš blog vypadat, přidejte nějaká fiktivní data.

Importujte kartu blogu do souboru index.js

index.js

import Blogcard from "../components/Blogcard";

export default function Home() {
  return (
    <div>
      <Blogcard />
      <Blogcard />
    </div>
  );
}

Nyní jsme tedy vytvořili celkovou strukturu našich webových stránek. Nyní musíme vykreslit obsah příspěvků na stránce.

Načítání příspěvků na naši domovskou stránku

Pokračujte a vytvořte složku obrázků ve veřejné složce. Dříve jsme v našem markdownu používali sociální obrázky, toto je složka, kam budeme ukládat všechny obrázky. Obrázky pojmenovávám jako „pic1“ a „pic2“, protože tak jsem je pojmenoval v souborech markdown. Mám 2 krásné obrázky importované z Pexels.

K extrahování obsahu bychom potřebovali balíček s názvem šedá hmota. Nainstalujme jej tedy pomocí „npm“.

npm install gray-matter

Co dělá šedá hmota?

Nyní otevřete svůj soubor index.js. Zde importujeme obsah markdown a analyzujeme jej pomocí šedé hmoty.

Přidejte tyto příkazy importu do index.js.

import fs from 'fs'
//FS to read files 
import matter from "gray-matter";

Nyní použijeme getStaticProps() metoda, což je metoda načítání dat, která běží pouze během doby sestavování a předává stránce rekvizity.

export async function getStaticProps(){
  // Getting all our posts at build time

  // Get all the posts from posts folder
  const files = fs.readdirSync("posts");

  // Loop over each post to extract the frontmatter which we need
  const posts = files.map((file) => {
    // getting the slug here which we will need as a URL query parameter
    const slug = file.replace(".md", "");
    // Reading the contents of the file
    const filecontent = fs.readFileSync(`posts/${file}`, "utf-8");
    const parsedContent = matter(filecontent);
    //The parsed content contains data and content we only need the data which is the frontmatter
    const {data} = parsedContent
    return {
      slug,
      data,
    };
  });

  return {
    props:{
      posts
    }
  }
}

Pokud se chcete dozvědět více o Data Fetching v Next.js, přečtěte si můj další blog.

Zde dostáváme slimáky z názvu souboru. Slugs bude sloužit jako parametr URL pro načtení každého příspěvku. Poté čteme data z každého souboru a analyzujeme je pomocí šedé hmoty. Destrukturujeme data z obsahu, protože chceme pouze data, která jsou frontmatter (meta data) z příspěvků právě teď. Poté shromažďujeme všechna data v poli příspěvků a vracíme je jako rekvizity na stránku index.js. Použijte příkazy protokolu konzoly, abyste lépe pochopili, který řádek co vrací.

Pojďme nyní shromáždit data na stránce index.js a předat je komponentě „Blogcard“.

import Blogcard from "../components/Blogcard";
import fs from 'fs'
import matter from "gray-matter";

export default function Home(props) {
  const {posts} = props
  return (
    <div>

      {posts.map((post,index)=>(
        <Blogcard key={index} post={post} />
      ))}

    </div>
  );
}
export async function getStaticProps(){
  // Getting all our posts at build time

  // Get all the posts from posts folder
  const files = fs.readdirSync("posts");

  // Loop over each post to extract the frontmatter which we need
  const posts = files.map((file) => {
    // getting the slug here which we will need as a URL query parameter
    const slug = file.replace(".md", "");
    // Reading the contents of the file
    const filecontent = fs.readFileSync(`posts/${file}`, "utf-8");
    const parsedContent = matter(filecontent);
    //The parsed content contains data and content we only need the data which is the frontmatter
    const {data} = parsedContent
    return {
      slug,
      data,
    };
  });

  return {
    props:{
      posts
    }
  }
}

Přijímáme data z getStaticProps() funkci a extrahování pole příspěvků z ní. Poté mapujeme pole a předáváme každou položku z pole do komponenty „Blogcard“.

V „Blogcard“ extrahujeme data a vykreslujeme je.

Blogcard.js

import Link from "next/link";

function Blogcard({post}) {
    console.log(post)
  return (
    <div className="container w-100 mx-auto mb-16">
      <img
        className="w-3/4 rounded-lg mx-auto drop-shadow-lg"
        src={post.data.socialImage}
      />
      <Link href={`blog/${post.slug}`}>
        <h1 className="text-4xl font-semibold mt-4">{post.data.metaTitle}</h1>
      </Link>
      <p className="text-gray-600 text-sm">{post.data.date}</p>
      <p>{post.data.metaDesc}</p>
    </div>
  );
}

export default Blogcard;

Takže pokud vše půjde dobře, dostanete své dva příspěvky na svou domovskou stránku. Pokud se zobrazí nějaká chyba, zkontrolujte, zda data, která předáváte, dosáhla součásti nebo ne. Pomocí protokolů konzoly otestujte každý segment kódu.

Výstup

Vytváření jednotlivých stránek pro blogy

Nyní vytvoříme jednotlivé stránky pro každý blog. Vytvoříme jednu stránku, která poběží pro každý příspěvek pomocí getStaticProps() a getStaticPaths() pro každý příspěvek vygenerujeme jednotlivé statické stránky.

Takto vypadá můj [id].js. Funkci jsem přejmenoval na Blog.

export default function Blog() {
  return <div></div>;
}

Otevřete tedy naši stránku [id].js ve složce blogu a přidejte následující kód.

Import šedé hmoty a souborového systému (fs)

import fs from 'fs';
import matter from 'gray-matter';

getStaticPaths()

export async function getStaticPaths() {
  // Get all the paths from slugs or file names
  const files = fs.readdirSync("posts");
  const paths = files.map((files) => ({
    params: {
      id: files.replace(".md", ""),
    },
  }));
  console.log("paths",paths)
  return {
    paths,
    fallback:false
  }
}

V této funkci tedy generujeme pole všech platných cest. Tyto cesty jsou názvy slimáků, které načtou blogové příspěvky pro toto jméno. A my pak vrátíme tyto cesty spolu s nouzovým návratem jako falešné. Záložní zobrazení zobrazí stránku 404 pro nesprávné adresy URL. Přečtěte si více o getStaticPaths() zde

getStaticPaths()

export async function getStaticProps({params:{id}}){
    const fileName = fs.readFileSync(`posts/${id}.md`, "utf-8");
    const { data: frontmatter, content } = matter(fileName);
    return {
      props: {
        frontmatter,
        content,
      },
    };
}

Tato funkce je podobná funkci, kterou jsme napsali na stránce index.js pro načtení seznamu blogů. Jediný rozdíl je v tom, že najdeme jeden příspěvek tím, že vezmeme ID předané v URL a vrátíme celý příspěvek na stránku. Položme nějaký protokol konzoly a zkontrolujme, že přijímáme obsah.

export default function Blog({ frontmatter ,content}) {
  console.log(frontmatter)
  console.log(content);

  return <div></div>;
}

Hurá! Máme obsah! Ale počkejte, obsah, který jsme načetli, je ve formátu markdown, nemůžeme ho zde přímo zobrazit. K tomu vám umožní nainstalovat markdown-it .

npm i markdown-it

Tento balíček převede markdown do HTML kódu, který pak můžeme vykreslit na naší webové stránce.

Přidejte nějaké třídy a vykreslete obsah, jak je uvedeno níže:


import fs from "fs";
import matter from "gray-matter";
import md from 'markdown-it'

export default function Blog({ frontmatter ,content}) {

  return (
    <div>
      <img src={`/${frontmatter.socialImage}`} className="w-3/4 mx-auto" />
      <div className="">
        <h1 className="text-3xl">{frontmatter.title}</h1>
        <div dangerouslySetInnerHTML={{ __html: md().render(content) }}></div>
      </div>
    </div>
  );
}

K aplikaci obsahu HTML na naši webovou stránku používáme „dangerouslySetInnerHTML“.

Nyní je vaším prvním dojmem, že obsah je vykreslen, ale něco vypadá špatně. Ano, typografie ještě není správná. Nebojte se, Tailwind je tu, aby nás zachránil. Nainstalujte tento typografický plugin pro zadní vítr.

npm install -D @tailwindcss/typography

Pomocí tohoto pluginu můžete divu přiřadit „className“ jako „prózu“ a vše v tomto divu nastyluje správným způsobem.

Po instalaci jej přidejte do souboru tailwind.config.js

module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [require("@tailwindcss/typography")],
};

Nyní zadejte className jako prózu do nejvzdálenějšího prvku div vykresleného obsahu.

Takže konečně by váš soubor [id].js měl vypadat nějak takto.

import fs from "fs";
import matter from "gray-matter";
import md from 'markdown-it'

export default function Blog({ frontmatter ,content}) {

  return (
    <div className="w-100">
      <img src={`/${frontmatter.socialImage}`} className="w-3/4 mx-auto" />
      <div className="prose w-3/4  mx-auto">
        <h1 className="text-3xl">{frontmatter.title}</h1>
        <div dangerouslySetInnerHTML={{ __html: md().render(content) }}></div>
      </div>
    </div>
  );
}

export async function getStaticPaths() {
  // Get all the paths from slugs or file names
  const files = fs.readdirSync("posts");
  const paths = files.map((files) => ({
    params: {
      id: files.replace(".md", ""),
    },
  }));
  console.log("paths",paths)
  return {
    paths,
    fallback:false
  }
}

export async function getStaticProps({params:{id}}){
    const fileName = fs.readFileSync(`posts/${id}.md`, "utf-8");
    const { data: frontmatter, content } = matter(fileName);
    return {
      props: {
        frontmatter,
        content,
      },
    };
}

A ano, konečně jste vytvořili svůj osobní blog pomocí Next.js a Markdown. Můžete použít svou vlastní kreativitu a stylizovat.

Blog na mém osobním portfoliu je také postaven pomocí stejné metody. Zkontrolujte to zde.

Portfolio

Odkazuji zde na repozitář GitHub, abyste se k němu mohli odkázat! Děkuji za přečtení. Sledujte mě na twitteru, pravidelně zveřejňuji obsah o vývoji webu a programování. Šťastné kódování!

GitHub – anuraggharat/Simple-Blog: