En los últimos años, los generadores de sitios estáticos o SSG (del inglés Static Site Generator) se han convertido en herramientas muy populares para la creación de páginas web. Este tipo de sitios web destacan por su sencillez, rendimiento y seguridad. Al compararlos con las webs construidas mediante los sistemas de gestión de contenidos o CMS (del inglés Content Management System) se reduce la complejidad y se eliminan sobrecargas innecesarias y vulnerabilidades. Sin embargo, al prescindir de una base de datos, no se puede servir contenido dinámico. Esto quiere decir que la limitación que existe es que el servidor sólo puede devolver el contenido que se haya compilado previamente y no permite realizar cambios en tiempo real. Entre los SSG más valorados1, se encuentran NestJS, Hugo, Gatsby, Mkdocs, Jekyll y Sphinx.
A continuación, utilizando las opciones de CI/CD que proporciona GitLab se detallan los pasos para desplegar una página web estática generada con Mkdocs y Hugo. Además, en el caso de Mkdocs, se utilizará pandoc para generar un documento PDF compilado a través de LaTeX. Ambos ejemplos contarán con la opción de multilenguaje.
Índice de Contenidos
Documentación con Mkdocs
Mkdocs es un generador de sitios estáticos rápido y sencillo que está orientado a la construcción de documentación de proyectos. Los ficheros de la documentación se escriben en Markdown, y se configuran con un archivo YAML. Como tema se utilizará Material for MkDocs y posteriormente, utilizando pandoc se convertirán los archivos markdown a un archivo PDF compilado mediante la plantilla Eisvogel de LaTeX. Se creará un archivo PDF para los distintos lenguajes utilizados.
Esta publicación detalla lo que se ha realizado en el repositorio mkdocs-material que es una plantilla para desplegar rápidamente la documentación. Se recomienda tener dicho repositorio de referencia.

Portada | Índice |
---|---|
![]() | ![]() |
Imágenes | Primer capítulo |
---|---|
![]() | ![]() |
Instalación y creación del proyecto
En primer lugar, se instalará material for mkdocs utilizando pip install mkdocs-material
o se usará mediante la imagen oficial docker pull squidfunk/mkdocs-material
. Una vez instalado se creará un nuevo proyecto con:
Alternativamente, si se está utilizando Docker:
Lo anterior creará la siguiente estructura:
.
├─ docs/
│ └─ index.md
└─ mkdocs.yml
Según esta discusión del proyecto mkdocs-material, para habilitar el multilenguaje y poder modificar las imágenes actualizaremos la estructura del proyecto a la mostrada a continuación. Es importante tener en cuenta que se crean dos archivos de configuración mkdocs.yml
y pdf_metadata_***.md
distintos para cada lenguaje, su contenido se muestra un poco más abajo. Además, las imágenes se guardarán en overrides/assets/images/
y las plantillas de latex se guardan en el directorio latex-templates
, aunque únicamente utilizaremos la plantilla eisvogel.latex
.
.
├── config
│ ├── en
│ │ └── mkdocs.yml
│ └── es
│ └── mkdocs.yml
├── docs
│ ├── en
│ │ ├── index.md
│ │ └── example.md
│ └── es
│ ├── index.md
│ └── example.md
├── latex-templates
│ ├── default.latex
│ ├── eisvogel.latex
│ └── pandoc-scholar.latex
├── overrides
│ └── assets
│ └── images
│ ├── favicon.ico
│ ├── logo-red.svg
│ └── logo.svg
├── pdf_metadata_esp.md
└── pdf_metadata_eng.md
El contenido del archivo config/es/mkdocs.yml
es el siguiente:
site_name: Docs Name
site_description: Descripción...
docs_dir: '../../docs/es' # Where to find the Spanish markdown files
site_dir: '../../public/es' # Where to put the Spanish HTML files
repo_url: https://lab.gsi.upm.es/docs/mkdocs-material/
edit_uri: edit/main/docs/
nav:
- Inicio: index.md
- Ejemplo: example.md
theme:
name: material
language: es
custom_dir: '../../overrides/' # This is where the customization of the theme lives
logo: assets/images/logo-red.svg # The logo is shared by all languages
favicon: assets/images/favicon.ico # The favicon is shared by all languages
include_search_page: true
search_index_only: true
palette:
# Light mode
- media: "(prefers-color-scheme: light)"
scheme: default
primary: indigo
accent: indigo
toggle:
icon: material/toggle-switch-off-outline
name: Switch to dark mode
# Dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: blue
accent: blue
toggle:
icon: material/toggle-switch
name: Switch to light mode
plugins:
- search
- minify:
minify_html: true
minify_js: true
htmlmin_opts:
remove_comments: true
- pandoc:
enabled_if_env: ENABLE_PANDOC_EXPORT
combined: true
combined_output_path: docs.pdf
- git-revision-date-localized:
timezone: Europe/Madrid
locale: es
fallback_to_build_date: false
enable_creation_date: true
markdown_extensions:
- toc:
permalink: "#"
toc_depth: 3
- attr_list
- footnotes
- pymdownx.tasklist:
custom_checkbox: true
extra:
social:
- icon: fontawesome/brands/gitlab
link: https://lab.gsi.upm.es/docs/mkdocs-material
- icon: fontawesome/brands/gitter
link: https://gitter.im/repo
- icon: fontawesome/brands/docker
link: https://lab.gsi.upm.es/docs/mkdocs-material/container_registry
- icon: fontawesome/brands/twitter
link: https://twitter.com/
alternate:
- link: /docs/mkdocs-material/
name: en - English
lang: en
- link: /docs/mkdocs-material/es/
name: es - español
lang: es
Mientras que el contenido del archivo config/en/mkdocs.yml
es el siguiente:
site_name: Docs Name
site_description: Description...
docs_dir: '../../docs/en' # Where to find the English markdown files
site_dir: '../../public/en' # Where to put the English HTML files
repo_url: https://lab.gsi.upm.es/docs/mkdocs-material/
edit_uri: edit/main/docs/
nav:
- Home: index.md
- Example: example.md
theme:
name: material
language: en
custom_dir: '../../overrides/' # This is where the customization of the theme lives
logo: assets/images/logo-red.svg # The logo is shared by all languages
favicon: assets/images/favicon.ico # The favicon is shared by all languages
include_search_page: true
search_index_only: true
palette:
# Light mode
- media: "(prefers-color-scheme: light)"
scheme: default
primary: indigo
accent: indigo
toggle:
icon: material/toggle-switch-off-outline
name: Switch to dark mode
# Dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: blue
accent: blue
toggle:
icon: material/toggle-switch
name: Switch to light mode
plugins:
- search
- minify:
minify_html: true
minify_js: true
htmlmin_opts:
remove_comments: true
- pandoc:
enabled_if_env: ENABLE_PANDOC_EXPORT
combined: true
combined_output_path: docs.pdf
- git-revision-date-localized:
timezone: Europe/Madrid
locale: en
fallback_to_build_date: false
enable_creation_date: false
markdown_extensions:
- toc:
permalink: "#"
toc_depth: 3
- attr_list
- footnotes
- pymdownx.tasklist:
custom_checkbox: true
extra:
social:
- icon: fontawesome/brands/gitlab
link: https://lab.gsi.upm.es/docs/mkdocs-material
- icon: fontawesome/brands/gitter
link: https://gitter.im/repo
- icon: fontawesome/brands/docker
link: https://lab.gsi.upm.es/docs/mkdocs-material/container_registry
- icon: fontawesome/brands/twitter
link: https://twitter.com/devops
alternate:
- link: /docs/mkdocs-material/
name: en - English
lang: en
- link: /docs/mkdocs-material/es/
name: es - español
lang: es
En los archivos de configuración anteriores, cabe destacar varias opciones que permiten el multilenguaje:
- Existen directorios distintos para los archivos markdown de origen y html de destino.
- La barra de navegación es diferente para cada idioma.
- El link de cada idioma es el mismo con la diferencia de que, en este caso, la versión inglesa es la que está por defecto y en la versión española se tiene que añadir el sufijo
/es/
.
Despliegue de la documentación en local
Es importante tener en cuenta que se han añadido varios plugins en los archivos de configuración, los cuales pueden ser fuentes de errores. Se utiliza mkdocs-pandoc-plugin para combinar todos los archivos markdown en uno único si la variable de entorno ENABLE_PANDOC_EXPORT
equivale a 1. El plugin mkdocs-git-revision-date-localized-plugin sirve para visualizar la fecha de la última modificación git de una página. Se usa mkdocs-minify-plugin para simplificar archivos HTML y/o JS antes de ser escritos en el disco y el plugin mkdocs-redirects para crear redirecciones de páginas (por ejemplo, para páginas movidas/renombradas). Por lo tanto, se requiere instalar los plugins en función de si se usa mkdocs mediante Docker
(recomendado) o pip
. Otra opción, sería comentar las líneas de los plugins en los archivos mkdocs.yml
.
- Uso de mkdocs mediante
Docker
:
Por defecto la imagen oficial de docker squidfunk/mkdocs-material, tiene instalado los plugins mkdocs-minify-plugin y mkdocs-redirects. Por lo tanto, es necesario utilizar una imagen con los plugins mkdocs-pandoc-plugin y mkdocs-git-revision-date-localized-plugin instalados para que funcione correctamente. Existen varias opciones, utilizar la imagen registry.gsi.upm.es/docs/mkdocs-material, la imagen jtr0/mkdocs-material o construir una imagen de docker con los plugins extra que se requieran fijándose en la plantilla de Dockerfile.
# Spanish
docker run --rm -it --network host -p 8000:8000 -v ${PWD}:/docs registry.gsi.upm.es/docs/mkdocs-material serve -f config/es/mkdocs.yml
# English
docker run --rm -it --network host -p 8000:8000 -v ${PWD}:/docs registry.gsi.upm.es/docs/mkdocs-material serve -f config/en/mkdocs.yml
La web estará accesible en http://localhost:8000/. Una pequeña desventaja es que no puede servir el sitio localmente con la función de multilenguje, únicamente funcionará cuando se despliegue en GitLab Pages.
- Uso de mkdocs mediante
pip
:
Se requiere la instalación de los plugins mkdocs-minify-plugin, mkdocs-redirects, mkdocs-pandoc-plugin y mkdocs-git-revision-date-localized-plugin. Para ello se usará el siguiente comando:
Una vez instalados los plugins, se podrá servir la web en local y acceder en http://localhost:8000/.
mkdocs serve
Construcción de PDFs con pandoc y la plantilla de LaTeX Eisvogel
Durante la construcción del contenido público de la página web, se utiliza el plugin de pandoc para combinar todos los archivos markdown en uno. Se construirán tantas veces como idiomas distintos haya, por ejemplo en este caso se generarán dos documentos public/en/docs.pdf.md
y public/es/docs.pdf.md
:
# Castellano
docker run --rm -it -v ${PWD}:/docs -e ENABLE_PANDOC_EXPORT=1 registry.gsi.upm.es/docs/mkdocs-material build -f config/es/mkdocs.yml
# English
docker run --rm -it -v ${PWD}:/docs -e ENABLE_PANDOC_EXPORT=1 registry.gsi.upm.es/docs/mkdocs-material build -f config/en/mkdocs.yml
Para compilar el pdf con pandoc y la plantilla de LaTeX Eisvogel se necesitan los archivos de metadatos del pdf (pdf_metadata_esp.md
y pdf_metadata_eng.md
), la plantilla Eisvogel (latex_templates/eisvogel.latex
) almacenada dentro del docker y la combinación de los archivos markdown. Entonces, se requiere utilizar la imagen jtr0/latex-pandoc o construirse otra imagen a partir de este Dockerfile. Además, existen variables de configuración propias de la plantilla Eisvogel que se pueden consultar en su Github. Dichas variables se almacenarán en los archivos de metadatos, como se muestra en el ejemplo a continuación:
---
title: "Title"
author: [Author]
date: \today
subject: "Markdown"
keywords: [keyword1, keyword2]
subtitle: "Subtitle"
lang: "en"
titlepage: true
listings: true
urlcolor: "blue"
toc-own-page: true
...
Por último, la generación de los PDFs se lleva a cabo mediante los siguientes comandos:
# Castellano
docker run --rm -it -v ${PWD}:/data jtr0/latex-pandoc /bin/bash -c 'mkdir -p /assets; cp -r /data/overrides/assets/images /assets/images ; pandoc -N --template=eisvogel.latex --listings -V lang=es --from markdown --variable mainfont="DejaVuSerif" --variable sansfont="DejaVuSans" --variable monofont="DejaVuSansMono" --variable fontsize=12pt --variable version=2.0 /data/pdf_metadata_esp.md /data/public/es/docs.pdf.md --pdf-engine=xelatex --toc -o /data/eisvogel_template_esp.pdf;'
# English
docker run --rm -it -v ${PWD}:/data jtr0/latex-pandoc /bin/bash -c 'mkdir -p /assets; cp -r /data/overrides/assets/images /assets/images ; pandoc -N --template=eisvogel.latex --listings -V lang=en --from markdown --variable mainfont="DejaVuSerif" --variable sansfont="DejaVuSans" --variable monofont="DejaVuSansMono" --variable fontsize=12pt --variable version=2.0 /data/pdf_metadata_eng.md /data/public/en/docs.pdf.md --pdf-engine=xelatex --toc -o /data/eisvogel_template_eng.pdf;'
Despliegue en GitLab Pages
Para la configuración de CI/CD con GitLab, hay que crear un archivo .gitlab-ci.yml
para que construya el sitio web y lo despliegue en GitLab Pages. En el siguiente ejemplo se establecen tres etapas, en la primera se construye la web con el plugin pandoc, en la segunda se despliega y en la última se generan los PDFs automáticamente.
stages:
- build
- deploy
- pdfs
build_mkdocs:
image:
name: registry.gsi.upm.es/docs/mkdocs-material
entrypoint: [""]
stage: build
only:
- main
script:
- export ENABLE_PANDOC_EXPORT=1
- mkdir -p data/en
- mkdir data/es
- mkdocs build -f config/en/mkdocs.yml --verbose --site-dir ../../data/en --no-directory-urls
- mkdocs build -f config/es/mkdocs.yml --verbose --site-dir ../../data/es --no-directory-urls
artifacts:
paths:
- data
pages:
image:
name: registry.gsi.upm.es/docs/mkdocs-material
entrypoint: [""]
stage: deploy
only:
- main
script:
- mkdir -p public/en
- mkdir public/es
- mkdocs build -f config/en/mkdocs.yml --verbose --no-directory-urls
- mkdocs build -f config/es/mkdocs.yml --verbose --no-directory-urls
- cp -r public/en/* public
artifacts:
paths:
- public
generate_pdfs:
image: jtr0/latex-pandoc
stage: pdfs
only:
- main
script:
- mkdir -p public/pdfs/en
- mkdir public/pdfs/es
- mkdir -p assets/images
- cp -r overrides/assets/images /assets
- cp -r overrides/assets/images/* assets/images
# English pdf
- pandoc -N --template=eisvogel.latex --listings -V lang=en --from markdown --variable mainfont="DejaVuSerif" --variable sansfont="DejaVuSans" --variable monofont="DejaVuSansMono" --variable fontsize=12pt --variable version=2.0 pdf_metadata_eng.md data/en/docs.pdf.md --pdf-engine=xelatex --toc -o public/pdfs/en/eisvogel_template.pdf
# Spanish pdfs
- pandoc -N --template=eisvogel.latex --listings -V lang=es --from markdown --variable mainfont="DejaVuSerif" --variable sansfont="DejaVuSans" --variable monofont="DejaVuSansMono" --variable fontsize=12pt --variable version=2.0 pdf_metadata_esp.md data/es/docs.pdf.md --pdf-engine=xelatex --toc -o public/pdfs/es/eisvogel_template.pdf
artifacts:
paths:
- public/pdfs/
Una vez haya tenido éxito el pipeline, se podrá acceder a la documentación en la web en la dirección https://<gitlab-user>.gitlab.io/<project-name>/
. Por otro lado, se podrán acceder a los artefactos generados con los pdfs en la url https://gitlab.com/<gitlab-user>/<project-name>/-/jobs/artifacts/main/download?job=generate_pdfs
. En caso de tener el proyecto en un grupo, será necesario cambiar <gitlab-user>
por <gitlab-group>
. Además, GitLab permite añadir un dominio o subdominio a la documentación.
A continuación, se describe otro método para documentar proyectos a través del generador de páginas estáticas Hugo.
Documentación con Hugo
Hugo es un SSG escrito en Go, lanzado en 2013, y es capaz de generar la mayoría de las páginas web en pocos segundos (menos de 1 ms por página)2. También se usará el tema Learn, el cual está escrito en Go y es rápido, moderno y con función de multilenguaje.

Instalación y creación del proyecto
Lo primero es proceder a instalar Hugo siguiendo la documentación oficial dependiendo del sistema operativo utilizado. Lo segundo es escoger un tema para utilizar de plantilla. Por ejemplo, los temas más recomendados para documentación técnica son: Learn, Geekdoc, Techdoc, Ace documentation y Hugo Book. Se continúa creando un nuevo proyecto con el siguiente comando:
En este momento, es recomendable inicializar el repositorio git:
Para añadir el tema escogido, se necesita copiar el zip del tema en la nueva carpeta themes
(recomendado) o añadir el submódulo del tema.
# Opción de añadir el zip:
mkdir themes
wget -c https://github.com/matcornic/hugo-theme-learn/archive/refs/tags/2.5.0.zip -O hugo-learn.zip
unzip hugo-learn.zip -d themes/ && mv themes/hugo-theme-learn-2.5.0 themes/learn
# Opción de añadir el submodulo
git clone https://github.com/matcornic/hugo-theme-learn themes/learn
A continuación, edita el archivo de configuración config.toml
y añade el nombre del directorio del tema:
baseURL = "http://localhost:1313/"
theme = "learn"
Sirva el sitio web en local, estará disponible en http://localhost:1313/.
Creación de capítulos y páginas
Para crear un nuevo capítulo llamado ejemplo
se utiliza el comando:
Mientras que para crear una nueva entrada llamada ci_cd
, se utiliza:
Despliegue en GitLab Pages
Lo primero es modificar el parámetro baseurl con esta estructura baseURL = "https://<gitlab-user>.gitlab.io/<project-name>/"
. Lo siguiente es realizar la configuración CI/CD en GitLab añadiendo un archivo .gitlab-ci.yml
o pulsando en el. Concretamente, se utiliza la plantilla que se muestra a continuación para que realice un test básico en las ramas que no son la principal y el despliegue de la rama principal en GitLab Pages.
---
stages:
- test
- pages
variables:
GIT_SUBMODULE_STRATEGY: recursive
test:
image: registry.gitlab.com/pages/hugo:latest
script:
- hugo
except:
- main
pages:
image: registry.gitlab.com/pages/hugo:latest
script:
- hugo
artifacts:
paths:
- public
only:
- main
Por último, se recomienda habilitar la visibilidad para todos en el control de acceso a la página para que cualquier persona pueda acceder mediante la url. Dirigete a Settings > General and expand Visibility, project features, permissions > Pages > Everyone
.