Creación de un blog con Next.js

Índice
  1. Instalación
  2. Concepto de pagina
  3. Paginas dinamicas
  4. Anatomía de un blog.
  5. API de blogs
  6. Incluye
  7. Diseños
  8. Página principal
  9. Publicar página
  10. Listo para la producción
  11. Mejoras

En este artículo, usaremos Next.js para crear un marco de blog estático con el diseño y la estructura inspirados en Jekyll. Siempre ha sido un gran admirador de cómo Jekyll facilita a los principiantes la configuración de un blog y, al mismo tiempo, proporciona también un gran grado de control sobre cada aspecto del blog para los usuarios avanzados.

Con la introducción de Next.js en los últimos años, combinada con la popularidad de React, existe una nueva vía para explorar los blogs estáticos. Next.js hace que sea muy fácil crear sitios web estáticos basados ​​en el propio sistema de archivos con poca o ninguna configuración requerida.

La estructura de directorios de un típico blog básico de Jekyll se ve así:

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

La idea es diseñar nuestro marco en torno a esta estructura de directorios tanto como sea posible para que sea más fácil migrar un blog desde Jekyll simplemente reutilizando las publicaciones y ajustes definidos en el blog.

Para aquellos que no se conocen con Jekyll, es un generador de sitios estáticos que puede transformar texto sin formato en blogs y sitios web estáticos. Consulte la guía de inicio rápido para comenzar a utilizar Jekyll.

Este artículo también supone que tienes conocimientos básicos de React. De lo contrario, la página de inicio de React es un buen lugar para comenzar.

Instalación

Next.js funciona con React y está escrito en Node.js. Por lo tanto, primero debemos instalar npm, antes de agregarlo nexty al proyecto.reactreact-dom

mkdir nextjs-blog  cd $_npm init -ynpm install next react react-dom --save

Para ejecutar scripts Next.js en la línea de comando, tenemos que agregar el nextcomando a la scriptssección de nuestro archivo package.json.

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

Ahora podemos ejecutar npm run deven la línea de comando por primera vez. Veamos qué pasa.

$ npm run dev nextjs-blog@1.0.0 dev /~user/nextjs-blog nextready - started server on http://localhost:3000Error:  Couldn't find a `pages` directory. Please create one under the project root

El compilador se queja de que falta un directorio de páginas en la raíz del proyecto. Aprenderemos sobre el concepto de páginas en la siguiente sección.

Concepto de pagina

Next.js se basa en el concepto de páginas. Cada página es un componente de React que puede ser de tipo .jso .jsxque está asignado a una ruta según el nombre del archivo. Por ejemplo:

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

Creemos el pagesdirectorio en la raíz del proyecto y completamos nuestra primera página, index.jscon un componente básico de React.

// pages/index.jsexport default function Blog() {  return divWelcome to the Next.js blog/div}

Ejecute npm run devuna vez más para iniciar el servidor y navegue http://localhost:3000en el navegador para ver su blog por primera vez.

