Logo Jekyll

En este apunte describo cómo he montado este blog estático “fabricado” con jekyll y hospedado en las GitHub Pages. Los fuentes se encuentran a su vez en el repositorio LuisPalacios.github.io. El sitio ha quedado finalmente configurado en mi dominio: https://www.luispa.com


Seguro que conoces GitHub, una plataforma de colaboración y compartición de código (mediante el sistema de control de versiones git). Por cierto, más info en mi apunte sobre GIT.

Bueno, pues tiene una característica muy útil llamada GitHub Pages, que te permite publicar tus propias páginas web para que las hospede el propio GitHub. Se integra perfectamente con el generador de sitios estáticos llamado Jekyll, que tiene capacidades de blog y es super adecuado para montarte blogs o sitios web personales. Por cierto, está escrito en Ruby y su creador es Tom Preston-Werner, el cofundador de GitHub.

Arquitectura GitHub Pages

El proceso que he seguido, muy, muy resumido:

  • Preparar mi puesto de trabajo (instalarme: Brew, Ruby, Jekyll, Bundler, GIT),
  • Crear un directorio dedicado nuevo y un repositorio local para el futuro LuisPalacios.github.io
  • Escribir “apuntes” en formato markdown (nuevos o migrados desde mi blog antiguo)
  • Conectar con la versión local del sitio en mi ordenador e ir probando…
  • Hacer un git push al repositorio remoto para crear LuisPalacios.github.io
  • Ver cómo GitHub genera las páginas automáticamente.
  • Conectar con la versión pública web del sitio
Ah!, podrás encontrar trucos y documentación adicional sobre cómo he montado mi blog en los issues de GitHub, sobre todo en los haya cerrado y resuelto.


Preparar mi ordenador

A continuación vemos paso a paso lo que he ido haciendo en mi puesto de trabajo, un Mac. Puedes usar windows, mac o linux. De hecho más adelante explico comandos para linux.

Si es un Mac, yo uso la versión de Ruby que viene con Homebrew en vez de la que viene con el Mac para evitar problemas con SIP (Systems Integrity Protection - fuente). También he seguido un par de enlaces interesantes: Jekyll Installation o sobre Git en GitHub y también Bundler.


Homebrew

Si trabajas en un Mac y eres desarrollador o necesitas programas de bajo nivel o de línea de commandos es muy, pero que muy probable que tengas que instalarte Homebrew (o brew por resumir). Se trata de un sistema de gestión de paquetes que simplifica la instalación, actualización y eliminación de programas en los sistemas operativos Mac OS de Apple y GNU/Linux. Creado originalmente por Max Howell, el programa ha ganado popularidad en la comunidad de Ruby on Rails. Lo que más me gusta es que te permite acceder a las últimas versiones de un montón de software libre.

Instalación

➜  ~ > /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Ver qué está instalado:

➜  ~ > brew list
➜  ~ > brew cask list

Actualizar brew:

➜  ~ > brew [-v] update
➜  ~ > brew [-v] upgrade

Ejemplos de instalaciones:

➜  ~ > brew install wget
➜  ~ > brew install imagemagick

Me aseguro que brew está correctamente instalado y actulalizado

➜  ~ > brew update
➜  ~ > brew doctor
➜  ~ > brew --version
Homebrew 3.1.2
➜  ~ > nano $HOME/.zshrc
    PATH=$HOME/bin:/usr/local/bin:/usr/local/sbin:$PATH
    launchctl setenv PATH "/usr/local/bin:/usr/local/sbin:$PATH"


Python

No es necesario instalar Python para lo que estamos discutiendo aquí, pero es un buen momento para hacerlo si lo vas a necesitar en el futuro. Aquí tienes un apunte sobre Python en MacOS


Ruby

Ruby es un lenguaje de programación interpretado, reflexivo y orientado a objetos, creado por el programador japonés Yukihiro “Matz” Matsumoto, quien comenzó a trabajar en Ruby en 1993, y lo presentó públicamente en 1995. Necesitamos Ruby para ejecutar Jekyll.

  • Instalación en MacOS con Homebrew:
➜  ~ > brew install ruby
➜  ~ > nano $HOME/.zshrc
   export PATH=$HOME/0_priv/bin:/usr/local/bin:/usr/local/sbin:/usr/local/opt/ruby/bin:$PATH
   launchctl setenv PATH "/usr/local/bin:/usr/local/sbin:/usr/local/opt/ruby/bin:$PATH"
  • Instalación en Ubuntu
% apt-get install ruby-full
  • Preparar la insalación de Gem’s en HOME (y evitar tener que hacer instalaciones a nivel de todo el sistema), válido para MacOS y para Ubuntu
➜  ~ > nano ~/.zshrc
export GEM_HOME=~/gems
export PATH=~/gems/bin:$PATH


Bundler

Es un gestor de paquetes de software que va a facilitar el trabajo con Jekyll y sus dependencias.

➜  ~ > gem install jekyll bundler

Meses después, tras actualizar Homebrew, Ruby y el propio Macos, me encontré con problemas con el comando gem. Lo resolví ejecutando lo siguiente:

➜  ~ > gem cleanup && gem pristine --all


Jekyll

Jekyll es un generador simple para sitios web estáticos con capacidades de blog; está escrito en Ruby por Tom Preston-Werner (cofundador de GitHub) y es rapidísimo.

Para instalarlo en mi Mac he seguido esta fuente


Prueba de concepto

Una vez que tengo todo lo anterior instalado, intento probar que todo va bien…

➜  ~ > jekyll new test
New jekyll site installed in /Users/luis/test.
➜  ~ > cd test
➜  ~ test > bundle add webrick
➜  ~ test > bundle exec jekyll serve

Desde un browser conecto (y funciona) con mi propio ordenador en: http://127.0.0.1:4000/


luispalacios.github.io

Sigo las instrucciones de pages.github.com y su documentación oficial para crear mi Mi repositorio LuisPalacios.github.io

Realizo un clone en local y cambio al directorio.

➜  ~ > cd github/LuisPalacios.github.io
➜  LuisPalacios.github.io git:(master) >

Creo la nueva rama, sin history ni contenido, con el nombre gh-pages y cambio (checkout) a dicha rama. Decido que el directorio raiz (GitHub sources) sea el “subdirectorio ./docs, así que tengo que crearlo y después crear la rama (branch) “gh-pages” y hacer un checkout hacia ella (cambiar a dicha rama). Github publicará desde dicha rama.


Mi directorio raíz está en: “./docs”

➜  docs git:(master) > git checkout --orphan gh-pages
Switched to a new branch 'gh-pages'
➜  LuisPalacios.github.io git:(master) > mkdir docs
➜  LuisPalacios.github.io git:(master) > cd docs

Creo un nuevo “sitio” con jekyll

➜  docs git:(gh-pages)> jekyll new .

Abro el fichero Gemfile que se ha creado y comento la línea que empieza por gem “Jekyll” y además Añado el gem “github-pages” en la línea que empieza por # gem “github-pages”

#gem "jekyll", "~> 4.2.0"
gem "github-pages", "~> 214", group: :jekyll_plugins

Por último hago un bundle update

➜  docs git:(gh-pages)> bundle update


Acceso en local

Una de las ventajas es que puedo activar un “web server” en local en el mismo ordenador donde estoy editanto los ficheros Markdown. Para conseguirlo, cambio al directorio de los posts (./docs) y ejecuto lo siguiente:

docs git:(gh-pages)> bundle add webrick             <== Esto solo una vez
docs git:(gh-pages)> bundle exec jekyll serve

Para actualizar las páginas en GitHub simplemente hago mi primer commit y empujo la rama actual (el branch “gh-pages”) al remoto (el que está en GitHub) como su upstream.

➜  docs git:(gh-pages)> git commit -m "initial commit"
➜  docs git:(gh-pages)> git push --set-upstream origin 'gh-pages'

Añado doc y sincronizo (push)

➜  docs git:(gh-pages)> cd ..
➜  LuisPalacios.github.io git:(gh-pages)> git add docs
➜  LuisPalacios.github.io git:(gh-pages)> git commit -m "añado docs"
➜  LuisPalacios.github.io git:(gh-pages) > git push

En GitHub configuro el “publishing source for your GitHub Pages site

  • En GitHub, navego hasta el repositorio del sitio
  • Bajo el nombre del repositorio, clic en Configuración
  • En la barra lateral izquierda, clic en Páginas.
  • En Source selecciono la Branch gh-pages y el directorio /docs y lo salvo
Al cabo de unos minutos estará aquí disponible
https://luispalacios.github.io

El siguiente paso es opcional. En mi caso tengo un dominio propio así que seguí la guía para redirigir mi dominio a las páginas de GitHub (básicamente poner un CNAME en tu proveedor) y además activé SSL, por lo tanto mi sitio Blog ahora ya se encuentra aquí:

Documentación sobre cómo redirigir tu dominio
https://www.luispa.com


Paginación

En muchos sitios web, especialmente en los blogs, es muy común dividir el listado principal de publicaciones en listas más pequeñas y mostrarlas en varias páginas. Jekyll ofrece un plugin de paginación, para que poder generar automáticamente un blog paginado, así que he seguido el manual de Jekyll sobre cómo configurar la paginación:

  • Activo la paginación en el fichero _config.yml
paginate: 3
paginate_path: '/page-:num/'
  • Elimino el fichero index original ./docs/index.markdown
➜  docs git:(gh-pages) ✗ > mv index.markdown ..
  • Creo el fichero ./docs/index.html en la raíz del sitio.

---
layout: default
---

<!-- Loop sobre los diferentes apuntes -->
{% for post in paginator.posts %}
  <h1><a href="{{ post.url }}">{{ post.title }}</a></h1>
  <p class="author">
  <!-- Muestro la fecha en castellano -->
  <span class="date">{% assign m = post.date | date: "%-m" %}
                      {{ post.date | date: "%-d de" }}
                      {% case m %}
                      {% when '1' %}enero
                      {% when '2' %}febrero
                      {% when '3' %}marzo
                      {% when '4' %}abril
                      {% when '5' %}mayo
                      {% when '6' %}junio
                      {% when '7' %}julio
                      {% when '8' %}agosto
                      {% when '9' %}septiembre
                      {% when '10' %}octubre
                      {% when '11' %}noviembre
                      {% when '12' %}diciembre
                      {% endcase %}
                      {{ post.date | date: "de %Y" }}</span>
  </p>
  <div class="content">
    {{ post.excerpt }}
  </div>
{% endfor %}

<!-- Enlaces a la paginación -->
<div class="pagination">
    Página:
  {% if paginator.previous_page %}
    <a href="{{ paginator.previous_page_path }}" class="previous">
      Previa
    </a>
  {% else %}
    <span class="previous"></span>
  {% endif %}
  <span class="page_number ">
    ( {{ paginator.page }} de {{ paginator.total_pages }} )
  </span>
  {% if paginator.next_page %}
    <a href="{{ paginator.next_page_path }}" class="next">Siguiente</a>
  {% else %}
    <span class="next ">Siguiente</span>
  {% endif %}
</div>


Búsqueda

Una de las características más útiles de un blog es la posibilidad de buscar dentro de sus artículos pero por desgracia Jekyll no trae ni implementa dicha función. He encontrado una alternativa en este proyecto Simple-Jekyll-Search.

  • Me bajo los scripts a mi ordenador:
➜  ~ > npm install simple-jekyll-search
added 2 packages, and audited 3 packages in 708ms
found 0 vulnerabilities
  • Copio los scripts a docs/assets/js
> cd $HOME/prog.git/github-luispa/LuisPalacios.github.io
➜  > cp $HOME/node_modules/simple-jekyll-search/dest/simple-jekyll-search.* docs/assets/js

➜  > ls -al docs/assets/js
total 48
drwxr-xr-x  5 luis  staff   160  2 may 13:37 .
drwxr-xr-x@ 7 luis  staff   224  2 may 12:38 ..
-rw-r--r--  1 luis  staff  9854  2 may 13:37 simple-jekyll-search.js
-rw-r--r--  1 luis  staff  4379  2 may 13:37 simple-jekyll-search.min.js
-rw-r--r--  1 luis  staff  2491  2 may 07:49 vanilla-back-to-top.min.js
  • Creo el fichero search.json en el directorio raíz de mi blog (recuerdo que es docs)
  ~ > cd prog.git/github-luispa/LuisPalacios.github.io/docs
   > cat > search.json

---
layout: none
---
[
  {% for post in site.posts %}
    {
      "title"    : "{{ post.title | escape }}",
      "category" : "{{ post.category }}",
      "tags"     : "{{ post.tags | join: ', ' }}",
      "url"      : "{{ site.baseurl }}{{ post.url }}",
      "date"     : "{{ post.date }}"
    } {% unless forloop.last %},{% endunless %}
  {% endfor %}
]

Modifico mi fichero ./docs/_includes/footer.html:


<!-- Elemento HTML para realizar la búsqueda -->
<div id="search-container">
    <input type="text" id="search-input" placeholder="buscar...">
    <ul id="results-container"></ul>
</div>

<!-- Script apuntando al script JS que hará la búsqueda -->
<script src="/assets/js/simple-jekyll-search.js" type="text/javascript"></script>

<!-- Configuración -->
<script>
    SimpleJekyllSearch({
    searchInput: document.getElementById('search-input'),
    resultsContainer: document.getElementById('results-container'),
    json: '/search.json'
    })
</script>


Mejoras

Issues

En vez de seguir ampliando este apunte lo que he hecho es crear issuesen github con cada una de las modificaciones y mejoras que quería añadirle.

Puedes encontrarlas entre mis issues cerrados sobre este blog


Actualizaciones

Actualizar Homebrew

➜  ~ > brew update
➜  ~ > brew upgrade

Actualizar bundle

➜  ~ > cd prog.git/github-luispa/LuisPalacios.github.io/docs
➜  docs git:(gh-pages) > bundle update


Resolución de problemas

Tanto si he realizado un clone del repositorio desde cero, como si tengo problemas, esta secuencia siempre me ha ayudado:

brew update
brew upgrade

cd $HOME
rm -fr .gems
gem install jekyll bundler

cd 00.git/02.github-luispa/LuisPalacios.github.io/docs
[rm Gemfile.lock] (si es que existe)
bundle install

# Ya puedo arrancar mi server local
JEKYLL_ENV=development bundle exec jekyll serve --drafts --port 4001

Cuando he tenido que actualizar algo

$ e docs/Gemfile
#gem "github-pages", "~> 214", group: :jekyll_plugins
gem "github-pages", "~> 228", group: :jekyll_plugins
gem uninstall liquid -v 4.0.3
gem update --system

Para actualizar bundle

gem cleanup && gem pristine --all
bundle lock --update --bundler
bundle update

A veces he tenido problemas con permisos en la instalación. Para resolverlo:

# cd /opt/homebrew/Cellar/ruby/3.3.5/lib/ruby/gems/3.3.0/specifications
# rm -fr *.gemspec


Enlaces interesantes

Para mejorar mi sitio de apuntes, algunos enlaces interesantes: