Siempre tenemos algo que compartir con los demás ya sea alguna experiencia propia, recomendaciones, o algo de conocimiento propio. ¿Y porque no empezar a crear en lugar de solo consumir? así que veamos cómo crear nuestro propio blog en un solo día. En este proyecto usaremos un CMS como backend más específicamente Sanity, crearemos nuestro propio frontend utilizando webpack, y por último haremos deploy del frontend en Now.
<h3>¿Qué es un CMS? y ¿Qué es Sanity?</h3>Un CMS es un Content Management System nos permite gestionar cualquier tipo de contenido que queramos manejar en nuestro sitio web, también podríamos utilizar uno para crear un portafolio. Sanity es un CMS muy sencillo de usar e implementar aparte genera dos diferentes API’s una de ellas es en GraphQL y es la que ocuparemos para mostrar todos los blogs y cada uno individualmente
<h3>Creación de la cuenta de Sanity</h3>Empecemos creando la cuenta para poder ocupar Sanity, es muy sencillo nos dirigimos a manage.sanity.io y seleccionamos de qué manera iniciaremos sesión por Google, Github o con nuestro correo electrónico, si seleccionamos Google o Github solo nos redirigirá al inicio de sesión del servicio que escogimos y nos creará la cuenta automáticamente pero si escogemos la opción de nuestro correo electrónico está la opción de registrarse y el formulario es muy sencillo es como si te registraras en cualquier otro lado. Una vez creada nuestra cuenta iniciamos sesión.
<h4>Creación del proyecto en Sanity</h4>Empecemos a crear nuestro CMS lo primero es instalar el CLI de Sanity globalmente:
$ npm install @sanity/cli -g
Ahora creemos el directorio del proyecto y nos ubicamos dentro del directorio:
$ mkdir blog-sanity && cd blog-sanity
Luego tenemos que iniciar sesión en la consola:
$ sanity login
Nos aparecerán las mismas tres opciones de inicio de sesión seleccionamos la de nuestra preferencia y nos redirigirá al navegador para completar el proceso, una vez iniciada sesión nos lo mostrará en la consola.
Por último, inicializamos el proyecto de Sanity:
$ sanity init
Seleccionamos en crear un nuevo proyecto:
Luego le ponemos un nombre:
Nos preguntara que si queremos usar la configuración por defecto del daset y seleccionaremos que si:
Ahora escogeremos la ubicación del proyecto en nuestro equipo:
Y al final seleccionaremos la plantilla del proyecto, en nuestro caso, seleccionaremos la plantilla del blog:
Ahora sólo hay que hacer deploy del Studio de Sanity donde podremos crear, editar o eliminar todo nuestro contenido que creemos y la API de GraphQL.
Primero el Studio:
$ sanity deploy
Nos pedirá escoger un nombre:
Y ahora la API de GraphQL:
$ sanity graphql deploy --playground
Con esto todo tenemos todo lo necesario para crear blogs y tener la API a donde hacer peticiones para mostrar todos e individualmente los blogs. Pasemos a la creación de contenido nos dirigiremos a la url que nos generó Sanity al hacer el deploy del Studio y crearemos nuestra primera categoría, un autor y un blog sencillo:
El contenido del blog lo pondremos en el body ahí podemos crear contenido con imágenes, listas, texto obviamente y otros.
También necesitamos agregar permisos de origen al localhost para que cuando pidamos datos en modo desarrollo podamos acceder a ellos. Para eso nos dirigiremos a Sanity y seleccionaremos nuestro proyecto(1), ahora en las configuraciones de API y justo en la sección de CORS Origins añadiremos el origen de desarrollo “http://localhost:8080/”(2)
El frontend lo crearemos usando React y Webpack, con webpack podemos tener más control y personalización de nuestro proyecto que con Create React App ya que solo instalaremos las dependencias necesarias que ocuparemos. El frontend se terminará viendo de la siguiente manera, pero lo puedes personalizar a tu gusto cambiando los estilos:
Empecemos creando el directorio del frontend y ubicándonos en él:
$ mkdir blog && cd blog
Continuemos con la inicialización del proyecto:
$ npm init -y
Ahora con la instalación de webpack:
$ npm i -D webpack webpack-cli webpack-dev-server
Luego con la instalación de Babel:
$ npm i -D @babel/core @babel/preset-env @babel/preset-react babel-loader
Seguido de los plugins y loaders para CSS y HTML
$ npm i -D css-loader mini-css-extract-plugin style-loader html-loader html-webpack-plugin
Ahora con React:
$ npm i -S react react-apollo react-dom react-router-dom
Luego con las dependencias necesarias para poder hacer la conexión a la API de GraphQL generada y las peticiones a ellas:
$ npm i -S react-apollo apollo-boost graphql
Y por último con una dependencia para poder mostrar las imágenes dentro del contenido de Sanity en el blog:
$ npm i -S @sanity/image-url
La estructura de carpetas de este proyecto será la siguiente, pero eres libre de usar la que más te guste:
Ahora pasemos a configurar webpack. Hay que crear el archivo webpack.config.js en la raíz del proyecto con el siguiente código:
const path = require('path');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: './src/index.js', //Es el archivo o archivos que webpack usara para empaquetar la aplicaciónoutput: {
path: path.resolve(__dirname, 'dist'), //Es la dirección donde se guardará el archivo o archivos resultantes del empaquetado.filename: 'bundle.js'//Sera el nombre del archivo o archivos resultantes
},
devServer: {//Configuración del servidor de desarrollo de webpackhistoryApiFallback: true
},
resolve: {
extensions: ['.js', '.jsx']
},
module: {
rules: [//Es toda la configuración de los loaders para los tipos de archivos que se usarán en el proyecto
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader'
}
]
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
'css-loader'
]
}
]
},
plugins: [//Configuración de los plugins que ocupara webpacknew HtmlWebPackPlugin({
template: './public/index.html',
filename: './index.html'
}),
new MiniCssExtractPlugin({
filename: 'assets/[name].css'
})
]
};
Pasemos a la configuración de babel para poder usar las nuevas características de JavaScript y JSX que es la forma en que se escribe código en React. Crearemos el archivo .babelrc en la raíz del proyecto con el siguiente código:
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
Por último, para tener lista la configuración inicial del frontend creemos el archivo index.html en la carpeta public y también crearemos unos scripts en el package.json para facilitarnos el desarrollo:
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><metahttp-equiv="X-UA-Compatible"content="ie=edge"><title>Blog</title></head><body><divid="app"></div></body></html>
{
//..."scripts": {
"now-build": "npm run build",
"build": "webpack --mode production",
"dev": "webpack-dev-server --open --mode development"
},
//...
}
Ahora empecemos a escribir los archivos necesarios para tener nuestro frontend básico con rutas, primero el index.js dentro de la carpeta src:
Luego crearemos el archivo App.jsx en la carpeta containers, aquí estarán todas las rutas del blog:
Seguiremos con de todos los containers faltantes que son Home.jsx, Blogs.jsx, Blog.jsx y NotFound.jsx:
Por último, con todos los components que son Layout.jsx, Header.jsx y Footer.jsx:
Listo ya tenemos nuestro frontend completo, pero sin estilos sólo hay que correr el siguiente comando para poder probarlo en nuestro equipo:
$ npm run dev
<h3>Conexión al backend</h3>
¡Genial! Ya casi acabamos nuestro proyecto solo nos falta hacer la conexión a la API y mostrar los datos, la cual la haremos por GraphQL como lo hemos estado diciendo, si no sabes que es te recomiendo el curso Básico de GraphQL, pero básicamente es un lenguaje tipado para construir API’s y hacer queries.
¿Y que son las queries? Es la forma de hacer peticiones a la base de datos de ciertos datos filtrados o no para mostrarlos en el Frontend. La forma de hacerlo en GraphQL es con la palabra reservada “query”, un ejemplo sería el siguiente:
query getBlogs{
allBlogs(limit:10){
_id
}
}//Esto quiere decir que traerá el "_id" de diez blogs.
¿Y dónde puedo probar las queries? Para saber si funcionan y que datos recibirás puedes ir al siguiente enlace “https://<PROJECT_ID>.api.sanity.io/v1/graphql/<DATASET>/default”, el PROJECT_ID y el DATASET los encontraras en Sanity
Ahora vamos a modificar el index.js para hacer la conexión a la API antes generada y que nuestra aplicación tenga acceso a todos los datos.
Luego de modificar el index.js vamos a crear dos higher order component (HOC) que en español sería “componentes de orden superior” uno nos ayudará a traer todos los blogs para luego mostrarlos y el otro nos ayudará a traer imágenes que hayamos puesto en el contenido del blog en Sanity. Los pondremos dentro de la carpeta hoc.
El primero lo nombraremos como withBlogs.js y tendrá el siguiente código:
import { graphql } from 'react-apollo';
import { gql } from 'apollo-boost';
const GET_BLOGS = gql`
query getBlogs{ //Esta será la query que ocuparemos para poder traer todos los blogs
blogs: allPosts(limit: 10 offset: 0) {
_id
title
author{
name
}
mainImage{
asset{
url
}
hotspot{
height
width
}
crop{
_type
}
}
categories{
title
}
bodyRaw
slug{
current
}
publishedAt
}
}
`;
export const withBlogs = graphql(GET_BLOGS);
El segundo lo nombraremos como UrlFor.js y tendrá el siguiente código:
import imageUrlBuilder from '@sanity/image-url';const builder = imageUrlBuilder({
projectId: '', //Aquí irá el id del projecto que nos generó Sanitydataset: '',//Aquí irá el nombre del dataset que querramos ocupar básicamente es la base de datos donde se guardara todo nuestro contenidouseCdn: false
});
exportfunctionurlFor(source) {
return builder.image(source);
}
Ahora modifiquemos el container Blogs.jsx para mostrar todos los blogs de la API:
En estos momentos ya deberíamos poder ver todos los blogs en la ruta “/blogs”, sólo nos faltaría poder ver un blog individualmente, para eso modificaremos el container Blog.jsx de la siguiente manera:
import React from 'react';
import { gql } from 'apollo-boost';
import { Query } from 'react-apollo';
import IndividualBlog from '../components/IndividualBlog';
const GET_SINGLE_BLOG = gql`
query getBlog($id: ID!) {
blog: Post(id: $id){
_id
title
author{
name
twitter
}
mainImage{
asset{
url
}
}
categories{
title
}
bodyRaw
slug{
current
}
publishedAt
}
}
`;
const renderProp = ({ loading, error, data }) => {
if (loading) return <p>Loading...</p>
if (error) return <p>Error!</p>
const { blog = {} } = data;
return <IndividualBlog {...blog} />;
};
const Blog = (props) => {
const { match: { params: { id } } } = props;
return (
<Query query={GET_SINGLE_BLOG} variables={{ id }}>
{renderProp}
</Query>
);
};
export default Blog;
Y necesitamos crear un nuevo componente para darle formato a la información recibida de la query del blog individual el cual lo llamaremos IndividualBlog.jsx en la carpeta compenents y tendrá el siguiente código:
import React from 'react';
import { urlFor } from '../hoc/UrlFor';
const IndividualBlog = (props) => {
const {
title,
author: { name, twitter } = {},
mainImage: {
asset: { url }
} = {},
categories = {},
bodyRaw,
slug: { current } = {},
publishedAt
} = props;
const publishedDate = publishedAt.replace(/-/g, "/");
const formatedPublishedDate = publishedDate.split("T");
return (
<section className="blog">
<img className="blog-mainImg" src={url} alt={current} />
<div className="blog-title-container">
<h1>{title}</h1>
<div>
<span>Author: <a href={twitter} target="_blank">@{name}</a></span>
{categories.map(({ title }) => <span key={title}>{title}</span>)}
<span> Publication date: {formatedPublishedDate[0]}</span>
</div>
</div>
<div className="blog-content">
{
bodyRaw.map(({ _key, _type, asset, children, style, level, listItem }) => {
switch (_type) {
case "image":
return (
<div key={_key}>
<img src={urlFor(asset._ref)} alt={asset._ref} />
</div>
);
case "block":
if (listItem) {
return (
<ul key={_key}>
<li>{children.map(({ _key, text }) => (
text
))}</li>
</ul>
)
}
return (
<p key={_key}>
{
children.map(({ _key, text }) => {
return text;
})
}
</p>
);
default:
return <h1>No hay contenido en el blog</h1>;
}
})
}
</div>
</section>
);
};
export default IndividualBlog;
¡Perfecto! Hemos acabado el proyecto está todo listo para poder hacer contenido y crear blogs, solo nos faltaría darle estilos, pero esos los puedes agregar tú a tú gusto, pero si quieres usar los que yo use para este proyecto y se vea tal y como te mencione que se vería te dejo el repositorio de Github para que los descargues.
Blog with React and Sanity
Bueno el proyecto ya está terminado, pero nos falta algo, el blog no está funcionando en línea y los demás no nos pueden leer, veamos como lo podemos poner en línea rápido y sencillamente. Utilizaremos un servicio que se llama Now es muy útil para cuando queremos tener este tipo de proyectos en línea rápidamente y sin necesidad de preocuparnos por manejar algún servidor o un dominio, lo mejor de todo es que es gratis, lo único que necesitamos es agregar dos archivos más a nuestro proyecto y crearnos una cuenta en Now y estará listo para que todos puedan ver nuestro contenido.
Para crearnos una cuenta es muy sencillo es como cualquier otra plataforma nos dirigiremos al siguiente enlace https://zeit.co/login y ahí crearemos la cuenta, tiene la opción de crear la cuenta con Gitlab y Github. Una vez creada la cuenta instalaremos el CLI de Now para poder subir el proyecto de la siguiente manera:
$ npm i now -g
Continuemos con la creación de los archivos necesarios para poder subir el proyecto a Now, primero crearemos el archivo now.json el cual tendrá el siguiente código:
{
"version": 2,
"name": "Blog", //Es el nombre que tendrá el proyecto en Now
"builds": [
{
"use": "@now/static-build",
"src": "package.json"
}
],
"routes": [
{
"src": "(.*).js",
"dest": "/$1.js"
},
{
"src": "(.*).css",
"dest": "/$1.css"
},
{
"src": "(.*).png",
"dest": "/$1.png"
},
{
"src": "(.*).jpg",
"dest": "/$1.jpg"
},
{
"src": "/.*",
"dest": "/index.html"
}
]
}
El ultimo archivo que crearemos será .nowignore funciona muy parecido a .gitignore y lo único que tendrá escrito será lo siguiente:
node_modules/
Si sabes usar git sabes para que sirve esta línea si no te explico rápido lo único que indica es que no se subirá la carpeta node_modules a Now así de sencillo, todo lo que este en este archivo será ignorado por Now y no se subirá.
Ahora iniciemos sesión por la consola y con esto solo nos faltara un paso para tener nuestro proyecto en línea.
$ now login
Listo ya iniciamos sesión por la consola ahora subamos el proyecto a Now con el siguiente comando
$ now
Es realmente sencillo verdad, cuando termine de subir todos los archivos nos dará la url donde estará en línea nuestro blog y eso es todo. Podemos personalizar un podo la url que nos ofrece en la sección de “Domains”.
Por último, siempre tenemos que asegurarnos de la seguridad así que cambiaremos el dataset de Sanity de público a privado para que solo nosotros podamos usarlo y crearemos tokens para poder autenticar que somos nosotros los que accedemos a la API que nos genera Sanity, también tenemos que agregar permisos de origen para que Sanity le de acceso a la url que nos generó Now de poder hacer peticiones a la API.
Cambiar el dataset de público a privado
Creación de los Tokens necesarios para poder acceder a la API
Estos tokens solo serán visibles por única vez así que asegúrate de guardarlos bien y de no perderlos.
Agregar la url generada de Now a los CORS
Este paso es muy similar a cuando le dimos permiso al localhost para poder acceder a los datos en modo desarrollo
Implementación de los Tokens al proyecto
Ahora lo único que tenemos que hacer para poder acceder por tokens es hacer una pequeña modificación en el index.js de la siguiente manera:
y en el HOC UrlFor.js de la siguiente manera:
Con todo esto solo nosotros podremos acceder a la API’s que Sanity nos generó.
Eres libre de modificar el proyecto a tu gusto y si lo haces te invito a tagearme en Twitter para que me compartas los cambios que hiciste y también te invito a decirme que tal te pareció el tutorial 😁. @TuentyFaiv
¿Y qué fue lo que aprendimos? Aprendimos que es un CMS y para qué sirven, a usar Sanity, a crear proyectos con él, desplegar el Studio de nuestro CMS y generar nuestra API de GraphQL seguido de poder crear un proyecto de React con Webpack y sin Create React App, saber cuál es el beneficio de usar Webpack y poder conectar la API generada y también a hacer el despliegue de nuestro Frontend con Now.
Te dejo unos cursos para veas a más profundidad alguno de los temas que vimos: