Catégories
Astuces et Design

Création d'un blog avec Next.js

Dans cet article, nous utiliserons Next.js pour créer un cadre de blog statique avec la conception et la structure inspirées de Jekyll. J'ai toujours été un grand fan de la façon dont Jekyll facilite la création d'un blog pour les débutants et, en même temps, offre également un grand degré de contrôle sur tous les aspects du blog pour les utilisateurs avancés.

Avec l'introduction de Next.js ces dernières années, combinée à la popularité de React, il existe une nouvelle avenue à explorer pour les blogs statiques. Next.js facilite la création de sites Web statiques basés sur le système de fichiers lui-même avec peu ou pas de configuration requise.

La structure de répertoires d'un blog Jekyll dépouillé typique ressemble à ceci:

.
├─── _posts/          ...blog posts in markdown
├─── _layouts/        ...layouts for different pages
├─── _includes/       ...re-usable components
├─── index.md         ...homepage
└─── config.yml       ...blog config

L'idée est de concevoir notre framework autour de cette structure de répertoires autant que possible afin qu'il devienne plus facile de migrer un blog depuis Jekyll en réutilisant simplement les publications et les configurations définies dans le blog.

Pour ceux qui ne connaissent pas Jekyll, c'est un générateur de site statique qui peut transformer votre texte brut en sites Web et blogs statiques. Reportez-vous au guide de démarrage rapide pour être opérationnel avec Jekyll.

Cet article suppose également que vous avez une connaissance de base de React. Sinon, la page de démarrage de React est un bon point de départ.

Installation

Next.js est propulsé par React et écrit en Node.js. Nous devons donc installer npm d'abord, avant d'ajouter next, react et react-dom au projet.

mkdir nextjs-blog && cd $_
npm init -y
npm install next react react-dom --save

Pour exécuter les scripts Next.js sur la ligne de commande, nous devons ajouter le next commande au scripts section de notre package.json.

"scripts": {
  "dev": "next"
}

Nous pouvons maintenant courir npm run dev sur la ligne de commande pour la première fois. Voyons ce qui se passe.

$ npm run dev
> (email protected) dev /~user/nextjs-blog
> next

ready - started server on http://localhost:3000
Error: > Couldn't find a `pages` directory. Please create one under the project root

Le compilateur se plaint d'un répertoire de pages manquantes à la racine du projet. Nous découvrirons le concept de pages dans la section suivante.

Concept de pages

Next.js est construit autour du concept de pages. Chaque page est un composant React qui peut être de type .js ou .jsx qui est mappé à une route basée sur le nom de fichier. Par exemple:

File                            Route
----                            -----
/pages/about.js                 /about
/pages/projects/work1.js        /projects/work1
/pages/index.js                 /

Créons le pages répertoire à la racine du projet et remplir notre première page, index.js, avec un composant React de base.

// pages/index.js
export default function Blog() {
  return 
Welcome to the Next.js blog
}

Courir npm run dev encore une fois pour démarrer le serveur et accédez à http://localhost:3000 dans le navigateur pour afficher votre blog pour la première fois.

Capture d'écran de la page d'accueil dans le navigateur. Le contenu dit bienvenue sur le blog next.js.

