<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://angelblanco.dev/es/blog/</id>
    <title>Ángel Blanco · Blog</title>
    <updated>2026-11-06T23:00:00.000Z</updated>
    <author>
        <name>Ángel Blanco</name>
        <uri>https://angelblanco.dev/es/about/</uri>
    </author>
    <link rel="alternate" href="https://angelblanco.dev/es/blog/"/>
    <link rel="self" href="https://angelblanco.dev/es/atom.xml"/>
    <subtitle>Últimas entradas del blog de ingeniería informática full-stack</subtitle>
    <logo>https://angelblanco.dev/android-chrome-512x512.png</logo>
    <icon>https://angelblanco.dev/favicon.ico</icon>
    <rights>CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ © Ángel Blanco</rights>
    <entry>
        <title type="html"><![CDATA[@angelblanco/eslint-config 3.0 ya disponible, ahora con Tailwind CSS]]></title>
        <id>https://angelblanco.dev/es/blog/lint-tailwind-css-v4-with-eslint/</id>
        <link href="https://angelblanco.dev/es/blog/lint-tailwind-css-v4-with-eslint/"/>
        <updated>2026-11-06T23:00:00.000Z</updated>
        <summary type="html"><![CDATA[@angelblanco/eslint-config 3.0 ya está en npm: lint opcional de Tailwind CSS v4, @antfu/eslint-config v10 y ESLint 10.]]></summary>
        <content type="html"><![CDATA[<p><a href="https://github.com/angelblanco/eslint-config">@angelblanco/eslint-config 3.0</a> ya está disponible en npm. Ahora puedes pasar el linter por tus clases de <a href="https://tailwindcss.com/">Tailwind CSS</a>.</p><p>Cuando empecé este blog y <a href="https://angelblanco.dev/es/blog/create-your-eslint-config/">creé mi propia configuración de ESLint</a> en 2025, todavía no había un plugin de <a href="https://eslint.org/">ESLint</a> para Tailwind CSS v4. En noviembre de 2026 estoy actualizando mis repositorios open source, y <a href="https://github.com/francoismassart/eslint-plugin-tailwindcss">eslint-plugin-tailwindcss</a> por fin está listo.</p><p>Es impresionante cuánto puede cambiar en un año el stack que usas, pero de eso escribiré en próximos artículos.</p><h2 id="activa-el-lint-de-tailwind-css">Activa el lint de Tailwind CSS</h2><p>Instala el plugin (necesita Tailwind CSS v4):</p><pre><code class="language-bash">pnpm add -D eslint-plugin-tailwindcss</code></pre><p>Después activa la opción <code>tailwind</code> e indícale tu fichero CSS de entrada:</p><pre><code class="language-js">import eslintConfig from '@angelblanco/eslint-config';

export default eslintConfig(defaultOptions =&gt; ({
  ...defaultOptions,
  tailwind: {
    cssConfigPath: 'app/assets/css/main.css',
  },
}));</code></pre><p>Viene desactivado por defecto. Si tu CSS está en <code>src/style.css</code>, basta con <code>tailwind: true</code>. El resto de <a href="https://github.com/francoismassart/eslint-plugin-tailwindcss#settings">ajustes del plugin</a> van en el mismo objeto.</p><h2 id="actualiza-a-antfueslint-config-v10-y-eslint-10">Actualiza a @antfu/eslint-config v10 y ESLint 10</h2><p>La 3.0 también actualiza a <a href="https://github.com/antfu/eslint-config">@antfu/eslint-config</a> v10 y ESLint 10. Instala la última versión de ambos paquetes:</p><pre><code class="language-bash">pnpm add -D eslint@latest @angelblanco/eslint-config@latest</code></pre><p>La primera vez que ejecutes <code>eslint --fix</code> verás que reformatea algunos arrays, objetos y ternarios multilínea.</p><p><a href="https://github.com/angelblanco/eslint-config">github.com/angelblanco/eslint-config</a> · Configuración de ESLint de Ángel Blanco, construida sobre @antfu/eslint-config para proyectos Vue + TypeScript.</p>]]></content>
        <category label="eslint" term="eslint"/>
        <category label="tailwindcss" term="tailwindcss"/>
        <category label="tooling" term="tooling"/>
        <category label="npm" term="npm"/>
        <published>2026-11-06T23:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Instalar PHP 8.5 con apt en Ubuntu 26.04]]></title>
        <id>https://angelblanco.dev/es/blog/apt-install-php-85-on-ubuntu-26/</id>
        <link href="https://angelblanco.dev/es/blog/apt-install-php-85-on-ubuntu-26/"/>
        <updated>2026-11-05T23:00:00.000Z</updated>
        <summary type="html"><![CDATA[Instala PHP 8.5 y Composer en Ubuntu 26.04 LTS con apt desde el repositorio packages.sury.org de Ondřej Surý y mantenlos al día con apt upgrade.]]></summary>
        <content type="html"><![CDATA[<p>Ayer subí cómo <a href="https://angelblanco.dev/es/blog/apt-install-node-26-on-ubuntu-26/">instalar Node.js 26 con apt</a> para que el sistema operativo lo mantenga parcheado tras las actualizaciones de seguridad de octubre. Hoy le toca a PHP, por el mismo motivo: las brechas de seguridad no dan tregua, y PHP también ha tenido lo suyo.</p><p>El 24 de septiembre, <a href="https://www.php.net/ChangeLog-8.php#8.5.11">PHP 8.5.11</a> corrigió más de diez CVE en OpenSSL, FPM, SOAP, Phar y el wrapper de streams HTTP, entre ellos un desbordamiento de buffer en el heap y un fallo que se saltaba la verificación del hostname en TLS. El 21 de octubre, <a href="https://www.php.net/archive/2026.php#2026-10-21-4">PHP 8.5.12</a> fue más allá: una release de emergencia para dos vulnerabilidades críticas (CVE-2026-109618 y CVE-2026-109619, CVSS 9.2) que permiten ejecutar código en remoto sin autenticación. Según el propio php.net, &quot;actualizar es la única opción segura&quot;. Las ramas 8.4, 8.3 y 8.2 recibieron las mismas correcciones.</p><p>Aquí viene la trampa: <a href="https://documentation.ubuntu.com/release-notes/26.04/">Ubuntu 26.04 LTS</a> (<em>Resolute Raccoon</em>) incluye PHP 8.5 en sus repositorios, pero congela la versión en el momento del lanzamiento y le aplica por encima los parches que considera importantes. Mientras escribo esto, <code>apt</code> te instala PHP <code>8.5.4</code> con parches, y <a href="https://www.php.net/">php.net</a> ya va por la <code>8.5.12</code>. Para ser justos, el equipo de seguridad de Ubuntu responde bien a lo urgente: publicó los parches de los RCE de octubre el mismo día que php.net. Pero la tanda de septiembre tardó 25 días en llegar, y las correcciones de bugs normales de upstream rara vez llegan.</p><p>Si quieres la versión completa de upstream, lo más sencillo sigue siendo que el propio sistema operativo se encargue. Instala PHP con <code>apt</code> desde el <a href="https://deb.sury.org/">repositorio de Ondřej Surý</a>, los mismos paquetes que llevan más de una década dando vida a PHP en Debian y Ubuntu, y deja que <code>sudo apt upgrade</code> haga el resto.</p><h2 id="fechas-de-soporte-de-un-vistazo">Fechas de soporte de un vistazo</h2><p>Cada rama de PHP tiene dos años de soporte activo y otros dos solo con correcciones de seguridad. Así está el panorama según la <a href="https://www.php.net/supported-versions.php">página oficial de versiones soportadas</a>:</p><table><thead><tr><th>Versión</th><th>Publicada</th><th>Soporte activo hasta</th><th>Soporte de seguridad hasta</th></tr></thead><tbody><tr><td>8.2</td><td>8 de diciembre de 2022</td><td>31 de diciembre de 2024</td><td>31 de diciembre de 2026</td></tr><tr><td>8.3</td><td>23 de noviembre de 2023</td><td>31 de diciembre de 2025</td><td>31 de diciembre de 2027</td></tr><tr><td>8.4</td><td>21 de noviembre de 2024</td><td>31 de diciembre de 2026</td><td>31 de diciembre de 2028</td></tr><tr><td>8.5</td><td>20 de noviembre de 2025</td><td>31 de diciembre de 2027</td><td>31 de diciembre de 2029</td></tr></tbody></table><p>Si sigues en PHP 8.2, te quedan menos de dos meses. <a href="https://wiki.php.net/todo/php86">PHP 8.6</a> está previsto para el 19 de noviembre de 2026, pero hoy PHP 8.5 es la apuesta segura para acompañar a una distribución LTS. Siempre puedes probar la 8.6 en paralelo (lo vemos <a href="https://angelblanco.dev/es/blog/apt-install-php-85-on-ubuntu-26/#y-otras-versiones-de-php">más abajo</a>).</p><p>En cuanto al sistema operativo, <a href="https://ubuntu.com/about/release-cycle">Ubuntu 26.04 LTS</a> salió en abril de 2026 y tiene mantenimiento de seguridad estándar hasta mayo de 2031, ampliable hasta 2036 con Ubuntu Pro. Así que esta instalación te va a durar una buena temporada.</p><h2 id="novedades-de-php-85">Novedades de PHP 8.5</h2><p>Si vienes de PHP 8.4 o anterior, hay motivos para actualizar más allá de la seguridad. El <a href="https://www.php.net/releases/8.5/es.php">anuncio oficial</a> tiene la lista completa, pero mis novedades favoritas son:</p><ul><li>El operador pipe, para encadenar callables de izquierda a derecha sin variables temporales.</li><li><code>clone()</code> con propiedades, que resuelve en una sola línea el patrón &quot;with-er&quot; de las clases <code>readonly</code>.</li><li>El atributo <code>#[\NoDiscard]</code>, que avisa cuando alguien ignora un valor de retorno que importa.</li><li>Una extensión URI nativa, con parseo de URL compatible con RFC 3986 y WHATWG, sin más sorpresas con <code>parse_url()</code>.</li><li><code>array_first()</code> y <code>array_last()</code>. Por fin.</li></ul><p>Así queda el operador pipe convirtiendo un título en un slug:</p><pre><code class="language-php">$slug = $title
    |&gt; trim(...)
    |&gt; (fn (string $str): string =&gt; str_replace(' ', '-', $str))
    |&gt; strtolower(...);</code></pre><h2 id="qué-ha-cambiado-adiós-ppa-hola-packagessuryorg">Qué ha cambiado: adiós PPA, hola packages.sury.org</h2><p>Si ya has instalado PHP en Ubuntu alguna vez, seguramente usaste <code>add-apt-repository ppa:ondrej/php</code>. Eso ya no es lo recomendable: Ondřej Surý está trasladando sus paquetes de Ubuntu desde <a href="https://launchpad.net/~ondrej/+archive/ubuntu/php">Launchpad</a> a <a href="https://packages.sury.org/php/">packages.sury.org</a>, el servidor que ya alojaba los de Debian. Los paquetes de <code>resolute</code> para Ubuntu 26.04 se publican <strong>solo</strong> ahí.</p><p>Si todavía tienes el PPA configurado, puede que este verano <code>apt update</code> se quejara de que el repositorio había cambiado su valor 'Label', un error que hacía fallar <code>apt-get update</code> en scripts hasta aceptar el cambio. De momento el PPA sigue recibiendo actualizaciones para Ubuntu 22.04 y 24.04, pero se está fusionando con packages.sury.org. Y si tienes los dos configurados, apt sigue prefiriendo los paquetes del PPA, así que elimínalo antes de seguir los pasos de abajo:</p><pre><code class="language-bash">sudo add-apt-repository --remove ppa:ondrej/php</code></pre><p>El nuevo método también mejora la gestión de la clave de firma. En lugar de descargar un fichero <code>.gpg</code> a pelo, instalas el paquete oficial <code>debsuryorg-archive-keyring</code>.</p><h2 id="la-vía-fácil">La vía fácil</h2><p>Como de costumbre, puedes instalarlo todo con un solo comando. El script añade el repositorio de Sury, instala PHP 8.5 con las extensiones más habituales, lo configura como <code>php</code> por defecto y, opcionalmente, instala <a href="https://getcomposer.org/">Composer</a>.</p><pre><code class="language-bash">curl -fsSL https://angelblanco.dev/scripts/ubuntu-install-php-85.sh | bash</code></pre><p>El script te pide confirmación en cada paso importante. Como siempre, lee <a href="https://angelblanco.dev/es/blog/apt-install-php-85-on-ubuntu-26/#el-script">el script</a> antes de pasárselo a <code>bash</code>. Fiarse de URL aleatorias con <code>sudo</code> es una forma estupenda de aprender a gestionar incidentes.</p><p>Si no tienes <code>curl</code> instalado:</p><pre><code class="language-bash">sudo apt update
sudo apt install curl</code></pre><h2 id="la-guía-paso-a-paso">La guía paso a paso</h2><p>Esto es lo que hace el script, por si prefieres ir paso a paso.</p><h3 id="_1-instalar-los-requisitos-previos">1. Instalar los requisitos previos</h3><pre><code class="language-bash">sudo apt update
sudo apt install -y ca-certificates curl unzip</code></pre><p>PHP no necesita <code>unzip</code>, pero Composer lo usa para descomprimir paquetes mucho más rápido que con su alternativa en PHP.</p><h3 id="_2-instalar-la-clave-de-firma-de-sury">2. Instalar la clave de firma de Sury</h3><pre><code class="language-bash">curl -fsSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb \
  &amp;&amp; sudo dpkg -i /tmp/debsuryorg-archive-keyring.deb \
  &amp;&amp; rm /tmp/debsuryorg-archive-keyring.deb</code></pre><p>Esto deja la clave en <code>/usr/share/keyrings/debsuryorg-archive-keyring.gpg</code> (y, de momento, una copia global en <code>/etc/apt/trusted.gpg.d/</code>). En Debian el repositorio también publica el paquete del keyring, así que las renovaciones llegan con <code>apt upgrade</code>. En las suites de Ubuntu todavía no está, así que si algún día se renueva la clave, vuelve a descargar e instalar el <code>.deb</code>.</p><h3 id="_3-añadir-el-repositorio-de-sury">3. Añadir el repositorio de Sury</h3><p>Desde la 24.04, Ubuntu usa el <a href="https://manpages.ubuntu.com/manpages/resolute/man5/sources.list.5.html">formato deb822</a> (ficheros <code>.sources</code>) para sus propios repositorios, y el formato clásico <code>.list</code> de una línea ya está oficialmente obsoleto. El nombre en clave se lee de <code>/etc/os-release</code>, así que el mismo fragmento funciona también en Ubuntu 22.04 y 24.04, y en derivadas como Linux Mint.</p><pre><code class="language-bash">sudo tee /etc/apt/sources.list.d/php.sources &gt; /dev/null &lt;&lt;EOF
Types: deb
URIs: https://packages.sury.org/php/
Suites: $(. /etc/os-release &amp;&amp; echo &quot;${UBUNTU_CODENAME:-$VERSION_CODENAME}&quot;)
Components: main
Architectures: $(dpkg --print-architecture)
Signed-By: /usr/share/keyrings/debsuryorg-archive-keyring.gpg
EOF

sudo apt update</code></pre><h3 id="_4-instalar-php-85">4. Instalar PHP 8.5</h3><pre><code class="language-bash">sudo apt install -y php8.5-cli php8.5-mbstring php8.5-curl php8.5-zip php8.5-xml</code></pre><p>Fíjate en que instalamos <code>php8.5-cli</code> y no el metapaquete <code>php8.5</code> a secas. El metapaquete arrastra <a href="https://httpd.apache.org/">Apache</a> y su módulo de PHP, que seguramente no quieres en tu máquina de desarrollo. Si necesitas un servidor web, añade <a href="https://www.php.net/manual/es/install.fpm.php"><code>php8.5-fpm</code></a> y combínalo con <a href="https://nginx.org/">Nginx</a> o <a href="https://caddyserver.com/">Caddy</a>. ¿Base de datos? Añade <code>php8.5-mysql</code>, <code>php8.5-pgsql</code> o <code>php8.5-sqlite3</code>.</p><p>No hace falta fijar prioridades en apt: la <code>8.5.12</code> de Sury tiene una versión mayor que la <code>8.5.4</code> de Ubuntu, así que apt la elige automáticamente. Puedes comprobar de dónde viene cada paquete con:</p><pre><code class="language-bash">apt policy php8.5-cli</code></pre><h3 id="_5-configurar-php-85-por-defecto">5. Configurar PHP 8.5 por defecto</h3><p>El comando <code>php</code> se gestiona con <a href="https://manpages.ubuntu.com/manpages/resolute/man1/update-alternatives.1.html"><code>update-alternatives</code></a>, así que puedes elegir qué versión responde a él:</p><pre><code class="language-bash">sudo update-alternatives --set php /usr/bin/php8.5
php --version</code></pre><h3 id="_6-instalar-composer">6. Instalar Composer</h3><p>El <a href="https://getcomposer.org/download/">instalador oficial</a> publica un checksum SHA-384, así que verifícalo antes de ejecutar nada:</p><pre><code class="language-bash">EXPECTED_CHECKSUM=&quot;$(curl -fsSL https://composer.github.io/installer.sig)&quot;
curl -fsSLo composer-setup.php https://getcomposer.org/installer
ACTUAL_CHECKSUM=&quot;$(php -r &quot;echo hash_file('sha384', 'composer-setup.php');&quot;)&quot;

if [ &quot;$EXPECTED_CHECKSUM&quot; = &quot;$ACTUAL_CHECKSUM&quot; ]; then
    php composer-setup.php --quiet
    sudo install -m 0755 composer.phar /usr/local/bin/composer
    rm composer.phar
    composer --version
else
    &gt;&amp;2 echo &quot;ERROR: checksum del instalador de Composer no válido&quot;
fi
rm composer-setup.php</code></pre><p>Usar <code>install</code> en lugar de <code>mv</code> deja el binario a nombre de <code>root</code>, algo importante porque más adelante ejecutarás <code>sudo composer self-update</code>.</p><h2 id="y-otras-versiones-de-php">¿Y otras versiones de PHP?</h2><p>Aquí es donde el repositorio de Sury brilla de verdad. Publica todas las ramas desde <code>php5.6</code> hasta <code>php8.5</code>, además de las release candidates de PHP 8.6, y pueden convivir todas a la vez:</p><pre><code class="language-bash">sudo apt install -y php8.4-cli php8.4-mbstring php8.4-curl php8.4-zip php8.4-xml
sudo update-alternatives --config php</code></pre><p><code>update-alternatives --config php</code> muestra un menú interactivo para cambiar el <code>php</code> por defecto. También puedes llamar directamente a una versión concreta con <code>php8.4</code> o <code>php8.5</code>, algo muy práctico para pasar los tests de un proyecto antiguo sin tocar tu versión por defecto.</p><p>Si pruebas la 8.6 antes de la versión final del 19 de noviembre, revisa <code>apt policy php8.6-cli</code>: las builds anteriores a la RC4 no incluyen los parches de los RCE de octubre.</p><p>Ten en cuenta que cada versión que instalas es una más que tienes que mantener parcheada. Con Sury, al menos, <code>apt upgrade</code> las parchea todas de una vez.</p><h2 id="el-script">El script</h2><p>Este es el script completo. Incluye confirmaciones, usa un directorio temporal que se borra al terminar y lee tus respuestas desde la terminal, así que funciona cuando lo ejecutas con <code>curl</code>. Puedes cambiar la versión de PHP y las extensiones con las variables del principio.</p><p>Este script sale de mi <a href="https://github.com/angelblanco/kickstart.nvim">repo de configuración de Neovim</a>, donde guardo mis <a href="https://github.com/angelblanco/kickstart.nvim/blob/master/install/install-php.sh">scripts de instalación</a>. El editor necesita <code>php</code> y <code>composer</code> para que funcionen los language servers y formateadores de PHP, así que los actualizo con frecuencia. Si quieres la versión más reciente, pásate por allí.</p><pre><code class="language-bash">#!/bin/bash
#
# Author: Ángel Blanco
# License: MIT
#
# This script is provided &quot;as is&quot;, without warranty of any kind. Use at your own risk.
#
# Source: https://angelblanco.dev/blog/apt-install-php-85-on-ubuntu-26
#
# Usage:
#   curl -fsSL https://angelblanco.dev/scripts/ubuntu-install-php-85.sh | bash
#
# Install PHP (from packages.sury.org) and Composer on Ubuntu.
# Normally you will call it from your non-root user; elevated permissions
# will be granted with sudo.
#

set -euo pipefail

# You can configure these variables if needed
PHP_VERSION=&quot;8.5&quot;
PHP_EXTENSIONS=&quot;cli mbstring curl zip xml&quot;
KEYRING=&quot;/usr/share/keyrings/debsuryorg-archive-keyring.gpg&quot;
SOURCE_FILE=&quot;/etc/apt/sources.list.d/php.sources&quot;

# Basic confirmation module before executing the script.
confirm_action() {
    while true; do
        read -r -p &quot;$1 (y/n): &quot; choice &lt; /dev/tty
        case &quot;$choice&quot; in
            [Yy]|[Yy][Ee][Ss]) return 0 ;;
            [Nn]|[Nn][Oo])     return 1 ;;
            *)                 echo &quot;Invalid choice. Please enter 'y' or 'n'.&quot; ;;
        esac
    done
}

WORKDIR=&quot;$(mktemp -d)&quot;
trap 'rm -rf &quot;$WORKDIR&quot;' EXIT

if ! confirm_action &quot;Install PHP $PHP_VERSION from packages.sury.org?&quot;; then
    echo &quot;Skipping PHP installation. Exiting.&quot;
    exit 0
fi

# --- Prerequisites ---------------------------------------------------------
sudo apt update
sudo apt install -y ca-certificates curl unzip

# --- Sury signing key (official keyring package) ---------------------------
curl -fsSLo &quot;$WORKDIR/debsuryorg-archive-keyring.deb&quot; https://packages.sury.org/debsuryorg-archive-keyring.deb
sudo dpkg -i &quot;$WORKDIR/debsuryorg-archive-keyring.deb&quot;

# --- Sury repository --------------------------------------------------------
CODENAME=&quot;$(. /etc/os-release &amp;&amp; echo &quot;${UBUNTU_CODENAME:-$VERSION_CODENAME}&quot;)&quot;

sudo tee &quot;$SOURCE_FILE&quot; &gt; /dev/null &lt;&lt;EOF
Types: deb
URIs: https://packages.sury.org/php/
Suites: $CODENAME
Components: main
Architectures: $(dpkg --print-architecture)
Signed-By: $KEYRING
EOF

sudo apt update

# --- PHP --------------------------------------------------------------------
# Use -cli instead of the bare &quot;phpX.Y&quot; metapackage, which pulls in Apache.
PACKAGES=&quot;&quot;
for EXTENSION in $PHP_EXTENSIONS; do
    PACKAGES=&quot;$PACKAGES php${PHP_VERSION}-${EXTENSION}&quot;
done

# shellcheck disable=SC2086
sudo apt install -y $PACKAGES

sudo update-alternatives --set php &quot;/usr/bin/php${PHP_VERSION}&quot;

echo &quot;&quot;
php --version
echo &quot;&quot;

# --- Composer ---------------------------------------------------------------
if confirm_action &quot;Install Composer?&quot;; then
    cd &quot;$WORKDIR&quot;

    EXPECTED_CHECKSUM=&quot;$(curl -fsSL https://composer.github.io/installer.sig)&quot;
    curl -fsSLo composer-setup.php https://getcomposer.org/installer
    ACTUAL_CHECKSUM=&quot;$(php -r &quot;echo hash_file('sha384', 'composer-setup.php');&quot;)&quot;

    if [ &quot;$EXPECTED_CHECKSUM&quot; != &quot;$ACTUAL_CHECKSUM&quot; ]; then
        &gt;&amp;2 echo &quot;ERROR: Invalid Composer installer checksum&quot;
        exit 1
    fi

    php composer-setup.php --quiet
    sudo install -m 0755 composer.phar /usr/local/bin/composer

    echo &quot;&quot;
    composer --version
fi

echo &quot;&quot;
echo &quot;Installation process finished.&quot;
echo &quot;Run 'sudo apt update &amp;&amp; sudo apt upgrade' periodically to get PHP security releases.&quot;</code></pre><h2 id="mantén-todo-al-día">Mantén todo al día</h2><p>Una vez instalado, mantenerlo actualizado es cosa de un par de comandos:</p><pre><code class="language-bash"># Sistema operativo y PHP
sudo apt update &amp;&amp; sudo apt upgrade

# Composer
sudo composer self-update</code></pre><p>Incluso con la 8.5.12, php.net <a href="https://www.php.net/archive/2026.php#2026-10-23-1">recomienda</a> desactivar el progreso de subida de sesiones hasta la próxima release, para cerrar del todo una vía de RCE poco probable (CVE-2026-115560). Si sirves PHP con FPM, es cosa de una línea:</p><pre><code class="language-bash">echo 'session.upload_progress.enabled=0' | sudo tee /etc/php/8.5/fpm/conf.d/99-session-upload-progress.ini
sudo systemctl restart php8.5-fpm</code></pre><p>Y no te olvides de las dependencias de tus proyectos: <a href="https://getcomposer.org/doc/03-cli.md#outdated"><code>composer outdated</code></a> y <a href="https://getcomposer.org/doc/03-cli.md#audit"><code>composer audit</code></a> te dicen qué toca actualizar y qué paquetes tienen vulnerabilidades conocidas.</p><p>Dos tandas de parches de seguridad de PHP en menos de un mes, una de ellas de emergencia, recuerdan que no puedes saber qué parche será el importante. Lo que sí puedes hacer es que aplicarlos sea aburrido: un <code>apt upgrade</code> para PHP, un <code>composer self-update</code> para Composer y <code>composer audit</code> para tus proyectos. Déjalo configurado una vez y olvídate.</p>]]></content>
        <category label="php" term="php"/>
        <category label="ubuntu" term="ubuntu"/>
        <category label="composer" term="composer"/>
        <category label="bash" term="bash"/>
        <published>2026-11-05T23:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Instalar Node.js 26 con apt en Ubuntu 26.04]]></title>
        <id>https://angelblanco.dev/es/blog/apt-install-node-26-on-ubuntu-26/</id>
        <link href="https://angelblanco.dev/es/blog/apt-install-node-26-on-ubuntu-26/"/>
        <updated>2026-11-04T23:00:00.000Z</updated>
        <summary type="html"><![CDATA[El 21 de octubre de 2026, Node.js publicó parches de seguridad para diez vulnerabilidades que afectan a sus versiones con soporte, cuatro de ellas graves, incluida una ejecución remota de código. Las versiones sin soporte, como Node.js 20 y 25, no recibirán actualizaciones.]]></summary>
        <content type="html"><![CDATA[<p>El 21 de octubre de 2026, Node.js publicó <a href="https://nodejs.org/en/blog/vulnerability/october-2026-security-releases">parches de seguridad</a> para diez vulnerabilidades que afectan a sus versiones con soporte, cuatro de ellas graves, incluida una ejecución remota de código. Las versiones sin soporte, como Node.js 20 y 25, no recibirán actualizaciones.</p><p>Mantener Node.js al día no es opcional: merece la pena dedicarle un rato, tanto en tu ordenador personal como en tu servidor. Lo más sencillo es que sea el propio sistema operativo quien gestione esas actualizaciones. Para eso, instalas Node.js con <code>apt</code> desde el repositorio de <a href="https://nodesource.com/">NodeSource</a> y <code>sudo apt upgrade</code> se encarga del resto.</p><p>Ahora que <a href="https://nodejs.org/">Node.js 26</a> (<em>Lithium</em>) es LTS desde el 28 de octubre de 2026 y <a href="https://documentation.ubuntu.com/release-notes/26.04/">Ubuntu 26.04 LTS</a> (<em>Resolute Raccoon</em>) lleva meses publicado, es buen momento para dejarlo bien instalado. La receta es la misma que en mi <a href="https://angelblanco.dev/es/blog/install-node-24-on-ubuntu-24/">guía de Node.js 24 en Ubuntu 24</a>.</p><h2 id="fechas-de-soporte-de-un-vistazo">Fechas de soporte de un vistazo</h2><p>Las dos versiones tienen periodos de soporte largos, así que esta instalación te va a durar una buena temporada:</p><table><thead><tr><th>Versión</th><th>Publicación</th><th>LTS / soporte estándar</th><th>Fin de vida</th></tr></thead><tbody><tr><td>Node.js 26 (Lithium)</td><td>5 de mayo de 2026</td><td>Active LTS desde el 28 de octubre de 2026</td><td>30 de abril de 2029</td></tr><tr><td>Ubuntu 26.04 LTS</td><td>23 de abril de 2026</td><td>Soporte estándar hasta abril de 2031</td><td>ESM con Ubuntu Pro durante 10 años</td></tr></tbody></table><p>Node.js 26 pasa a mantenimiento el 20 de octubre de 2027 (lo tienes en el <a href="https://github.com/nodejs/Release#release-schedule">calendario oficial</a>) y es la última versión del modelo de pares e impares: a partir de <a href="https://nodejs.org/es/blog/announcements/evolving-the-nodejs-release-schedule">Node.js 27</a>, el proyecto publica una sola versión mayor al año y todas pasan a ser LTS. Si sigues en Node.js 24, tranquilidad: tiene soporte hasta abril de 2028 (y Node.js 22, hasta abril de 2027).</p><h2 id="qué-ha-cambiado-desde-nodejs-24">Qué ha cambiado desde Node.js 24</h2><p>Casi todos los pasos son iguales, pero hay un cambio importante: <strong>Corepack ya no viene incluido con Node.js</strong>. Se eliminó en Node.js 25, así que <code>corepack enable</code> no funciona en una instalación limpia de Node.js 26. La <a href="https://nodejs.org/docs/latest-v25.x/api/corepack.html">documentación de Node.js</a> recomienda usar el paquete <code>corepack</code> de npm si todavía lo necesitas.</p><p>Yo he optado por lo más sencillo y ahora instalo <a href="https://pnpm.io/">pnpm</a> con su propio instalador. Si usas <a href="https://yarnpkg.com/">Yarn</a>, puedes instalar el paquete <code>corepack</code> de forma global (lo vemos <a href="https://angelblanco.dev/es/blog/apt-install-node-26-on-ubuntu-26/#y-yarn">más abajo</a>).</p><h2 id="la-vía-fácil">La vía fácil</h2><p>Igual que antes, puedes instalarlo todo con un solo comando. El script instala Node.js 26 desde NodeSource, configura un prefijo global de <a href="https://docs.npmjs.com/">npm</a> (para que no necesites <code>sudo</code> con los paquetes globales) y, opcionalmente, instala pnpm y <a href="https://bun.sh/">Bun</a>.</p><pre><code class="language-bash">curl -fsSL https://angelblanco.dev/scripts/ubuntu-install-node-26.sh | bash</code></pre><p>El script te pide confirmación en cada paso importante. Como siempre, échale un vistazo <a href="https://angelblanco.dev/es/blog/apt-install-node-26-on-ubuntu-26/#el-script">al script</a> antes de pasárselo a <code>bash</code>. Ejecutar scripts aleatorios de internet es muy divertido hasta que deja de serlo.</p><p>Si no tienes <code>curl</code> instalado:</p><pre><code class="language-bash">sudo apt update
sudo apt install curl</code></pre><h2 id="la-guía-paso-a-paso">La guía paso a paso</h2><p>Esto es lo que hace el script, por si prefieres ir paso a paso.</p><h3 id="_1-actualizar-dependencias-y-añadir-el-repositorio-de-nodesource">1. Actualizar dependencias y añadir el repositorio de NodeSource</h3><p>Primero, instala las herramientas necesarias para descargar y verificar paquetes:</p><pre><code class="language-bash">sudo apt update
sudo apt install -y ca-certificates curl gnupg</code></pre><p>Después, añade el repositorio de NodeSource para Node.js 26:</p><pre><code class="language-bash">curl -fsSL https://deb.nodesource.com/setup_26.x | sudo -E bash -</code></pre><p>NodeSource usa una única suite <code>nodistro</code> para todas las distribuciones basadas en Debian, así que funciona en Ubuntu 26.04 sin esperar a un repositorio específico para su nombre en clave. El script de NodeSource también añade un pin de apt con prioridad <code>600</code>, de modo que el paquete de NodeSource siempre gana al paquete <code>nodejs</code> del archivo de Ubuntu. Sin él, podrías acabar con un Node.js más antiguo de los repositorios de Ubuntu.</p><h3 id="_2-instalar-nodejs-y-npm">2. Instalar Node.js y npm</h3><pre><code class="language-bash">sudo apt-get install -y nodejs
node --version</code></pre><p>Esto instala tanto el entorno de ejecución <code>node</code> como <code>npm</code>.</p><h3 id="_3-configurar-el-prefijo-global-de-npm">3. Configurar el prefijo global de npm</h3><p>Para instalar paquetes globales sin <code>sudo</code>, configura un directorio dentro de tu carpeta personal:</p><pre><code class="language-bash">mkdir -p ~/.npm-global
npm config set prefix '~/.npm-global'</code></pre><p>Y añádelo a tu <code>PATH</code> en <code>~/.bashrc</code> o <code>~/.zshrc</code>:</p><pre><code class="language-bash">export PATH=~/.npm-global/bin:$PATH</code></pre><h3 id="_4-instalar-pnpm">4. Instalar pnpm</h3><p>Como Corepack ya no viene incluido, instala pnpm con su <a href="https://pnpm.io/installation">script oficial</a>:</p><pre><code class="language-bash">curl -fsSL https://get.pnpm.io/install.sh | sh -</code></pre><p>El instalador añade pnpm al <code>PATH</code> en la configuración de tu shell, así que abre una terminal nueva (o haz <code>source</code> de tu fichero de configuración) antes de ejecutar <code>pnpm --version</code>. A partir de ahí, <code>pnpm self-update</code> lo mantiene actualizado.</p><h3 id="_5-instalar-bun-opcional">5. Instalar Bun (opcional)</h3><p>Si quieres probar <a href="https://bun.sh/">Bun</a>, usa su instalador oficial, que necesita <code>unzip</code>:</p><pre><code class="language-bash">sudo apt install -y unzip
curl -fsSL https://bun.sh/install | bash</code></pre><h2 id="y-yarn">¿Y Yarn?</h2><p>Si tus proyectos usan Yarn, puedes seguir usando Corepack. Solo tienes que instalarlo tú:</p><pre><code class="language-bash">npm install -g corepack
corepack enable</code></pre><p>Como hemos configurado un prefijo global de npm, funciona sin <code>sudo</code>. Eso sí, el paquete <a href="https://github.com/nodejs/corepack">Corepack</a> ahora se mantiene fuera del ciclo de versiones de Node.js, así que revisa su README si algo no se comporta como esperas en Node.js 26.</p><h2 id="el-script">El script</h2><p>Este es el script completo. Incluye confirmaciones, usa un directorio temporal que se borra al terminar y lee tus respuestas desde la terminal, así que funciona aunque lo ejecutes directamente desde <code>curl</code>.</p><p>Este script sale de mi <a href="https://github.com/angelblanco/kickstart.nvim">repo de configuración de Neovim</a>, donde guardo mis <a href="https://github.com/angelblanco/kickstart.nvim/blob/master/install/install-node.sh">scripts de instalación</a>. El editor necesita Node.js para varios language servers y plugins, así que los actualizo con frecuencia. Si quieres la versión más reciente, pásate por allí.</p><pre><code class="language-bash">#!/bin/bash
#
# Author: Ángel Blanco
# License: MIT
#
# This script is provided &quot;as is&quot;, without warranty of any kind. Use at your own risk.
#
# Source: https://angelblanco.dev/blog/apt-install-node-26-on-ubuntu-26
#
# Usage:
#   curl -fsSL https://angelblanco.dev/scripts/ubuntu-install-node-26.sh | bash
#
# This script installs Node.js and several package managers.
# Run it as your non-root user: it asks for elevated permissions
# with sudo when needed.
#

set -e

# Basic confirmation module before executing the script.
confirm_action() {
    read -p &quot;$1 (y/n): &quot; choice &lt; /dev/tty
    case &quot;$choice&quot; in
        [Yy]|[Yy][Ee][Ss])
            return 0
            ;;
        [Nn]|[Nn][Oo])
            return 1
            ;;
        *)
            echo &quot;Invalid choice. Please enter 'y' or 'n'.&quot;
            confirm_action &quot;$1&quot;
            ;;
    esac
}

# You can configure these variables if needed
NODE_VERSION=26
NPM_PREFIX=&quot;~/.npm-global&quot;
DEPS=&quot;ca-certificates curl gnupg&quot;

TMP_DIR=$(mktemp -d)
trap 'rm -rf &quot;$TMP_DIR&quot;' EXIT

echo &quot;This script will install Node.js and optionally other package managers.&quot;
echo &quot;&quot;

if ! confirm_action &quot;Install Node.js version $NODE_VERSION?&quot;; then
    echo &quot;Skipping Node.js installation. Exiting.&quot;
    exit 0
fi

echo &quot;Installing the dependencies needed to install Node.js...&quot;

sudo apt update
sudo apt install -y $DEPS

echo &quot;Installing Node.js...&quot;
curl -fsSL https://deb.nodesource.com/setup_$NODE_VERSION.x -o $TMP_DIR/nodesource_setup.sh
sudo -E bash $TMP_DIR/nodesource_setup.sh

sudo apt-get install -y nodejs

mkdir -p ~/.npm-global
npm config set prefix $NPM_PREFIX
echo &quot;npm prefix set to $NPM_PREFIX&quot;

echo &quot;Node.js installation completed.&quot;
echo &quot;Node version: &quot;
node --version

echo &quot;&quot;

if confirm_action &quot;Install pnpm?&quot;; then
    echo &quot;Installing pnpm...&quot;
    curl -fsSL https://get.pnpm.io/install.sh | sh -
    echo &quot;pnpm installation completed. Open a new terminal (or source your shell config) to use it.&quot;
fi

echo &quot;&quot;

if confirm_action &quot;Install Bun?&quot;; then
    echo &quot;Installing Bun...&quot;
    sudo apt install -y unzip
    curl -fsSL https://bun.sh/install | bash
    export BUN_INSTALL=&quot;$HOME/.bun&quot;
    export PATH=&quot;$BUN_INSTALL/bin:$PATH&quot;
    echo &quot;Bun version: &quot;
    bun --version
fi

echo &quot;&quot;
echo &quot;Installation process finished.&quot;
echo &quot;&quot;
echo &quot;Add the global npm bin directory to your PATH by adding this line to your .bashrc or .zshrc:&quot;
echo 'export PATH=~/.npm-global/bin:$PATH'
echo &quot;&quot;
echo &quot;Node.js now comes from apt, so keep it patched with:&quot;
echo &quot;sudo apt update &amp;&amp; sudo apt upgrade&quot;
echo &quot;&quot;</code></pre><h2 id="mantén-todo-al-día">Mantén todo al día</h2><p>Una vez instalado, mantenerlo al día es cuestión de un par de comandos:</p><pre><code class="language-bash"># Sistema operativo y Node.js
sudo apt update &amp;&amp; sudo apt upgrade

# Gestores de paquetes
pnpm self-update
bun upgrade
npm update -g</code></pre><p>Y no te olvides de las dependencias de tus proyectos: <code>pnpm outdated</code> y <code>pnpm audit</code> te dicen qué toca actualizar.</p><p>Por eso mismo sigo sin usar <a href="https://github.com/nvm-sh/nvm">NVM</a> en el día a día, como ya conté en el <a href="https://angelblanco.dev/es/blog/install-node-24-on-ubuntu-24/#y-qu%C3%A9-hay-de-nvm">post anterior</a>. Es estupendo si de verdad necesitas varias versiones de Node.js a la vez, pero cada versión que instalas con NVM es una más que tienes que acordarte de parchear.</p><p>Con una inteligencia artificial que acelera cómo se descubren y explotan las vulnerabilidades, y con brechas de seguridad que no paran de surgir, mantenerse al día tiene que ser lo más sencillo posible. Porque ahora, más que nunca, no es opcional.</p>]]></content>
        <category label="nodejs" term="nodejs"/>
        <category label="ubuntu" term="ubuntu"/>
        <category label="javascript" term="javascript"/>
        <category label="bash" term="bash"/>
        <published>2026-11-04T23:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Crea tu propia configuración de ESLint y compártela entre proyectos]]></title>
        <id>https://angelblanco.dev/es/blog/create-your-eslint-config/</id>
        <link href="https://angelblanco.dev/es/blog/create-your-eslint-config/"/>
        <updated>2025-11-01T23:00:00.000Z</updated>
        <summary type="html"><![CDATA[Si alguna vez has trabajado en varios proyectos, conoces el aburrimiento de copiar configuraciones de ESLint de un repositorio a otro. Cada vez que empiezas un proyecto nuevo, o partes de cero o copias el archivo eslint.config.js del anterior. Hay una forma mejor: publicar tu propio paquete de configuración de ESLint.]]></summary>
        <content type="html"><![CDATA[<p>Si alguna vez has trabajado en varios proyectos, conoces el aburrimiento de copiar configuraciones de <a href="https://eslint.org/">ESLint</a> de un repositorio a otro. Cada vez que empiezas un proyecto nuevo, o partes de cero o copias el archivo <code>eslint.config.js</code> del anterior. Hay una forma mejor: publicar tu propio paquete de configuración de ESLint.</p><h2 id="por-qué-me-encanta-antfueslint-config">Por qué me encanta antfu/eslint-config</h2><p>Descubrir <a href="https://github.com/antfu/eslint-config">@antfu/eslint-config</a> cambió mi forma de configurar ESLint. El paso a &quot;Flat Config&quot; me parecía innecesario, hasta que <a href="https://antfu.me/">Anthony Fu</a> creó una configuración que hace que ESLint sea sencillo de montar y de extender.</p><p>En lugar de hacer malabares con docenas de plugins, configuraciones y dependencias, instalas un paquete y listo. Por defecto no necesita configuración: lo importas, lo exportas y respeta tu <code>.gitignore</code>. Analiza tu proyecto y activa las reglas adecuadas para <a href="https://vuejs.org/">Vue</a>, <a href="https://www.typescriptlang.org/">TypeScript</a> o JavaScript, con unos valores por defecto con criterio que puedes sobrescribir.</p><p>Además formatea el código, así que en la mayoría de proyectos no necesitas <a href="https://prettier.io/">Prettier</a>. Aparte de JavaScript y TypeScript, se encarga de JSON, Markdown y YAML, de modo que ESLint lo gestiona todo.</p><p>Para mi stack habitual (Vue y TypeScript), es el mejor punto de partida para configurar ESLint.</p><h2 id="por-qué-crear-tu-propio-paquete-de-configuración-de-eslint">¿Por qué crear tu propio paquete de configuración de ESLint?</h2><p>Extender la configuración de <code>antfu</code> con mis preferencias y plugins es sencillo, porque está pensada para componer la tuya propia. Estoy acostumbrado a acabar las líneas con punto y coma, indentar con 2 espacios y tener el <code>&lt;template&gt;</code> al principio de mis ficheros <code>.vue</code>.</p><p>Pero lo importante no son los gustos personales, sino la <strong>consistencia y la reutilización</strong>. Cuando publicas tu configuración de ESLint como paquete de <a href="https://www.npmjs.com/">npm</a>, puedes:</p><ul><li>Añadir plugins de librerías concretas que no pueden entrar en el core de <code>antfu</code>.</li><li>Usarla en todos tus repositorios, con las mismas reglas en todos.</li><li>Versionar tus reglas de linting: actualizas el paquete, subes la versión en tus proyectos y todos tienen las reglas nuevas.</li><li>Compartirla con tu equipo o hacerla pública.</li><li>Mantenerla en un solo sitio en vez de actualizar las mismas reglas en 10 proyectos.</li></ul><h2 id="mi-configuración-angelblancoeslint-config">Mi configuración: @angelblanco/eslint-config</h2><p>Mi configuración, <a href="https://www.npmjs.com/package/@angelblanco/eslint-config">@angelblanco/eslint-config</a>, está disponible en npm y el código fuente está en GitHub:</p><p><a href="https://github.com/angelblanco/eslint-config">github.com/angelblanco/eslint-config</a> · Configuración de ESLint de Ángel Blanco, construida sobre @antfu/eslint-config para proyectos Vue + TypeScript.</p><h2 id="cómo-crear-la-tuya">Cómo crear la tuya</h2><p>Crear tu propia configuración de ESLint es sencillo. En lugar de empezar de cero, puedes hacer un fork de la mía:</p><ol><li>Haz fork de <a href="https://github.com/angelblanco/eslint-config">@angelblanco/eslint-config</a>.</li><li>Regístrate en npm con tu usuario de GitHub.</li><li>Actualiza <code>package.json</code> con el nombre de tu paquete, por ejemplo <code>@tunombre/eslint-config</code>, y el resto de datos.</li><li>Instala las dependencias con <code>pnpm install</code>.</li><li>Personaliza las reglas en <code>index.ts</code>.</li><li>Genera el JavaScript con tsup ejecutando <code>pnpm build</code>.</li><li>Publícalo con <code>npm publish --access public</code>.</li><li>Instala <code>@tunombre/eslint-config</code> en el resto de tus repositorios e impórtalo en su configuración de ESLint.</li></ol><p>El <a href="https://github.com/angelblanco/eslint-config">README de mi repositorio</a> tiene las instrucciones de instalación actualizadas, ejemplos de uso y todas las reglas que he cambiado. Abre un issue si quieres que te eche una mano.</p><h2 id="hazla-tuya">Hazla tuya</h2><p>No hace falta reinventar la rueda. Parte de algo sólido como @antfu/eslint-config, ajústalo a tu gusto y publícalo. Todo el proceso lleva más o menos una hora, y acabas con una única configuración de linting versionada para todos tus proyectos.</p><p>Si trabajas con Vue y TypeScript, prueba la configuración de antfu o la mía. Si ninguna es exactamente lo que buscas, haz un fork y hazla tuya.</p>]]></content>
        <category label="eslint" term="eslint"/>
        <category label="typescript" term="typescript"/>
        <category label="vue" term="vue"/>
        <category label="tooling" term="tooling"/>
        <category label="npm" term="npm"/>
        <published>2025-11-01T23:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[Instalar Node.js 24 en Ubuntu 24.04]]></title>
        <id>https://angelblanco.dev/es/blog/install-node-24-on-ubuntu-24/</id>
        <link href="https://angelblanco.dev/es/blog/install-node-24-on-ubuntu-24/"/>
        <updated>2026-11-04T23:00:00.000Z</updated>
        <summary type="html"><![CDATA[Instalar Node.js 24 en Ubuntu 24 debería ser un proceso sencillo. Aunque Ubuntu incluye una versión de Node.js en sus repositorios por defecto, es posible que quieras utilizar una versión más reciente, como Node.js 24, que es LTS desde el 28 de octubre de 2025 y tiene soporte hasta abril de 2028. Si vas a instalarlo desde cero, mejor instala Node.js 26 en Ubuntu 26.04. En esta guía te enseño dos métodos para que lo tengas listo rápidamente.]]></summary>
        <content type="html"><![CDATA[<p>Instalar Node.js 24 en Ubuntu 24 debería ser un proceso sencillo. Aunque Ubuntu incluye una versión de Node.js en sus repositorios por defecto, es posible que quieras utilizar una versión más reciente, como Node.js 24, que es LTS desde el 28 de octubre de 2025 y tiene soporte hasta abril de 2028. Si vas a instalarlo desde cero, mejor <a href="https://angelblanco.dev/es/blog/apt-install-node-26-on-ubuntu-26/">instala Node.js 26 en Ubuntu 26.04</a>. En esta guía te enseño dos métodos para que lo tengas listo rápidamente.</p><p>Veremos un script de una sola línea que lo automatiza todo, incluyendo la configuración de npm necesaria para instalar herramientas globales sin permisos de administrador y la activación de <a href="https://yarnpkg.com/">Yarn</a> y <a href="https://pnpm.io/">pnpm</a> usando Corepack.</p><p>Si quieres personalizar la instalación, también veremos cómo hacerlo paso a paso.</p><h2 id="la-vía-fácil">La vía fácil</h2><p>Si tienes prisa, puedes instalarlo todo con un solo comando. He preparado un script que se encargará de instalar Node.js 24, configurar npm (para que no necesites <code>sudo</code> al instalar paquetes globales) y, opcionalmente, habilitar <code>corepack</code> (para Yarn y pnpm) e instalar Bun.</p><p>Abre la terminal y ejecuta:</p><pre><code class="language-bash">curl -fsSL https://angelblanco.dev/scripts/ubuntu-install-node-24.sh | bash</code></pre><p>El script te pedirá confirmación en cada paso importante, así que seguirás teniendo el control sobre lo que se instala. Por supuesto, puedes revisar el <a href="https://angelblanco.dev/es/blog/install-node-24-on-ubuntu-24/#el-script">contenido completo del script en este post</a>, o en la propia URL antes de ejecutarlo.</p><p>Si no tienes <code>curl</code> instalado:</p><pre><code class="language-bash">sudo apt update
sudo apt install curl</code></pre><h2 id="la-guía-paso-a-paso">La guía paso a paso</h2><p>Para quienes prefieren un enfoque más manual, aquí tienes un desglose de lo que hace el script. Puedes seguir estos pasos para realizar la instalación por tu cuenta.</p><h3 id="_1-actualizar-dependencias-y-añadir-el-repositorio-de-nodesource">1. Actualizar dependencias y añadir el repositorio de NodeSource</h3><p>Primero, tenemos que asegurarnos de que nuestro sistema tiene las herramientas necesarias para descargar e instalar Node.js.</p><pre><code class="language-bash">sudo apt update
sudo apt install -y ca-certificates curl gnupg</code></pre><p>A continuación, añadiremos el repositorio de <a href="https://nodesource.com/">NodeSource</a>, que es una fuente de confianza para obtener versiones actualizadas de Node.js en Debian y Ubuntu.</p><pre><code class="language-bash">curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -</code></pre><h3 id="_2-instalar-nodejs-y-npm">2. Instalar Node.js y npm</h3><p>Con el repositorio ya configurado, instalar Node.js es tan sencillo como ejecutar:</p><pre><code class="language-bash">sudo apt-get install -y nodejs</code></pre><p>Este comando instala tanto el entorno de ejecución <code>node</code> como el gestor de paquetes <code>npm</code>.</p><h3 id="_3-configurar-el-prefijo-global-de-npm">3. Configurar el prefijo global de npm</h3><p>Por defecto, <code>npm</code> instala los paquetes globales en un directorio del sistema que requiere <code>sudo</code>. Esto puede provocar problemas de permisos más adelante. Para evitarlo, es una buena práctica configurar un directorio local para tus paquetes globales.</p><pre><code class="language-bash">mkdir -p ~/.npm-global
npm config set prefix '~/.npm-global'</code></pre><p>También necesitarás añadir este directorio a tu <code>PATH</code>. Abre tu fichero <code>~/.bashrc</code> o <code>~/.zshrc</code> y añade la siguiente línea:</p><pre><code class="language-bash">export PATH=~/.npm-global/bin:$PATH</code></pre><h3 id="_4-habilitar-corepack-para-yarn-y-pnpm">4. Habilitar Corepack (para Yarn y pnpm)</h3><p><a href="https://nodejs.org/docs/latest-v24.x/api/corepack.html">Corepack</a> es una herramienta experimental incluida con Node.js que simplifica la gestión de diferentes gestores de paquetes. Con ella, no necesitas instalar <a href="https://yarnpkg.com/">Yarn</a> o <a href="https://pnpm.io/">pnpm</a> manualmente.</p><p>Para habilitarla, ejecuta:</p><pre><code class="language-bash">sudo corepack enable</code></pre><p>Ahora puedes usar <code>yarn</code> y <code>pnpm</code> en tus proyectos sin pasos de instalación adicionales.</p><h3 id="_5-instalar-bun-opcional">5. Instalar Bun (opcional)</h3><p><a href="https://bun.sh/">Bun</a> es un toolkit de JavaScript todo en uno y muy rápido que está ganando mucha popularidad. Si quieres probarlo, puedes instalarlo con su script oficial, que necesita <code>unzip</code>:</p><pre><code class="language-bash">sudo apt install -y unzip
curl -fsSL https://bun.sh/install | bash</code></pre><h2 id="el-script">El script</h2><p>Este es el script completo que automatiza los pasos anteriores. Pide confirmación antes de cada paso y borra sus archivos temporales al terminar.</p><pre><code class="language-bash">#!/bin/bash
#
# Author: Ángel Blanco
# License: MIT
#
# This script is provided &quot;as is&quot;, without warranty of any kind. Use at your own risk.
#
# Source: https://angelblanco.dev/blog/install-node-24-on-ubuntu-24
#
# Usage:
#   curl -fsSL https://angelblanco.dev/scripts/ubuntu-install-node-24.sh | bash
#
# This script installs Node.js and several package managers.
# Run it as your non-root user: it asks for elevated permissions
# with sudo when needed.
#

set -e

# Basic confirmation module before executing the script.
confirm_action() {
    read -p &quot;$1 (y/n): &quot; choice &lt; /dev/tty
    case &quot;$choice&quot; in
        [Yy]|[Yy][Ee][Ss])
            return 0
            ;;
        [Nn]|[Nn][Oo])
            return 1
            ;;
        *)
            echo &quot;Invalid choice. Please enter 'y' or 'n'.&quot;
            confirm_action &quot;$1&quot;
            ;;
    esac
}

