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

  1. Instalamos las dependencias necesarias:
npm add -S express prismic-javascript prismic-reactjs
  1. Como en el blog vamos a necesitar crear nuestras propias rutas, necesitamos un servidor, y para ello utilizamos express. Creamos el archivo server.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.

  1. 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 con build.
  1. Escribimos npm run dev en la terminal y navegamos a http://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.

Crear un nuevo custom type

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"
      }
    }
  }
}

Blog post type

  • 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:

  1. Creamos el archivo config/index.js y exportamos la variable PRISMIC_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,
};
  1. 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,
};
  1. 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,
};
  1. Escribimos npm run dev en la terminal y navegamos a http://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.

  1. 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>
    );
  }
}
  1. 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,
};
  1. 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,
  });
});

...
  1. Escribimos npm run dev en la terminal y navegamos a http://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:

  1. 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.

  1. 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.

  1. 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"
      }
    }
  },
}

Nueva pestaña SEO dentro del Blog Post Type

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.
  1. Para finalizar, escribimos npm run dev en la terminal y navegamos a http://localhost:3000/ para comprobar que todo funciona correctamente.

Herramientas de debugging