Fermer

janvier 11, 2022

Créer un blog avec Next.js


Next.js est peut-être le meilleur framework React pour créer votre blog. Parmi les avantages figurent les performances, la taille du bundle et le référencement. Construisons-en un !

Next.js est devenu l'un des frameworks les plus importants pour les applications React. Il aide les développeurs à créer de meilleures applications React de rendu côté serveur sans modèle standard. , prise en charge de TypeScript, référencement, etc.

Créer un blog à l'aide de Next.js est la meilleure option aujourd'hui pour ceux qui souhaitent avoir un blog simple mais puissant, sans se retrouver avec beaucoup de code et tout en augmentant notre classement SEO.

SEO (optimisation des moteurs de recherche) est le processus d'amélioration de votre application pour mieux se positionner sur les moteurs de recherche. C'est très important pour tout blog qui souhaite être mieux classé sur les moteurs de recherche et générer plus de trafic. Une bonne application avec un mauvais classement SEO ne sera pas productive, efficace ou réussie.

Nous allons utiliser Next.js dans cet article pour créer un blog généré de manière statique et prêt pour la production. Nous allons découvrir le fonctionnement de SSG (génération de site statique) et aboutir à un très bon blog avec un référencement efficace.

Prise en main

Nous allons créer une nouvelle application Next.js à l'aide de l'outil CLI Create Next App. Cela nous aide à démarrer facilement avec Next.js et à créer une nouvelle application. Pour commencer, nous allons utiliser la commande suivante :

npx create-next-app blog-with-next-js --example --with-typescript

Nous avons utilisé l'option --example pour créer une nouvelle application Next.js en utilisant l'exemple de nom pour le référentiel Next.js. Nous avons utilisé l'option --with-typescript pour créer une nouvelle application Next.js avec TypeScript.

Maintenant que nous avons notre nouvelle application Next.js, nous allons créer notre structure de dossiers.[19659003]Voici à quoi ressemblera notre structure de dossiers :

-- src
  -- pages
  -- Composants
  -- des articles
  --lib

Nous allons supprimer tous les dossiers provenant de l'interface de ligne de commande Create Next App et créer un nouveau dossier appelé src. Dans le dossier srcnous allons créer tous les dossiers dont nous aurons besoin pour créer notre blog.

Maintenant, nous allons installer toutes les dépendances dont nous aurons besoin.

 fil ajouter @emotion/styled @next/mdx date-fns matière grise mdx-prism next-mdx-remote next-seo read-time rehype remark-autolink-headings remark-capitalize remark-code-titles remark-external -liens remarque-images remarque-slug

Création de nos fichiers

Après avoir installé toutes nos dépendances, nous allons dans notre dossier de pages et créons un nouveau fichier appelé _app.tsx.

Voici comment notre Le fichier _app.tsx va chercher :

function MyApp({ Component, pageProps } : tout) {
  retour <Composant {...pageProps} />[19659022];
}

export default MonApp

Maintenant, dans notre dossier articlesnous allons créer un nouveau fichier appelé introducing-blog-with-nextjs.mdx. Tous les articles de blog de notre blog seront écrits à l'aide de Markdown et devraient avoir un contenu décrit par -- qui est connu sous le nom de matière première. Le premier article contient toutes les informations de notre article de blog.

Voici à quoi ressemblera notre premier article de blog :

---
title : « Présentation du blog avec Next.js »
description: "Un nouveau blog utilisant Next.js et Markdown"
date : "14 avril 2021"
slug: "présentation-blog-avec-nextjs"
ogImage :
  URL : "/images/articles/introducing-blog-with-nextjs.jpeg"
---

Nulla tortor orci, porttitor dans pulvinar sit amet, ultricies sit amet sem. Nullam et posuere felis, sit amet convallis urna. Pellentesque vel ipsum dolor.

Maintenant que nous avons écrit notre premier article de blog, nous allons dans notre dossier lib et créons des fonctions d'aide dont nous aurons besoin.

Nous allons créer un fichier appelé lib.ts et y mettre le code suivant :

import fs from "fs";[19659045]import { join } from "path";
import matière from "gray-matter"[19659022];
import readingTime from "reading-time";
import { API, BlogArticleType  } de "src/types";

const articlesRépertoire = join(process.cwd[19659022](), "src/articles");

fonction getRawArticleBySlug(slug:  chaîne): matière.GrayMatterFile<chaîne> {[19659026]const fullPath = join(articlesDirectory, `${slug}.mdx` );
  const fileContents = fs.readFileSync(fullPath,  "utf8");
  return matter(fileContents);
}

function getAllSlugs (): Array<string> {
  return fs.readdirSync(répertoire articles);
}

fonction getArticleBySlug(
  slug: string,
  champs: string[] = [],
): BlogArticleType {[19659026]const realSlug = slug.replace(/.mdx$/, "")[19659022];
  const { data, contenu } = getRawArticleBySlug(realSlug) ;
  const timeReading: any = readingTime(content);
  const items:BlogArticleType = {};
  
  champs.pourChaque((champ) => {
    if (champ = == "limace") {
      items[field] = realSlug;
    }
    if (field ===  "contenu") {
      éléments[champ] = contenu;
    }
    if (champ ===  "lecture du temps") {
      items[field] = timeReading;
    }
    if (data[field]) {
      éléments[champ] = données[champ];
    }
  })[19659022];
  return items;
}

function getAllArticles(fields: string[ ] = []): Array<BlogArticleType> {
  return getAllSlugs[19659022]()
    .map((slug) => getArticleBySlug(slug, champs))
    .tri((article1, article2) = > (article1.date > article2.date ? -1 :[19659225]1)[1 9659022]);
}

fonction getArticlesByTag(
  balise: chaîne,
  champs: string[] = [],
): Array<BlogArticleType> {
  return getAllArticles(fields)..filter(( article) => {
    const tags = article.tags ?? [];
    balises de retour.comprend(tag);
  })[19659022];
}

function getAllTags(): Array<string> {
  const  articles = getAllArticles(["tags"]);;
  const allTags =  nouveau[19659289]Set<string>();
  articles.forEach((article) => {
    const tags = article .balises as Array<string>;
    tags.forEach((tag) => allTags.add(tag ));
  });
  retour Array.de(tous les tags);
}

export const api: API = {
  getRawArticleBySlug,
  getAllSlugs,
  obtenirTous lesarticles,
  getArticlesByTag,
  getArticleBySlug,
  getAllTags,
};

Une petite explication de ce qui se passe dans ce fichier et de ce que font toutes les fonctions :

  • La fonction appelée getRawArticleBySlug est chargée de récupérer tous nos articles de blog par slug. Il va dans notre dossier d'articles et récupère tous les fichiers par slug et renvoie nos données et le contenu de notre article de blog.
  • La fonction appelée getArticleBySlug est responsable de la réception d'un slug et d'un tableau de champs comme arguments et renvoyer un article de blog.
  • La fonction appelée getAllArticles est chargée de récupérer tous nos articles de blog et de renvoyer un tableau d'articles de blog.

Dans notre dossier srcnous allons créer un fichier types.tsoù nous allons créer toutes nos interfaces et types TypeScript. Dans le fichier, collez le code suivant :

import matière from "gray-matter";

export interface AuthorType {
  nom: chaîne;
  image: chaîne;
}

export interface ArticleType {
  slug: chaîne;
  titre: chaîne;
  description: chaîne;
  date: chaîne;
  coverImage: chaîne;
  auteur: AuthorType;
  extrait: chaîne;
  lecture de l'heure : {
    texte: chaîne;
  };
  ogImage: {
    URL: chaîne;
  };
  content: string;
}

export interface BlogArticleType {
  [key: string]: chaîne | Tableau<chaîne>;
}

export interface  API {
  getRawArticleBySlug: (slug: chaîne) => matière.GrayMatterFile<chaîne >;
  getAllSlugs: () => Tableau<string>;
  getAllArticles: (fields: string[]) => Array<BlogArticleType >;
  getArticlesByTag: (tag: chaîne, champs: chaîne[])[19659027]=> Tableau<BlogArticleType>;
  getArticleBySlug: (slug: chaîne, champs: chaîne[])[19659027]=> BlogArticleType;
  getAllTags: () => Array<string>;
}

Création de nos composants[19659008]Dans notre dossier componentsnous allons créer deux nouveaux dossiers.

Nous allons créer un dossier appelé ArticleItemoù nous allons créer le composant pour le rendu d'un article en tant qu'aperçu.

Nous allons créer un dossier appelé Articleoù nous allons créer notre composant pour le rendu d'un article spécifique.

Nous allons commencer par notre dossier ArticleItem. Dans le dossier, créez un fichier nommé ArticleItem.tsx et un fichier nommé ArticleItem.styles.ts.

Dans notre ArticleItem.styles.tsnous allons créer un style simple pour notre composant en utilisant Emotion. Mettez-y le code suivant :

import styled from "@emotion/styled";

export const ArticleItemContainer = style.article`
  largeur : 100 % ;
  largeur maximale : 800 px ;
  hauteur : fit-contenu ;
  affichage : grille ;
  grille-modèle-colonnes : 1fr ;
  grid-template-rows : 250px repeat(auto-fill, max-content);
  grille-ligne-écart : 20px ;
  align-items: center;

  @media screen et (min-width : 1000px) {
    grille-modèle-colonnes : 340px 1fr ;
    grille-modèle-lignes : 1fr ;
    grille-colonne-écart : 20px ;
    align-items: center;
  }
`;

Maintenant, dans notre fichier ArticleItem.tsxnous allons coller le code suivant :

import React from "react";[19659045]import NextLink from "next/link";

import { ArticleItemContainer } from "./ArticleItem .styles";
import { ArticleType } de "src/types";

interface Accessoires  {
  article: ArticleType;
};

const ArticleItem = ({ article }[19659022]: Accessoires) => (
  <ArticleItemContainer>
    <img
      src={article.ogImage.url}
      alt="Image de l'article"
      style={{ largeur: "100%", hauteur: 250, borderRadius: 5, objectFit: "cover" }}
      lazy="loading"
    />

    <div style={{ display:[19659043]"flex", direction: "column", alignItems: "center", justifierItems:"center" }}>
      <NextLink as={`/blog/ ${article.slug}`} href="/blog/[slug] ">
        <a href="/blog">
          {article.titre}[19659475]</a>
      </NextLink>

      <p style={[19659022]{ color: "#6F6F6F, fontSize: 16, fontWeight: 300 }}>
        {article. description}
      </p>

      <div style={{ afficher :  "flex", direction: "column", alignItems: "center", justifierItems :"centre" }}>
        <p style={{ couleur : "#6F6F6F, fontSize: 16, fontWeight: 300 }} >
          {article.timeReading.text}
        </p>

        <p style={{ couleur: "#6F6F6F, fontSize: 16, fontWeight: 300 }[19659022]}></p>

        <p style={{ couleur: "# 6F6F6F, fontSize: 16, fontWeight: 300 }}>
          {article.date}
        </p>
      </div>

       <NextLink as={`/blog/${article.slug}[19659085]`} href="/blog/[slug]">
        <a href="/ blog" couleur="#6f6f6f">
          Lire l'article
        </a>
      </NextLink>
    </div>[19659435]</ArticleItemContainer>
);

export default ArticleItem;

Ensuite, dans notre dossier Articlenous allons créer un fichier appelé Article.tsx et deux autres dossiers appelés Header et Content.

Dans le dossier Headernous allons créer un fichier appelé Header.tsx et y coller le code suivant :

import React from  "réagir";

interface Accessoires {
  Temps de lecture: {
    texte: chaîne;
  };
  titre: chaîne;
  description: chaîne;
  date: chaîne;
  ogImage: {
    url: chaîne;
  };
}

const En-tête = ({ titre, description, date, ogImage }: Accessoires) => ([19659435]<div style={{ display: "flex", direction: "colonne ", alignItems: "center", justifierItems:"center" }}>[19659436]<p style={{ couleur: "#6F6F6F", fontWeight:  "300", textAlign: "center" }}>
      Publié le {date}
    </p>

    <h1 style={ { color: "#101010", fontWeight: "600", textAlign: " center" }}>
      {title}
    </h1>

    <p style={{ couleur: "#6F6F6F", fontWeight: "300" textAlign: "center" }}>
      {description}
    </p >

    <img
      src={ogImage.url}
      alt="Poster l'image"
      style={{ largeur: "100%", hauteur: 400, borderRadius: 5, objectFit: "cover" }}
      lazy="loading"
    />
  </div>
);

export  par défaut En-tête;

À l'intérieur du Dossier de contenunous allons créer un fichier appelé Content.tsx et y coller le code suivant :

import React from[19659043]"réagir";

interface Accessoires {
  content: React.ReactNode;
};

const Content = ({ contenu }: Accessoires) => (
  <div style={{ display: "flex", direction: "column", alignItems: "center"[19659022], justifierItems:"center" }}>
    {content}
  </div>
);

export default Contenu;

Maintenant, dans notre fichier Article.tsxcollez le code suivant :

import React from "react";
import En-tête de "./En-tête/En-tête";
import Contenu de "./Content/Content";

 interface Accessoires {
  Temps de lecture: {
    texte: chaîne;
  };
  titre: chaîne;
  description: chaîne;
  date: chaîne;
  ogImage: {
    URL: chaîne;
  };
  contenu: React.ReactNode;
  slug: string;
};

const Article = ({
  Temps de lecture,
  titre,
  description,
  date,
  ogImage,
  contenu,
}: Accessoires) => (
  <div style={ { display: "flex", direction: "column", alignItems: "center ", justifierItems:"center" }}>
    <En-tête
      Heure de lecture={Heure de lecture}
      titre={titre}
      description={description}
      date={date}
      ogImage={ogImage}
    />
    <Contenu content={content}  />
    <hr />
  </div>
);[19659033]export default Article;

Rendu de nos articles de blog

Maintenant que nous avons créé nos composants et les fonctions d'assistance dont nous allons avoir besoin, nous allons réellement créer les pages pour afficher nos articles de blog.

Dans notre dossier pagesnous allons avoir un fichier appelé index.tsx où nous afficherons tous nos articles de blog.

Dans le fichier index.tsxnous allons importer le composant ArticleItem que nous avons créé. Après cela, nous allons importer l'API depuis notre fichier lib.ts pour renvoyer tous nos articles de blog.

import React from "react"[19659022];
import ArticleItem from "src/components/ArticleItem/ArticleItem";
import { api } from  "src/lib/lib";
import { BlogArticleType, ArticleType } de "src/types" ;

interface Accessoires {
  articles: Array<ArticleType>;
};

const Index = ([19659022]{ articles }: Accessoires) => (
  <div style={[19659022]{ display: "flex", direction: "column", alignItems:  "center", justifierItems:"center" }}>
    {articles.map[19659022]((article: ArticleType) => (
      <ArticleItem key={article.slug} article={article} />
    ) )}
  <[19659028]/div>
);

Pour chaque article de blog que nous avons, nous allons rendre un composant ArticleItem. Nous recevons nos articles en tant qu'accessoire, mais nous devons les récupérer.

Nous allons utiliser la fonction getStaticProps de Next.js pour récupérer tous nos articles de blog et transmettre nos articles en tant que un accessoire à notre composant.

export const getStaticProps = async () => {
  const articles: Array<BlogArticleType> = api.getAllArticles([
    "slug ",
    "titre",
    "description",
    "date",
    "coverImage",
    "extrait ",
    "timeReading",
    "ogImage",
    "content",
  ]);
   retour {
    accessoires: { articles },
  };
};

Nous affichons désormais correctement tous nos articles de blog. Maintenant, dans notre dossier pagesnous allons créer un dossier appelé blog et à l'intérieur de ce dossier créer un fichier appelé [slug].tsx.

Inside this file, we're going to render a specific blog post. We’re going to import a few dependencies that we’re going to need and again the API from our lib.ts file.

import React from "react";
import readingTime from "reading-time";
import mdxPrism from "mdx-prism";
import renderToString from "next-mdx-remote/render-to-string";
import hydrate from "next-mdx-remote/hydrate";
import { NextSeo } from "next-seo";

import MDXComponents from "src/components/MDXComponents/MDXComponents";
import Article from "src/components/Article/Article";
import { api } from "src/lib/lib" ;
import { BlogArticleType } from "src/types";

interface Props {
  readingTime: {
    text: string;
  };
  frontMatter: {
    title: string;
    description: string;
    date: string;
    content: string;
    ogImage: {
      url: string;
    };
  };
  slug: string;
  source: any;
  tags: Array<string>;
};

const Index = ({ readingTime, frontMatter, slug, source }: Props) => {
  const content = hydrate(source);

  return (
    <div>
      <NextSeo
        title={frontMatter.title}
        description={frontMatter.description}
      />
      <Article
        readingTime={readingTime}
        title={frontMatter.title}
        description={frontMatter.description}
        date={frontMatter.date}
        content={content}
        ogImage={frontMatter.ogImage}
        slug={slug}
      />
    </div>
  );
};

We’re going to use the getStaticPaths from Next.js and pass a list of paths that have to be pre-rendered at build time. We’re also going to use the renderToString function from next-mdx-remote to turn our content into a string and use some plugins for our Markdown text.

type Params = {
  params: {
    slug: string;
    timeReading: {
      text: string;
    };
  };
};

export async function getStaticProps({ params }: Params) {
  const { content, data } = api.getRawArticleBySlug(params.slug);
  const mdxSource = await renderToString(content, {
    components: MDXComponents,
    mdxOptions: {
      remarkPlugins: [
        require("remark-autolink-headings"),
        require("remark-slug"),
        require("remark-code-titles"),
        require("remark-autolink-headings"),
        require("remark-capitalize"),
        require("remark-code-titles"),
        require("remark-external-links"),
        require("remark-images"),
        require("remark-slug"),
      ],
      rehypePlugins: [mdxPrism],
    },
  });
  const tags = data.tags ?? [];
  return {
    props: {
      slug: params.slug,
      readingTime: readingTime(content),
      source: mdxSource,
      frontMatter: data,
      tags,
    },
  };
}

export async function getStaticPaths() {
  const articles: Array<BlogArticleType> = api.getAllArticles(["slug"]);
  return {
    paths: articles.map((articles) => {
      return {
        params: {
          slug: articles.slug,
        },
      };
    }),
    fallback: false,
  };
};

We now have a fully production-ready and statically generated blog using Next.js.

Conclusion

Creating a blog using Next.js is very easy and straightforward. The benefits of Next.js, especially for blogs, are huge. Your blog application will have a very good performance, a small bundle and a good SEO score.




Source link