# You can configure these variables if needed
NODE_VERSION=24
NPM_PREFIX=&quot;~/.npm-global&quot;
DEPS=&quot;ca-certificates curl gnupg&quot;

TMP_DIR=$(mktemp -d)
trap 'rm -rf &quot;$TMP_DIR&quot;' EXIT

echo &quot;This script will install Node.js and optionally other package managers.&quot;
echo &quot;&quot;

if ! confirm_action &quot;Install Node.js version $NODE_VERSION?&quot;; then
    echo &quot;Skipping Node.js installation. Exiting.&quot;
    exit 0
fi

echo &quot;Installing the dependencies needed to install Node.js...&quot;

sudo apt update
sudo apt install -y $DEPS

echo &quot;Installing Node.js...&quot;
curl -fsSL https://deb.nodesource.com/setup_$NODE_VERSION.x -o $TMP_DIR/nodesource_setup.sh
sudo -E bash $TMP_DIR/nodesource_setup.sh

sudo apt-get install -y nodejs

mkdir -p ~/.npm-global
npm config set prefix $NPM_PREFIX
echo &quot;npm prefix set to $NPM_PREFIX&quot;

echo &quot;Node.js installation completed.&quot;
echo &quot;Node version: &quot;
node --version

echo &quot;&quot;

if confirm_action &quot;Enable Yarn and pnpm via corepack?&quot;; then
    echo &quot;Enabling corepack...&quot;
    sudo corepack enable
    echo &quot;Corepack enabled.&quot;
    echo &quot;Yarn version: &quot;
    yarn --version
    echo &quot;PNPM version: &quot;
    pnpm --version
fi

echo &quot;&quot;

if confirm_action &quot;Install Bun?&quot;; then
    echo &quot;Installing Bun...&quot;
    sudo apt install -y unzip
    curl -fsSL https://bun.sh/install | bash
    export BUN_INSTALL=&quot;$HOME/.bun&quot;
    export PATH=&quot;$BUN_INSTALL/bin:$PATH&quot;
    echo &quot;Bun version: &quot;
    bun --version
fi

echo &quot;&quot;
echo &quot;Installation process finished.&quot;
echo &quot;&quot;
echo &quot;Add the global npm bin directory to your PATH by adding this line to your .bashrc or .zshrc:&quot;
echo 'export PATH=~/.npm-global/bin:$PATH'
echo &quot;&quot;</code></pre><h2 id="y-qué-hay-de-nvm">¿Y qué hay de NVM?</h2><p><a href="https://github.com/nvm-sh/nvm">Node Version Manager (NVM)</a> es una herramienta fantástica para gestionar múltiples versiones de Node.js. Sin embargo, personalmente prefiero mantenerme con una única instalación de la última versión LTS a nivel de sistema. Este enfoque me obliga a mantener mis proyectos actualizados. Además, Node.js no suele introducir grandes cambios disruptivos en sus versiones LTS, por lo que el proceso de actualización suele ser sencillo.</p><p>Si prefieres la flexibilidad de NVM, puedes seguir usándolo, pero probablemente acabarías eligiendo un método u otro. Después de instalar NVM, gestionarías tus gestores de paquetes como <code>yarn</code> y <code>pnpm</code> instalándolos globalmente a través de <code>npm</code> para cada versión de Node que utilices. Podrías entonces usar alias para cambiar entre diferentes versiones de tus herramientas. Ten en cuenta que esto a veces puede llevar a conflictos de rutas o comportamientos inesperados, así que ten cuidado con qué versiones están activas en tu terminal.</p>]]></content>
        <category label="nodejs" term="nodejs"/>
        <category label="ubuntu" term="ubuntu"/>
        <category label="javascript" term="javascript"/>
        <category label="bash" term="bash"/>
        <published>2025-10-11T22:00:00.000Z</published>
    </entry>
    <entry>
        <title type="html"><![CDATA[De Svelte a Nuxt: Reconstruyendo mi portfolio en 2025]]></title>
        <id>https://angelblanco.dev/es/blog/hello/</id>
        <link href="https://angelblanco.dev/es/blog/hello/"/>
        <updated>2025-09-26T22:00:00.000Z</updated>
        <summary type="html"><![CDATA[Estamos en 2025 y acabo de publicar una versión completamente nueva de mi web personal. He migrado de un stack basado en Svelte y Sapper a Nuxt, Tailwind CSS y un monorepo con Turborepo. No ha sido un cambio estético, sino una reescritura completa, fruto de cinco años de evolución en el frontend y de las ganas de usar en casa las mismas herramientas que en el trabajo.]]></summary>
        <content type="html"><![CDATA[<p>Estamos en 2025 y acabo de publicar una versión completamente nueva de mi web personal. He migrado de un stack basado en <a href="https://svelte.dev/">Svelte y Sapper</a> a <a href="https://nuxt.com/">Nuxt</a>, <a href="https://tailwindcss.com/">Tailwind CSS</a> y un monorepo con <a href="https://turborepo.dev/">Turborepo</a>. No ha sido un cambio estético, sino una reescritura completa, fruto de cinco años de evolución en el frontend y de las ganas de usar en casa las mismas herramientas que en el trabajo.</p><h2 id="la-decisión-de-2020-por-qué-svelte">La decisión de 2020: ¿Por qué Svelte?</h2><p>En 2020, cuando construí la primera versión de esta web, el ecosistema de Vue estaba en plena transición. Vue 3 estaba en pruebas, y se lanzó justo cuando yo ya había acabado mi página web. Los primeros dos años de Vue 3 fueron un dolor y Nuxt 3 no fue estable hasta noviembre de 2022. El camino de migración desde Vue 2 era incierto y, francamente, el futuro parecía algo inestable.</p><p>En aquel momento, Svelte y Sapper, su framework de aplicaciones, eran una alternativa muy atractiva: rápida, sencilla y estable. Fue la decisión acertada para su momento.</p><h2 id="el-punto-de-inflexión-ecosistema-vs-diy">El punto de inflexión: Ecosistema vs. DIY</h2><p>Cinco años después, la situación ha cambiado. Svelte sigue siendo un gran framework, pero el ecosistema de Nuxt ha crecido hasta cubrir casi todo lo que necesita una web como esta.</p><p>Con mi antigua web en Sapper, tuve que construir desde cero muchas funcionalidades: metaetiquetas para SEO, gestión de contenido para el blog y optimización de imágenes. Aprendí mucho, pero mantener ese código a medida se convirtió en un engorro. Además, migrar de Sapper a SvelteKit era un proyecto grande para el que, simplemente, no tenía tiempo.</p><p>Nuxt, en cambio, tiene módulos que resuelven todo eso sin configuración:</p><ul><li><a href="https://content.nuxt.com/">@nuxt/content</a> para gestionar el contenido desde archivos.</li><li><a href="https://nuxt.com/modules/seo">@nuxtjs/seo</a> para el SEO y los metadatos, con valores por defecto que sirven sin tocar nada.</li><li><a href="https://nuxt.com/modules/image">@nuxt/image</a> para optimizar las imágenes.</li><li><a href="https://nuxt.com/modules/icon">@nuxt/icon</a> para usar cualquier colección de iconos sin cargarla entera.</li></ul><p>Con eso resuelto, puedo centrarme en escribir.</p><h2 id="alineación-con-mi-flujo-de-trabajo-diario">Alineación con mi flujo de trabajo diario</h2><p>En el frontend de mi trabajo usamos Vue 3 con la Composition API, TypeScript y Tailwind. Tiene sentido que mi web personal use las mismas tecnologías que uso a diario. Trabajar con Nuxt me resulta natural y sencillo, una vez entiendes su filosofía.</p><h2 id="el-nuevo-stack-de-un-vistazo">El nuevo stack de un vistazo</h2><p><a href="https://nuxt.com/">Nuxt</a> es el núcleo de la aplicación. <a href="https://tailwindcss.com/">Tailwind CSS</a> se encarga de los estilos y <a href="https://daisyui.com/">daisyUI</a> añade los componentes y los temas claro y oscuro. <a href="https://turborepo.dev/">Turborepo</a> gestiona el monorepo, que reúne la app principal, las configuraciones compartidas y las herramientas internas en un único lugar.</p><h2 id="de-bulma-a-tailwind-css-daisyui">De Bulma a Tailwind CSS &amp; daisyUI</h2><p>En la versión anterior de mi web usaba <a href="https://bulma.io/">Bulma</a>, que es una librería CSS estupenda. Sin embargo, mi día a día gira en torno a Tailwind CSS, y pasar del template a un fichero CSS aparte me parece el doble de trabajo, porque rara vez reutilizas las clases entre componentes <code>.vue</code> o <code>.svelte</code>.</p><p>Como uso Tailwind todos los días, he empezado a &quot;pensar&quot; en Tailwind a la hora de maquetar. El live reload de Vite y el enfoque <em>utility-first</em> son parte de mi forma de trabajar y, una vez que piensas así, es muy difícil volver atrás. Para esta versión lo he combinado con <a href="https://daisyui.com/">daisyUI</a>. Me permite usar componentes ya listos cuando no me quiero complicar, y prescindir de ellos para crear algo totalmente a medida sin perder ninguna de las ventajas de Tailwind. Además, trae un sistema de temas pensado para Tailwind con el que puedes tener tantos temas como quieras.</p><h2 id="el-papel-de-la-ia-en-el-desarrollo">El papel de la IA en el desarrollo</h2><p>Esta reconstrucción también ha sido una oportunidad para probar la última generación de asistentes de código con IA. He probado (demasiadas) herramientas, como <a href="https://github.com/google-gemini/gemini-cli">Gemini CLI</a>, <a href="https://github.com/Aider-AI/aider">Aider</a> y <a href="https://github.com/features/copilot">GitHub Copilot</a>. Algunos días me he sentido con superpoderes y otros, como si tuviera la gripe. Si cumplo mi objetivo de escribir más, pronto te contaré más sobre cada una.</p><h2 id="y-ahora-qué">¿Y ahora qué?</h2><p>Quiero escribir más, compartir algunas ideas que llevo mucho tiempo pensando y quizás empezar a contribuir en algún proyecto open source.</p><p>Gracias por leer. Nos vemos.</p>]]></content>
        <category label="nuxt" term="nuxt"/>
        <category label="vue" term="vue"/>
        <category label="svelte" term="svelte"/>
        <category label="turborepo" term="turborepo"/>
        <category label="tailwindcss" term="tailwindcss"/>
        <published>2025-09-26T22:00:00.000Z</published>
    </entry>
</feed>