Hasta ahora escribí algunas cosas que podrían ser blog posts (node-tooling o algunas partes de fullstack) pero nunca dediqué el tiempo y esfuerzo necesario para armar uno. Esta es mi historia de cómo modifiqué un framework de blog para que satisfaga mis necesidades.

Descartando las alternativas

Hace unas semanas ya que estoy trabajando en un proyecto personal con muchas visualizaciones de datos y pensé que no sólo sería una buena idea escribir acerca de eso sino también integrar interacciones con las visualizaciones en el mismo blog post. Quería la flexibilidad de poder modificar el HTML y JavaScript (más bien insertar pedazos de HTML y JavaScript en este caso) a mi voluntad.
Estos requerimientos terminaron descartando Wordpress, Jekyll, Ghost y Medium cómo posibles alternativas. No es algo que Wordpress te limite a hacerlo pero tanto PHP cómo la estructura de Wordpress son cosas con las que no estoy familiarizado. Acá es dónde Hexo entra en escena y, de ser necesario, me sería más sencillo de entender código JavaScript.

Otro requerimiento muy importante para mi fué la opción de publicar posts tanto en Inglés cómo en Español.

Siempre hay que volver a la fuente

Después de instalar y crear un nuevo blog con hexo-cli vas a tener una estructura de directorios cómo la siguiente:

1
2
3
4
5
6
7
8
9
.
├── _config.yml
├── db.json
├── node_modules
├── package.json
├── public
├── scaffolds
├── source
└── themes

Dónde el directorio “source” será dónde vas a guardar tus páginas (“About”, “Tags”, etc) y todos tus posts.

Creé dos nuevos blog posts (podés crear uno ejecutando el comando hexo new post yourtitle) con un mismo identificador (leé Front-matter) para saber que aunque estén en diferentes lenguajes representan el mismo blog post. De esa forma significaría para Hexo mostrar dos posts distintos en tus secciones de “Home” o “Archives”.

Mi primer intento en solucionar el problema de duplicados fué modificando la lógica de los templates. Después de jugar un poco con Jade Pug y de resolver el problema parcialmente me dí cuenta que no se integraría correctamente con otros componentes cómo paginación y, algo más importante, que sería una solución basada en el theme actual, si por alguna razón decidiera cambiar a otro theme debería resolver el problema de nuevo.

Hexo tiene una colección (guardada en un archivo json generado de tu directorio “source/_posts”) para posts y esa misma colección es inyectada a todas las secciones del front-end cómo “Home”, “Archives”, “About”, etc. Agregar un parámetro a la query que retorna todos los posts no solucionaría el problema ya que borraría todos los archivos generados de los posts traducidos.

Tuve que seguir lo que hexo generate exactamente hacía para tener una idea de cómo solucionarlo: hay un directorio que contiene un archivo para cada componente que va a generar (“assets”, “page” y “post”). Mirando en el archivo “post.js” vas a encontrar que se está iterando sobre la colección de posts y agregando contenido que no es específico al post en sí, cómo las referencias post.prev y post.next. Ya que no interactua directamente con el resto de los componentes sería un buen lugar para agregar los cambios que necesito.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var translatedPosts = locals.translatedPosts.toArray();
var translatedResults = translatedPosts.map(function(translatedPost){
var originalPost = results.find(function(r){
return r.data.postId === translatedPost.postId;
});

translatedPost.prev = originalPost.data.prev;
translatedPost.next = originalPost.data.next;
return {
path: translatedPost.path,
layout: ['post', 'page', 'index'],
data: translatedPost
};
});

El código anterior va a iterar sobre una lista de posts traducidos y va a mockear las referencias post.prev y post.next para que sean las mismas que el post original tiene.

Ahora lo que nos falta hacer es definir la variable translatedPosts con la colección correspondiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
locals.set('translatedPosts', function() {
var query = {};

if (!self.config.future) {
query.date = {$lte: Date.now()};
}

if (!self._showDrafts()) {
query.published = true;
}
query.translated = true;

return db.model('Post').find(query);
});

Agregué el código anterior después de la sección de código dónde se define la referencia a posts en la línea 122 de index.js

También modifiqué el template de posts para mostrar los links de las traducciones disponibles si están presentes, pero eso si será específico al theme que se utilice.

Conclusions

Encontré que Hexo es de cierta forma bastante flexible y que el código es tanto entendible cómo estructurado.

Podés ver todos los cambios que menciono en el artículo en mi fork de Hexo. Si tenés preguntas o sugerencias de cómo hacer los cambios de otra forma escribime en los comentarios.