Hors de la boîte, nous obtenons:

  • Rechargement à chaud afin que nous n'ayons pas à actualiser le navigateur pour chaque changement de code.
  • Génération statique de toutes les pages à l'intérieur du /pages/** annuaire.
  • Fichier statique servant aux actifs vivant dans le/public/** annuaire.
  • Page d'erreur 404.

Accédez à un chemin aléatoire sur localhost pour voir la page 404 en action. Si vous avez besoin d'une page 404 personnalisée, les documents Next.js contiennent d'excellentes informations.

Capture d'écran de la page 404. Il dit 404 Cette page est introuvable.

Pages dynamiques

Les pages avec des itinéraires statiques sont utiles pour créer la page d'accueil, la page à propos, etc. Cependant, pour créer dynamiquement tous nos articles, nous utiliserons la capacité de route dynamique de Next.js. Par exemple:

File                        Route
----                        -----
/pages/posts/(slug).js      /posts/1
                            /posts/abc
                            /posts/hello-world

N'importe quel itinéraire, comme /posts/1, /posts/abc, etc., sera égalé par /posts/(slug).js et le paramètre slug sera envoyé en tant que paramètre de requête à la page. Ceci est particulièrement utile pour nos articles de blog, car nous ne voulons pas créer un fichier par article; à la place, nous pourrions passer dynamiquement le slug pour rendre le post correspondant.

Anatomie d'un blog

Maintenant que nous comprenons les éléments de base de Next.js, définissons l'anatomie de notre blog.

.
├─ api
│  └─ index.js             # fetch posts, load configs, parse .md files etc
├─ _includes
│  ├─ footer.js            # footer component
│  └─ header.js            # header component
├─ _layouts
│  ├─ default.js           # default layout for static pages like index, about
│  └─ post.js              # post layout inherts from the default layout
├─ pages
│  ├─ index.js             # homepage
|  └─ posts                # posts will be available on the route /posts/
|     └─ (slug).js       # dynamic page to build posts
└─ _posts
   ├─ welcome-to-nextjs.md
   └─ style-guide-101.md

API de blog

Un framework de blog de base a besoin de deux fonctions API:

  • Une fonction pour récupérer les métadonnées de tous les messages dans _posts annuaire
  • Une fonction pour récupérer un seul article pour une donnée slug avec le HTML complet et les métadonnées

En option, nous aimerions également que toute la configuration du site définie dans config.yml être disponible sur tous les composants. Nous avons donc besoin d'une fonction qui analysera la configuration YAML dans un objet natif.

Depuis, nous aurions affaire à de nombreux fichiers non JavaScript, comme Markdown (.md), YAML (.yml), etc., nous utiliserons le raw-loader bibliothèque pour charger ces fichiers sous forme de chaînes afin de faciliter leur traitement.

npm install raw-loader --save-dev

Ensuite, nous devons dire à Next.js d'utiliser raw-loader lorsque nous importons des formats de fichier .md et .yml en créant un next.config.js fichier à la racine du projet (plus d'informations à ce sujet).

module.exports = {
  target: 'serverless',
  webpack: function (config) {
    config.module.rules.push({test:  /.md$/, use: 'raw-loader'})
    config.module.rules.push({test: /.yml$/, use: 'raw-loader'})
    return config
  }
}

Next.js 9.4 a introduit des alias pour les importations relatives qui aident à nettoyer les spaghettis des instructions d'importation causés par les chemins relatifs. Pour utiliser des alias, créez un jsconfig.json dans le répertoire racine du projet en spécifiant le chemin de base et tous les alias de module nécessaires au projet.

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@includes/*": ("_includes/*"),
      "@layouts/*": ("_layouts/*"),
      "@posts/*": ("_posts/*"),
      "@api": ("api/index"),
    }
  }
}

Par exemple, cela nous permet d'importer nos mises en page en utilisant simplement:

import DefaultLayout from '@layouts/default'

Récupérer tous les messages

Cette fonction lira tous les fichiers Markdown dans le _posts , analysez l'avant-propos défini au début de la publication à l'aide de la matière grise et renvoyez le tableau de métadonnées pour toutes les publications.

// api/index.js
import matter from 'gray-matter'


export async function getAllPosts() {
  const context = require.context('../_posts', false, /.md$/)
  const posts = ()
  for(const key of context.keys()){
    const post = key.slice(2);
    const content = await import(`../_posts/${post}`);
    const meta = matter(content.default)
    posts.push({
      slug: post.replace('.md',''),
      title: meta.data.title
    })
  }
  return posts;
}

Un article Markdown typique ressemble à ceci:

---
title:  "Welcome to Next.js blog!"
---
**Hello world**, this is my first Next.js blog post and it is written in Markdown.
I hope you like it!

La section décrite par --- est appelé le sujet principal qui contient les métadonnées du message comme, le titre, le permalien, les balises, etc. Voici la sortie:

(
  { slug: 'style-guide-101', title: 'Style Guide 101' },
  { slug: 'welcome-to-nextjs', title: 'Welcome to Next.js blog!' }
)

Assurez-vous d'installer d'abord la bibliothèque de matière grise à partir de npm à l'aide de la commande npm install gray-matter --save-dev.

Récupérer un seul message

Pour un slug donné, cette fonction localisera le fichier dans le répertoire _posts , analysez le Markdown avec la bibliothèque marquée et renvoyez le HTML de sortie avec les métadonnées.

// api/index.js
import matter from 'gray-matter'
import marked from 'marked'


export async function getPostBySlug(slug) {
  const fileContent = await import(`../_posts/${slug}.md`)
  const meta = matter(fileContent.default)
  const content = marked(meta.content)    
  return {
    title: meta.data.title, 
    content: content
  }
}

Exemple de sortie:

{
  title: 'Style Guide 101',
  content: '

Incididunt cupidatat eiusmod ...

' }

Assurez-vous d'installer d'abord la bibliothèque marquée à partir de npm à l'aide de la commande npm install marked --save-dev.

Config

Afin de réutiliser la configuration Jekyll pour notre blog Next.js, nous analyserons le fichier YAML en utilisant le js-yaml bibliothèque et exporter cette configuration afin qu'elle puisse être utilisée entre les composants.

// config.yml
title: "Next.js blog"
description: "This blog is powered by Next.js"


// api/index.js
import yaml from 'js-yaml'
export async function getConfig() {
  const config = await import(`../config.yml`)
  return yaml.safeLoad(config.default)
}

Assurez-vous d'installer js-yaml à partir de npm en utilisant d'abord la commande npm install js-yaml --save-dev.

Comprend

Notre _includes répertoire contient deux composants de base de React,

et
, qui sera utilisé dans les différents composants de mise en page définis dans le _layouts annuaire.

// _includes/header.js
export default function Header() {
  return 

Blog | Powered by Next.js

} 
 // _includes/footer.js export default function Footer() {   return

©2020 | Footer

}

Disposition

Nous avons deux composants de mise en page dans le _layouts annuaire. L'un est le > qui est la disposition de base au-dessus de laquelle tous les autres composants de disposition seront construits.

// _layouts/default.js
import Head from 'next/head'
import Header from '@includes/header'
import Footer from '@includes/footer'


export default function DefaultLayout(props) {
  return (
    
              {props.title}                    
      {props.children}      
   
  ) }

La deuxième disposition est la composant qui remplacera le titre défini dans le avec le titre du message et affichez le code HTML du message. Il comprend également un lien vers la page d'accueil.

// _layouts/post.js
import DefaultLayout from '@layouts/default'
import Head from 'next/head'
import Link from 'next/link'


export default function PostLayout(props) {
  return (
    
      
        {props.title}
      
      
       

{props.title}

       
               
   
  ) }

next/head est un composant intégré pour ajouter des éléments à la de la page. next/link est un composant intégré qui gère les transitions côté client entre les routes définies dans le répertoire des pages.

Page d'accueil

Dans le cadre de la page d'index, également appelée page d'accueil, nous répertorierons tous les messages _posts annuaire. La liste contiendra le titre du message et le lien permanent vers la page du message individuel. La page d'index utilisera le et nous importons la configuration dans la page d'accueil pour passer le title et description à la mise en page.

// pages/index.js
import DefaultLayout from '@layouts/default'
import Link from 'next/link'
import { getConfig, getAllPosts } from '@api'


export default function Blog(props) {
  return (
    
      

List of posts:

     
            {props.posts.map(function(post, idx) {           return (            
  •                               {post.title}                          
  •           )         })}      
   
  ) }  
 export async function getStaticProps() {   const config = await getConfig()   const allPosts = await getAllPosts()   return {     props: {       posts: allPosts,       title: config.title,       description: config.description     }   } }

getStaticProps est appelé au moment de la construction pour pré-rendre les pages en passant props au composant par défaut de la page. Nous utilisons cette fonction pour récupérer la liste de tous les articles au moment de la construction et rendre l'archive des articles sur la page d'accueil.

Capture d'écran de la page d'accueil montrant le titre de la page, une liste avec deux titres de publication et le pied de page.

Page de publication

Cette page affichera le titre et le contenu du message pour le slug fourni dans le cadre du context. La page de publication utilisera le composant.

// pages/posts/(slug).js
import PostLayout from '@layouts/post'
import { getPostBySlug, getAllPosts } from "@api"


export default function Post(props) {
  return 
}


export async function getStaticProps(context) {
  return {
    props: await getPostBySlug(context.params.slug)
  }
}


export async function getStaticPaths() {
  let paths = await getAllPosts()
  paths = paths.map(post => ({
    params: { slug:post.slug }
  }));
  return {
    paths: paths,
    fallback: false
  }
}

Si une page a des itinéraires dynamiques, Next.js doit connaître tous les chemins possibles au moment de la construction. getStaticPaths fournit la liste des chemins qui doivent être rendus en HTML au moment de la construction. La propriété de repli garantit que si vous visitez un itinéraire qui n'existe pas dans la liste des chemins, il renverra une page 404.

Capture d'écran de la page du blog montrant un en-tête de bienvenue et un bleu bonjour au-dessus du pied de page.

Prêt pour la production

Ajoutez les commandes suivantes pour build et start dans package.json, sous le scripts section, puis exécutez npm run build suivi par npm run start pour créer le blog statique et démarrer le serveur de production.

// package.json
"scripts": {
  "dev": "next",
  "build": "next build",
  "start": "next start"
}

Le code source complet de cet article est disponible sur ce référentiel GitHub. N'hésitez pas à le cloner localement et à jouer avec. Le référentiel comprend également des espaces réservés de base pour appliquer le CSS à votre blog.

Améliorations

Le blog, bien que fonctionnel, est peut-être trop basique pour la plupart des cas moyens. Ce serait bien d'étendre le framework ou de soumettre un patch pour inclure plus de fonctionnalités comme:

  • Pagination
  • Mise en évidence de la syntaxe
  • Catégories et tags pour les articles
  • Coiffant

Dans l'ensemble, Next.js semble vraiment très prometteur pour créer des sites Web statiques, comme un blog. Combiné avec sa capacité d'exporter du HTML statique, nous pouvons créer une application vraiment autonome sans avoir besoin d'un serveur!

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *