Cómo DevContainers mejoró la coherencia y simplificó la incorporación en un proyecto frontend

Compartir esta publicación

En nuestro proyecto de frontend, empezamos a enfrentarnos a varios problemas comunes con los que muchos equipos pueden identificarse:

  • Cada desarrollador tenía una versión diferente de Node.js, lo que a veces provocaba comportamientos incoherentes.
  • Algunos compañeros de equipo no tenían las extensiones o configuraciones de VS Code adecuadas, lo que hacía que la base de código pareciera desordenada y desorganizada.
  • Los desarrolladores del backend que trabajaban ocasionalmente en el frontend carecían por completo de un entorno Node, y configurarlo -especialmente cuando se trataba de problemas complicados con paquetes- solía llevar mucho tiempo.
  • Los nuevos desarrolladores tenían que pasar por un proceso de incorporación manual y propenso a errores, que implicaba comprobar versiones, instalar dependencias y, a veces, incluso revisar la documentación de Azure sólo para obtener autorización.

Así que nos preguntamos: ¿Cómo podemos hacer que esto sea más rápido e igual para todos?

Fue entonces cuando nos decidimos por VS Code Devcontainers, una forma sencilla pero potente de proporcionar un entorno de desarrollo preconfigurado y portátil. Con DevContainers, podíamos:

  • Asegurarnos de que todos utilizan la misma versión de Node.js, extensiones y herramientas.
  • Ayudar a los desarrolladores del backend a trabajar en el código del frontend sin ninguna configuración manual.
  • Crear una experiencia de incorporación sencilla para los recién llegados, simplemente clona el repositorio y ábrelo en un DevContainer.

Por supuesto, había algunas limitaciones menores, como depender del terminal VS Code dentro del contenedor, pero los beneficios superaban a las desventajas. Y en este artículo, te mostraré el proceso.

Cómo funcionan los Devcontainers entre bastidores

DevContainers (abreviatura de Development Containers) es un método para definir y configurar un entorno de desarrollo consistente utilizando Docker.

  • Cuando haces clic en «Reabrir en contenedor» en VS Code, el editor utiliza Docker para construir e iniciar un contenedor de desarrollo definido por su configuración .devcontainer.
  • Una vez que el contenedor se está ejecutando, VS Code instala un proceso backend headless llamado VS Code Server dentro del contenedor. Este servidor gestiona todas las funciones de desarrollo, como la edición de archivos, los terminales y la depuración, mientras que la interfaz de usuario permanece en el equipo host.
  • Se crea automáticamente un volumen Docker persistente -a menudo denominado vscode- para almacenar este servidor y cualquier extensión instalada, lo que garantiza un inicio más rápido y la reutilización en todas las sesiones.
  • Cuando abres un terminal en el entorno del contenedor, se lanza un shell (por ejemplo, bash) dentro del contenedor, normalmente bajo el usuario por defecto definido en el Dockerfile. Como resultado, puede que veas que el terminal se inicia en una ruta Linux como /root o /home/vscode.

Esta arquitectura permite a los desarrolladores trabajar en entornos aislados y reproducibles, con todas las herramientas y dependencias encapsuladas dentro del contenedor, manteniendo al mismo tiempo una experiencia fluida dentro de VS Code.

  Consejos para controlar los riesgos de seguridad del código y la infraestructura

Una configuración típica de DevContainer incluye los siguientes archivos:

devcontainer.json: Define el nombre del contenedor, importa el archivo Docker Compose. También puede añadir las extensiones y la configuración de VSCode.

docker.compose.yml: Define la configuración del contenedor, volúmenes, puertos, variables de entorno y argumentos de compilación (token NPM, credenciales Git, etc).

Dockerfile: Personaliza el entorno, como instalar versiones específicas de Node.js, gestores de paquetes o herramientas CLI.

Implementación de DevContainers en VS Code

devcontainer.json

{
 "name": "frontendDev",
 "dockerComposeFile": [
   "docker-compose.yml"
 ],
 "postCreateCommand": "/workspace/.devcontainer/init-git.sh",
 "service": "master",
 "runServices": [
   "master"
 ],
 "forwardPorts": [
   3000
 ],
 "shutdownAction": "stopCompose",
 "overrideCommand": true,
 "workspaceFolder": "/workspace",
 "customizations": {
   "extensions": [    
     "github.vscode-pull-request-github" // Github interaction
   ],
   "settings": {
     "prettier-eslint.eslintIntegration": true,
   }
 }
}

Esta configuración garantiza que se inicialicen los servicios correctos, que se vincule el archivo Docker Compose, que se expongan puertos esenciales como el 3000 para el servidor de desarrollo y que las extensiones y la configuración estén disponibles en un entorno coherente para todos los miembros del equipo.

docker-compose.yml

Este archivo organiza el entorno de desarrollo en contenedores especificando cómo debe construirse y ejecutarse el contenedor, qué volúmenes debe montar y cómo maneja los puertos y las variables de entorno.

version: "3.7"
services:
 master:
   build:
     context: ..
     dockerfile: .devcontainer/Dockerfile
     args:
       NPM_TOKEN: ${NPM_TOKEN}
       GIT_EMAIL: ${GIT_EMAIL}
       GIT_NAME: ${GIT_NAME}
       GIT_USER: ${GIT_USER}
       GIT_CREDENTIAL: ${GIT_CREDENTIAL}
   volumes:
     - node_modules:/workspace/node_modules
     - build:/workspace/build
     - ../:/workspace
   ports:
     - 3000:3000
   env_file: .env
volumes:
 node_modules:
​​build:
  • servicios:
    Define los servicios individuales del contenedor. En este caso, tenemos un único servicio llamado master, que representa nuestro entorno de desarrollo frontend.

Service: master

  • build:
    • context: ..
      El contexto de construcción apunta al directorio padre de .devcontainer, permitiendo a Docker acceder a todos los archivos del proyecto.
    • dockerfile: .devcontainer/Dockerfile
      Especifica el Dockerfile utilizado para construir la imagen del contenedor.
    • args:
      Pasa argumentos secretos en tiempo de compilación (como credenciales Git y tokens npm) desde variables de entorno. Estos valores se inyectan de forma segura a través de .env y no están codificados.
  • volumes:
    • node_modules:/workspace/node_modules
      Aísla node_modules de la carpeta del proyecto para evitar conflictos entre las instalaciones del host y del contenedor.
    • ​​build:/workspace/build:

Artefactos de compilación compartidos (por ejemplo, archivos compilados) entre el contenedor y el host.

  • ../:/workspace
    Monta todo el directorio del proyecto en el contenedor, haciendo que el código fuente esté disponible dentro del contenedor en /workspace.

Named Volumes

  • node_modules
    Mantiene las instalaciones de dependencias aisladas del sistema anfitrión.
  • build: Comparte los resultados de la compilación entre el contenedor y el host.

Dockerfile

Para asegurarnos de que nuestro contenedor de desarrollo tiene todo lo que necesita para funcionar, creamos un archivo Dockerfile dentro de la carpeta .devcontainer. Este archivo define una imagen mínima basada en Node.js preconfigurada para nuestro proyecto frontend.

Aquí tienes un desglose de lo que hace:

1. Imagen base y directorio de trabajo

FROM node:20.15.1
EXPOSE 3000
WORKDIR /workspace
  • El puerto 3000 está expuesto, alineándose con el puerto utilizado por nuestro servidor de desarrollo.
  • El directorio de trabajo dentro del contenedor se establece en /workspace, que contendrá el código fuente de nuestro proyecto.
  Libros de arquitectura de software que se presentarán en GSAS 2023

2. Integración de Cypress

RUN apt-get update && \
   export DEBIAN_FRONTEND=noninteractive && \
   apt-get -y install --no-install-recommends \
       libgtk2.0-0 \
       libgtk-3-0 \
       libgbm-dev \
       libnotify-dev \
       libgconf-2-4 \
       libnss3 \
       libxss1 \
       libasound2 \
       libxtst6 xauth xvfb

Estas librerías de sistema son necesarias para ejecutar Cypress en un entorno de navegador headless (Electron/Chrome). xvfb crea una pantalla virtual para herramientas GUI en contenedores headless.

3. Preparación de la instalación de la dependencia

COPY package.json pnpm-lock.yaml* ./
COPY .husky .husky
  • Copiamos los archivos de manifiesto de dependencia (package.json, pnpm-lock.yaml) al contenedor. Esto nos permite instalar paquetes sin copiar todo el código base, lo que ahorra tiempo durante la creación de imágenes.
  • También copiamos la carpeta .husky, que contiene ganchos Git para aplicar comprobaciones de calidad del código.

4. Acceso seguro al registro privado de paquetes

ARG NPM_TOKEN
RUN echo "...auth token config..." > .npmrc
  • Usando un argumento de compilación (NPM_TOKEN), inyectamos credenciales de forma segura durante el tiempo de compilación para autenticarnos con nuestro registro privado de paquetes.
  • El archivo .npmrc se genera dinámicamente dentro de la imagen, lo que permite acceder a los paquetes internos de alcance durante la instalación.

5. Instalación de dependencias y preparación de herramientas

RUN npm install -g pnpm
RUN pnpm config set store-dir /root/.local/share/pnpm/store/v10 --global
RUN pnpm install
RUN pnpm config set side-effects-cache false --location project
RUN pnpm --allow-build=cypress add --save-dev cypress
RUN pnpm prepare
  • pnpm se instala globalmente para gestionar las dependencias de forma eficiente.
  • pnpm install instala todas las dependencias del proyecto listadas en el archivo de bloqueo.
  • pnpm prepare ejecuta scripts de configuración específicos del proyecto (como la configuración de ganchos Git con Husky), asegurando que el contenedor está listo para las tareas de desarrollo.
  • pnpm –allow-build=cypress add –save-dev cypress añade Cypress con permiso explícito para construir módulos nativos en el contenedor.

¿Cómo iniciar el proyecto?

Como parte de nuestra configuración de DevContainer, hemos creado un script de inicialización que ayuda a los desarrolladores a configurar las credenciales personales y las variables de entorno necesarias para acceder a los registros privados y a los repositorios Git. Este script simplifica la incorporación a la vez que mantiene los secretos fuera del control de origen.

#!/bin/bash
set -e


echo "Welcome to ${project_name}"


echo ""
echo "Open the next url, create a new token (full access and lastest day of expiry):"
echo "   👉 https://project_url/tokens"
read -p "Paste here your token: " TOKEN
TOKEN_BASE64=$(python3 -c "import base64; print(base64.b64encode(b'$TOKEN').decode())")


echo ""
echo "2️⃣ Now open this link, click on 'Clone' and click 'Generate Git Credentials:"
echo "   👉 https://project_url"
read -p "Paste here your credential: " CREDENTIAL


# Create the .env
cat > .devcontainer/.env <<EOF
NPM_TOKEN=$TOKEN_BASE64
GIT_CREDENTIAL=$CREDENTIAL
EOF
echo "✅ Setup successfully completed!"

Para agilizar el proceso de configuración y evitar la ejecución manual de comandos, hemos introducido un Makefile con un objetivo conveniente para ejecutar el script de inicialización de credenciales. Esto permite a cualquier desarrollador iniciar la configuración del entorno con un solo comando:

configuración del entorno con un solo comando:

make init

  • Sigue las instrucciones para introducir su token de acceso personal, credenciales Git, nombre y correo electrónico. Esto genera de forma segura el archivo .env necesario para el contenedor.
  • Abra la extensión DevContainers en VS Code.
  • Haz clic en «Reabrir en contenedor» o seleccione «Reconstruir y reabrir en contenedor» si se han realizado cambios en los archivos .devcontainer.
  • Una vez conectado al contenedor, ejecuta el comando pnpm start
  Receta de JavaScript con Closures, Currying y Arrow Functions

Y ¡voilá! Ya tienes el proyecto funcionando en el contenedor de desarrollo.

CONSEJO: Cuando utilice Devcontainers, puede que necesite hacer clic en «eliminar la caché de compilación de Docker y volver a abrir el contenedor» para garantizar una reconstrucción limpia del entorno. Esto es especialmente útil cuando:

  1. Dockerfile o dependencias cambian: Si has actualizado tu Dockerfile, devcontainer.json, o añadido/reasignado volúmenes, Docker puede reutilizar las capas en caché y no reflejar los últimos cambios. Eliminar la caché obliga a Docker a reconstruir todo desde cero, aplicando todas las actualizaciones correctamente.
  2. Módulos_nodo obsoletos o problemas de entorno: Los volúmenes montados como node_modules pueden causar conflictos entre las dependencias del host y del contenedor, especialmente en proyectos JavaScript/Node. La reconstrucción ayuda a restablecerlas para que coincidan con el entorno del contenedor.
  3. Extensiones/configuraciones corruptas o anticuadas: El volumen .vscode-server a veces puede tener versiones desajustadas o extensiones rotas. La reconstrucción borra estos errores y reinstala versiones limpias.

Conclusión

Los DevContainers de VS Code redefinen la forma en que abordamos el desarrollo local. Con DevContainers, no necesitas instalar Node.js, pnpm, o incluso configurar tokens Git o NPM en tu máquina anfitriona. Todo, herramientas, extensiones, configuraciones y credenciales, vive dentro del contenedor. Para los equipos que hacen malabares con varios proyectos o que trabajan con varios perfiles de Git, este aislamiento cambia las reglas del juego: tus credenciales se mantienen limpias y con un alcance limitado.

Y sí, el proyecto se ejecuta. Ningún infierno de configuración local. Sin entornos desajustados. Simplemente clone, ejecute make init, y sumérjase en un espacio de trabajo VS Code Devcontainer completamente configurado.

Dicho esto, los DevContainers no son perfectos. Están ligados a IDEs. Si dependes de terminales externos como Warp u otras herramientas personalizadas fuera de tu editor, esto puede suponer una limitación.

Aún así, para la mayoría de los flujos de trabajo frontales modernos, los DevContainers ofrecen un equilibrio entre velocidad, coherencia y portabilidad, lo que los convierte en una inversión sólida para cualquier equipo que se tome en serio el desarrollo escalable.

Si te interesa este tipo de contenido, no dudes en visitar el blog tecnológico de Apiumhub. Cada mes se publican nuevos contenidos sobre las últimas tendencias y tecnologías.

Author

  • Beste Burcu Bayhan

    Graduated from Istanbul Technical University with a bachelor degree of computer engineering in June 2018. During her studies, she has been involved in projects in various areas including web development, computer vision and computer networks.

    View all posts

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Suscríbete a nuestro boletín de noticias

Recibe actualizaciones de los últimos descubrimientos tecnológicos

Acerca de Apiumhub

Apiumhub reúne a una comunidad de desarrolladores y arquitectos de software para ayudarte a transformar tu idea en un producto potente y escalable. Nuestro Tech Hub se especializa en Arquitectura de Software, Desarrollo Web & Desarrollo de Aplicaciones Móviles. Aquí compartimos con usted consejos de la industria & mejores prácticas, basadas en nuestra experiencia.

Estima tu proyecto

Contacta
Posts populares
Obtén nuestro Libro: Software Architecture Metrics

¿Tienes un proyecto desafiante?

Podemos trabajar juntos

apiumhub software development projects barcelona
Secured By miniOrange