Fuera de la caja obtenemos:

  • Recarga en caliente para que no tengamos que actualizar el navegador para cada cambio de código.
  • Generación estática de todas las páginas dentro del /pages/**directorio.
  • Archivo estático que sirve para los activos que se encuentran en el /public/**directorio.
  • Página de error 404.

Navegue hasta una ruta aleatoria en localhost para ver la página 404 en acción. Si necesita una página 404 personalizada, los documentos de Next.js tienen excelente información.

Paginas dinamicas

Las páginas con rutas estáticas son útiles para crear la página de inicio, la página de información, etc. Sin embargo, para crear dinámicamente todas nuestras publicaciones, usaremos la capacidad de ruta dinámica de Next.js. Por ejemplo:

File            Route----            -----/pages/posts/[slug].js   /posts/1              /posts/abc              /posts/hello-world

Cualquier ruta, como /posts/1, /posts/abc, etc., coincidirá con /posts/[slug].jsy el parámetro slug se enviará como parámetro de consulta a la página. Esto es especialmente útil para las publicaciones de nuestro blog porque no queremos crear un archivo por publicación; en su lugar, podríamos pasar dinámicamente el slug para representar la publicación correspondiente.

Anatomía de un blog.

Ahora que entendemos los componentes básicos de Next.js, definimos la anatomía de nuestro 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 blogs

Un marco de blog básico necesita dos funciones API:

  • Una función para recuperar los metadatos de todas las publicaciones en el _postsdirectorio.
  • Una función para buscar una sola publicación para un determinado slugcon el HTML y los metadatos completos.

Opcionalmente, también nos gustaría que toda la configuración del sitio definida config.ymlesté disponible en todos los componentes. Entonces necesitamos una función que analice la configuración YAML en un objeto nativo.

Dado que estaríamos tratando con muchos archivos que no son JavaScript, como Markdown ( .md), YAML ( .yml), etc., usaremos la raw-loaderbiblioteca para cargar dichos archivos como cadenas para que sea más fácil procesarlos.

npm install raw-loader --save-dev

A continuación, debemos decirle a Next.js que use raw-loader cuando importemos formatos de archivos .md y .yml creando un next.config.jsarchivo en la raíz del proyecto (más información al respecto).

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 introdujo alias para importaciones relativas, lo que ayuda a limpiar los espaguetis de las declaraciones de importación causadas por rutas relativas. Para utilizar alias, cree un jsconfig.jsonarchivo en el directorio raíz del proyecto especificando la ruta base y todos los alias de módulo necesarios para el proyecto.

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

Por ejemplo, esto nos permite importar nuestros diseños simplemente usando:

import DefaultLayout from '@layouts/default'

Obtener todas las publicaciones

Esta función leerá todos los archivos Markdown en el _postsdirectorio, analizará el texto inicial definido al comienzo de la publicación usando materia gris y devolverá la matriz de metadatos para todas las publicaciones.

// api/index.jsimport 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;}

Una publicación típica de Markdown se ve así:

---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 sección descrita por ---se llama portada y contiene los metadatos de la publicación, como título, enlace permanente, etiquetas, etc. Aquí está el resultado:

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

Asegúrese de instalar primero la biblioteca de materia gris desde npm usando el comando npm install gray-matter --save-dev.

Obtener una sola publicación

Para un slug determinado, esta función ubicará el archivo en el _postsdirectorio, analizará Markdown con la biblioteca marcada y devolverá el HTML de salida con metadatos.

// api/index.jsimport 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  }}

Salida de muestra:

{  title: 'Style Guide 101',  content: 'pIncididunt cupidatat eiusmod .../p'}

Asegúrese de instalar primero la biblioteca marcada desde npm usando el comando npm install marked --save-dev.

configuración

Para reutilizar la configuración de Jekyll para nuestro blog Next.js, analizaremos el archivo YAML usando la js-yamlbiblioteca y exportaremos esta configuración para que pueda usarse en todos los componentes.

// config.ymltitle: "Next.js blog"description: "This blog is powered by Next.js"
// api/index.jsimport yaml from 'js-yaml'export async function getConfig() {  const config = await import(`../config.yml`)  return yaml.safeLoad(config.default)}

Asegúrese de instalar js-yamldesde npm primero usando el comando npm install js-yaml --save-dev.

Incluye

Nuestro _includesdirectorio contiene dos componentes básicos de React, Headery Footer, que se utilizarán en los diferentes componentes de diseño definidos en el _layoutsdirectorio.

// _includes/header.jsexport default function Header() {  return headerpBlog | Powered by Next.js/p/header}
// _includes/footer.jsexport default function Footer() {  return footerp©2020 | Footer/p/footer}

Diseños

Tenemos dos componentes de diseño en el _layoutsdirectorio. Uno es DefaultLayoutcuál es el diseño base sobre el cual se construirán todos los demás componentes del diseño.

// _layouts/default.jsimport Head from 'next/head'import Header from '@includes/header'import Footer from '@includes/footer'
export default function DefaultLayout(props) {  return (    main      Head        title{props.title}/title        meta name='description' content={props.description}/      /Head      Header/      {props.children}      Footer/    /main  )}

El segundo diseño es el PostLayoutcomponente que anulará el título definido en el DefaultLayouttítulo de la publicación y representará el HTML de la publicación. También incluye un enlace a la página de inicio.

// _layouts/post.jsimport DefaultLayout from '@layouts/default'import Head from 'next/head'import Link from 'next/link'
export default function PostLayout(props) {  return (    DefaultLayout      Head        title{props.title}/title      /Head      article        h1{props.title}/h1        div dangerouslySetInnerHTML={{__html:props.content}}/        divLink href='/'aHome/a/Link/div       /article    /DefaultLayout  )}

next/heades un componente integrado para agregar elementos a headla página. next/linkes un componente integrado que maneja las transiciones del lado del cliente entre las rutas definidas en el directorio de páginas.

Página principal

Como parte de la página de índice, también conocida como página de inicio, enumeraremos todas las publicaciones dentro del _postsdirectorio. La lista contendrá el título de la publicación y el enlace permanente a la página de la publicación individual. La página de índice usará DefaultLayoute importaremos la configuración en la página de inicio para pasar titley descriptional diseño.

// pages/index.jsimport DefaultLayout from '@layouts/default'import Link from 'next/link'import { getConfig, getAllPosts } from '@api'
export default function Blog(props) {  return (    DefaultLayout title={props.title} description={props.description}      pList of posts:/p      ul        {props.posts.map(function(post, idx) {          return (            li key={idx}              Link href={'/posts/'+post.slug}                a{post.title}/a              /Link            /li          )        })}      /ul    /DefaultLayout  )} 
export async function getStaticProps() {  const config = await getConfig()  const allPosts = await getAllPosts()  return {    props: {      posts: allPosts,      title: config.title,      description: config.description    }  }}

getStaticPropsse llama en el momento de la compilación para prerenderizar páginas pasando propsal componente predeterminado de la página. Usamos esta función para obtener la lista de todas las publicaciones en el momento de la compilación y representar el archivo de publicaciones en la página de inicio.

Publicar página

Esta página mostrará el título y el contenido de la publicación slugproporcionada como parte del context. La página de publicación utilizará el PostLayoutcomponente.

// pages/posts/[slug].jsimport PostLayout from '@layouts/post'import { getPostBySlug, getAllPosts } from "@api"
export default function Post(props) {  return PostLayout title={props.title} content={props.content}/}
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 una página tiene rutas dinámicas, Next.js necesita conocer todas las rutas posibles en el momento de la compilación. getStaticPathsproporciona la lista de rutas que deben representarse en HTML en el momento de la compilación. La propiedad alternativa garantiza que si visita una ruta que no existe en la lista de rutas, devolverá una página 404.

Listo para la producción

Agregue los siguientes comandos para buildy starten package.json, en la scriptssección y luego ejecútelos npm run buildseguidos de npm run startpara crear el blog estático e iniciar el servidor de producción.

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

El código fuente completo de este artículo está disponible en este repositorio de GitHub. Siéntete libre de clonarlo localmente y jugar con él. El repositorio también incluye algunos marcadores de posición básicos para aplicar CSS a tu blog.

Mejoras

El blog, aunque funcional, quizás sea demasiado básico para la mayoría de los casos promedio. Sería bueno ampliar el marco o enviar un parche para incluir algunas características más como:

  • Paginación
  • Resaltado de sintaxis
  • Categorías y etiquetas para publicaciones
  • Estilo

En general, Next.js parece realmente muy prometedor para crear sitios web estáticos, como un blog. Combinado con su capacidad para exportar HTML estático, podemos crear una aplicación verdaderamente independiente sin la necesidad de un servidor.

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir

Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion