Prismic.io
Introducción
Prismic es un CMS muy fácil de utilizar. Además, cuenta con un plan gratuito que viene muy bien para que lo puedas empezar a probar en tus aplicaciones.
Cómo crear un blog SSR con Prismic.io
Servidor Express
- Instalamos las dependencias necesarias:
npm add -S express prismic-javascript prismic-reactjs
- Como en el blog vamos a necesitar crear nuestras propias rutas, necesitamos un servidor, y para ello utilizamos
express
. Creamos el archivoserver.js
:
/* Vendor */
const express = require('express');
const next = require('next');
const app = next({
dev: process.env.NODE_ENV !== 'production',
});
const handle = app.getRequestHandler();
app
.prepare()
.then(() => {
const server = express();
server.get('*', (req, res) => handle(req, res));
server.listen(3000, err => {
if (err) throw err;
console.log('> Ready http://localhost:3000');
});
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});
Lo que estamos haciendo aquí es crear una instancia de Next.js y un servidor express. De momento, añadimos un único get
para servir todos los requests que le lleguen al servidor.
Volveremos a este archivo más adelante cuando tengamos que añadir la ruta para mostrar la página de un post.
- Como ya no estamos utilizando el servidor que viene con Next.js, tenemos que modificar los scripts de
package.json
:
"scripts": {
"dev": "node server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js"
},
dev
: Ejecuta la aplicación de modo desarrollo. Utiliza HMR (Hot Module Replacement), así que no es necesario refrescar el navegador después de hacer cambios.build
: Prepara la aplicación para ser desplegada en producción. Esto autogenerará un conjunto de archivos en el directorio.next
.start
: Ejecuta la aplicación en modo producción, utilizando los archivos generados conbuild
.
- Escribimos
npm run dev
en la terminal y navegamos ahttp://localhost:3000/
para comprobar que todo funciona correctamente.
Custom Types en Prismic
Para los siguientes pasos, es necesario que te crees una cuenta en Prismic.
Una vez estés dentro de Prismic, tienes que crear un Custom Type, y le das de nombre Blog Post
.
Ahora tenemos que añadir campos de contenido a nuestro blog post type, para lo cual vamos a utilizar este JSON:
{
"Main": {
"title": {
"type": "StructuredText",
"config": {
"single": "heading1",
"label": "Title"
}
},
"uid": {
"type": "UID",
"config": {
"label": "Url"
}
},
"body": {
"type": "StructuredText",
"config": {
"multi": "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item",
"label": "Body"
}
}
}
}
title
: El título del post.url
: Esto será un slug autogenerado a partir del título, pero puede ser editado, por ejemplo para SEO.body
: Aquí es donde irá el contenido del post.
Si quieres saber más sobre Custom Types, puedes seguir leyendo este artículo, Introduction to Custom Type building.
Enlazar Next.js con Prismic
Antes de nada, necesitamos crear y publicar nuestro primer post del blog, para poder después manejarlo con Next.js.
Después, hacemos los siguientes pasos:
- Creamos el archivo
config/index.js
y exportamos la variablePRISMIC_API_URL
, la url de tu API, que comienza con el nombre de tu repositorio de Prismic:
const PRISMIC_API_URL = 'https://mikelgoig-website.prismic.io/api/v2';
export {
PRISMIC_API_URL,
};
- Creamos un servicio para conectarnos con la API de Prismic, en el archivo
api/index.js
:
/* Vendor */
import Prismic from 'prismic-javascript';
/* Config */
import { PRISMIC_API_URL } from '../config';
const getBlogPostsAPI = async params => {
try {
// We initialise the API with Prismic's kit.
const API = await Prismic.api(PRISMIC_API_URL);
// Here we just query the documents with a filter of only returning
// the type of blog_post and order them. Full docs can be found here:
// https://github.com/prismicio/prismic-javascript#query-the-content
const response = await API.query(
Prismic.Predicates.at('document.type', 'blog_post'),
{
orderings: '[my.blog_post.date desc]',
...params
// params will be extra parameters we can pass through with api calls
// such as how many documents to return
}
);
return response;
} catch (error) {
return error;
}
};
export {
getBlogPostsAPI,
};
- Llamamos a la API desde la página donde queramos utilizar los posts:
/* Vendor */
import React, { Component } from 'react';
import Link from 'next/link';
/* Helpers */
import { linkResolver } from '../helpers';
/* API */
import { getBlogPostsAPI } from '../api';
/* Layouts */
import MainLayout from '../layouts/main';
export default class extends Component {
static async getInitialProps() {
const response = await getBlogPostsAPI();
return {
posts: response.results,
};
}
render() {
const { posts } = this.props;
return (
<MainLayout>
<div>
{posts.map((post, index) => (
<Link
key={index}
as={linkResolver(post)}
href={`/post?slug=${post.uid}`}
passHref
>
<div image={post.data.image.url}>
<h3>
{post.data.title[0].text}
</h3>
</div>
</Link>
))}
</div>
</MainLayout>
);
}
}
Te habrás dado cuenta de que estamos importando una función, linkResolver
, que todavía no hemos creado todavía. Esta función va a generar el path correcto según el custom type. Vamos a ello. Creamos el archivo helpers/index.js
:
/**
* Generate the correct path based on the document type.
*
* @param {Object} doc
*/
const linkResolver = doc => {
if (doc.type === 'blog_post') {
return `/blog/${doc.uid}`;
}
return '/';
};
export {
linkResolver,
};
- Escribimos
npm run dev
en la terminal y navegamos ahttp://localhost:3000/
para comprobar que todo funciona correctamente.
Crear la página de detalle de un post
Posiblemente te hayas dado cuenta de que el link al post no funciona, así que vamos a corregirlo.
- Creamos una nueva página para los posts,
pages/blogPost.js
:
/* Vendor */
import React, { Component } from 'react';
import { RichText } from 'prismic-reactjs';
/* Helpers */
import { linkResolver } from '../helpers';
/* API */
import { getBlogPostAPI } from '../api';
/* Layouts */
import MainLayout from '../layouts/main';
export default class extends Component {
static async getInitialProps({ query }) {
const { slug } = query;
const response = await getBlogPostAPI(slug);
return {
post: response,
};
}
render() {
const { post: info } = this.props;
const post = info.data;
return (
<MainLayout>
<article>
<h1>
{post.title.length ? post.title[0].text : ''}
</h1>
{RichText.render(post.body, linkResolver)}
</article>
</MainLayout>
);
}
}
- Añadimos una nueva función para conectarnos con la API en
api/index.js
:
const getBlogPostAPI = async slug => {
try {
// We initialise the API with Prismic's kit.
const API = await Prismic.api(PRISMIC_API_URL);
// We pass up the slug to request the correct blog_post.
const response = await API.query(
Prismic.Predicates.at('my.blog_post.uid', slug)
);
return response.results[0];
} catch (error) {
console.error(error);
return error;
}
};
...
export {
getBlogPostAPI,
getBlogPostsAPI,
};
- Modificamos el archivo
server.js
para que pueda manejar la ruta de los posts:
...
server.get('/post/:slug', (req, res) => {
app.render(req, res, '/blogPost', {
slug: req.params.slug,
});
});
...
- Escribimos
npm run dev
en la terminal y navegamos ahttp://localhost:3000/
para comprobar que todo funciona correctamente.
SEO en Prismic.io
Para personalizar el SEO de cada post, es necesario que primero tengamos unas bases de SEO ya realizadas dentro de nuestra aplicación.
Después, sigue estos pasos:
- Abrimos el archivo
pages/blogPost.js
y añadimos el componente<NextSeo>
de la librería next-seo:
/* Vendor */
import NextSeo from 'next-seo';
export default class extends Component {
render() {
const { post: info } = this.props;
const post = info.data;
const url = `https://mikelgoig.com/post/${info.uid}`;
return (
<MainLayout>
<NextSeo config={{
title: post.title[0].text,
description: post.og_description[0].text,
openGraph: {
url,
type: 'article',
title: post.og_title[0].text,
description: post.og_description[0].text,
images: [
{
url: post.og_image.url,
width: 1200,
height: 1200,
alt: post.og_title[0].text,
},
],
},
}}/>
</MainLayout>
);
}
}
Con esto, hemos conseguido que las meta tags se actualicen cuando navegamos a un post.
- Ahora vamos a utilizar el formato JSON-LD para enriquecer los datos de nuestro post de cara al posicionamiento en Google. Este formato de datos estructurados está estandarizado para proveer información sobre una página y clasificar su contenido. En nuestro caso vamos a clasificar nuestros posts como artículos y vamos a aportar información sobre la fecha en la que fue publicado y su autor. Puedes encontrar más información acerca de cómo funcionan los datos estructurados aquí y aquí.
Modificamos el archivo pages/blogPost.js
:
/* Vendor */
import NextSeo, { BlogJsonLd } from 'next-seo';
export default class extends Component {
render() {
const { post: info } = this.props;
const post = info.data;
const url = `https://mikelgoig.com/post/${info.uid}`;
return (
<MainLayout>
<NextSeo .../>
<BlogJsonLd
url={url}
title={project.og_title[0].text}
images={[
project.og_image.url,
]}
datePublished={info.first_publication_date}
dateModified={info.first_publication_date}
authorName="Mikel Goig"
description={project.og_description[0].text}
/>
</MainLayout>
);
}
}
Lo que hemos hecho aquí ha sido introducir el componente <BlogJsonLd>
de la librería next-seo, que simplemente inserta en la página el JSON-LD de un post con los parámetros introducidos.
Además, te habrás dado cuenta si has intentado lanzar la aplicación de que hay ciertos campos del tipo og_
que no han sido creados todavía en Prismic.
- En el dashboard de Prismic, dentro de nuestro Custom Type, vamos a crear una nueva pestaña, que se llame SEO, y vamos a añadir algunos campos:
{
"Main" : {
...
},
"SEO" : {
"og_title" : {
"type" : "StructuredText",
"config" : {
"single" : "heading1",
"label" : "OG Title"
}
},
"og_description" : {
"type" : "StructuredText",
"config" : {
"single" : "embed",
"label" : "OG Description"
}
},
"og_image" : {
"type" : "Image",
"config" : {
"constraint" : { },
"thumbnails" : [ ],
"label" : "OG Image"
}
}
},
}
Lo que acabamos de hacer es crear tres campos nuevos en la estructura de nuestro Blog Post Type, que servirán para asignarle a cada post los siguientes meta tags:
og-title
: El título de la página.og-description
: La descripción de la página.og-image
: La imagen utilizada cuando la página se comparta en redes sociales. Recuerda que la imagen debería ser de 1200px por 1200px.
- Para finalizar, escribimos
npm run dev
en la terminal y navegamos ahttp://localhost:3000/
para comprobar que todo funciona correctamente.