Cómo organizar las carpetas de un proyecto de JavaScript en 8 pasos
Una buena organización del proyecto es esencial para crear código escalable, fácil de mantener y colaborativo.
Sin una estructura clara, el código puede volverse difícil de navegar, complicando la implementación de nuevas funciones y la resolución de errores.
En este artículo, exploraremos cómo organizar un proyecto de programación, desde estructuras básicas hasta ejemplos más avanzados y complejos.
Con pequeñas modificaciones también vale para organizar en carpetas proyectos de TypeScript.
Cada semana, experiencias y aprendizaje sobre desarrollo web e IA en tu bandeja de entrada.
Únete a más de 5.800 developers que ya reciben la newsletter.
Suscríbete gratis →¿Por qué es importante organizar tu proyecto? ¶
Organizar tu proyecto correctamente te ofrece múltiples beneficios:
- Facilita la navegación: Una estructura clara te permite encontrar rápidamente los archivos y las partes del código que necesitas modificar.
- Mejora la colaboración: Otros desarrolladores pueden unirse al proyecto y entender dónde hacer cambios sin dificultad.
- Simplifica el mantenimiento: Cuando necesitas corregir errores o añadir funciones, una estructura organizada reduce la posibilidad de cometer errores.
- Facilita la escalabilidad: A medida que el proyecto crece, una buena organización te permite agregar nuevas funciones sin crear caos.
Vamos a ver diferentes ejemplos, desde estructuras básicas hasta complejas, adaptadas a distintos tipos de proyectos.
Paso 1: Proyecto básico de JavaScript ¶
En proyectos pequeños o simples, como scripts de automatización o pequeños programas, no necesitas una estructura elaborada. Aquí tienes un ejemplo de una estructura básica:
miProyecto
├── index.js
├── config.js
├── utils.js
└── README.md
Explicación: ¶
- index.js: Archivo principal que ejecuta el código.
- config.js: Contiene configuraciones y valores constantes.
- utils.js: Incluye funciones auxiliares reutilizables.
- README.md: Documentación básica del proyecto.
Este tipo de estructura es ideal para scripts pequeños y herramientas simples.
Paso 2: Proyecto web básico ¶
Para un proyecto web simple que utiliza HTML, CSS y JavaScript, una estructura organizada puede ser así:
miProyectoWeb
├── index.html
├── styles
│ └── styles.css
├── scripts
│ └── main.js
└── assets
└── logo.png
Explicación: ¶
- index.html: El archivo HTML principal.
- styles: Carpeta para archivos CSS.
- scripts: Carpeta para archivos JavaScript.
- assets: Carpeta para imágenes, fuentes u otros recursos.
Esta estructura es sencilla pero permite mantener separados los estilos, el código JavaScript y los recursos multimedia.
Paso 3: Proyecto Node.js sencillo ¶
Si estás trabajando en una aplicación de servidor con Node.js, aquí tienes una estructura básica:
miProyectoNode
├── src
│ ├── index.js
│ ├── config.js
│ └── utils.js
├── package.json
└── README.md
Explicación: ¶
- src: Carpeta que contiene el código fuente.
- index.js: Punto de entrada de la aplicación.
- config.js: Configuraciones y constantes del proyecto.
- utils.js: Funciones auxiliares.
- package.json: Archivo de configuración de npm para gestionar dependencias.
Esta estructura es ideal para proyectos pequeños o prototipos en Node.js.
Paso 4: Proyecto React ¶
En proyectos de React, una estructura clara ayuda a manejar componentes, estilos y datos. Aquí tienes una estructura recomendada para aplicaciones React:
miProyectoReact
├── public
│ └── index.html
├── src
│ ├── components
│ │ ├── Button.js
│ │ └── Header.js
│ ├── pages
│ │ ├── Home.js
│ │ └── About.js
│ ├── App.js
│ ├── index.js
│ └── styles.css
├── package.json
└── README.md
Explicación: ¶
- public: Archivos públicos accesibles directamente.
- components: Componentes reutilizables de la interfaz de usuario.
- pages: Componentes que representan páginas completas.
- App.js: Componente raíz de la aplicación.
- index.js: Punto de entrada de la aplicación React.
- styles.css: Archivo CSS global.
Esta estructura facilita la reutilización de componentes y permite escalar la aplicación.
Paso 5: Proyecto de API REST con Node.js y Express ¶
Cuando construyes una API REST, necesitas organizar tu código para manejar rutas, controladores y lógica de negocio. Aquí tienes una estructura típica:
miApiRest
├── src
│ ├── controllers
│ │ ├── userController.js
│ │ └── productController.js
│ ├── models
│ │ ├── userModel.js
│ │ └── productModel.js
│ ├── routes
│ │ ├── userRoutes.js
│ │ └── productRoutes.js
│ ├── services
│ │ ├── userService.js
│ │ └── productService.js
│ ├── index.js
│ └── config.js
├── package.json
└── README.md
Explicación: ¶
- controllers: Contiene la lógica para manejar las solicitudes HTTP.
- models: Define la estructura de los datos y las interacciones con la base de datos.
- routes: Define las rutas de la API.
- services: Contiene la lógica de negocio y funciones auxiliares.
- index.js: Punto de entrada de la API.
- config.js: Configuraciones y valores constantes.
Esta estructura permite mantener la lógica de negocio, el manejo de rutas y la interacción con la base de datos claramente separadas.
Paso 6: Proyecto complejo (Aplicación Full Stack) ¶
Para proyectos grandes y complejos, como una aplicación full stack con frontend y backend, la estructura puede ser más avanzada:
miProyectoFullStack
├── client
│ ├── public
│ ├── src
│ │ ├── components
│ │ ├── pages
│ │ ├── App.js
│ │ └── index.js
│ └── package.json
├── server
│ ├── controllers
│ ├── models
│ ├── routes
│ ├── services
│ ├── index.js
│ └── config.js
├── .env
├── docker-compose.yml
├── package.json
└── README.md
Explicación: ¶
- client: Contiene el frontend de la aplicación (React, Angular, etc.).
- server: Contiene el backend (Node.js, Express, etc.).
- .env: Variables de entorno.
- docker-compose.yml: Archivo de configuración para Docker.
- package.json: Maneja dependencias compartidas entre frontend y backend.
Esta estructura permite trabajar de manera independiente en frontend y backend, lo que facilita el desarrollo y la colaboración.
En la primera parte de este artículo cubrimos desde ejemplos básicos hasta una estructura completa para una aplicación Full Stack. Ahora, vamos a expandir esos ejemplos con estructuras aún más detalladas y avanzadas que son utilizadas en proyectos de gran escala.
Paso 7: Arquitectura basada en capas (Clean Architecture) ¶
La arquitectura basada en capas, también conocida como Clean Architecture, es un patrón diseñado para maximizar la mantenibilidad y escalabilidad de una aplicación. Este enfoque divide tu proyecto en capas independientes, cada una con responsabilidades claras y separadas, lo que permite desarrollar, probar y escalar más fácilmente.
Estructura del proyecto ¶
miProyectoCleanArchitecture
├── domain
│ ├── entities
│ └── repositories
├── application
│ ├── use-cases
│ └── dto
├── infrastructure
│ ├── controllers
│ ├── models
│ ├── routes
│ └── database
├── config
│ └── env.js
├── tests
├── package.json
└── README.md
Desglose de la estructura: ¶
-
domain: Es la capa central que contiene las reglas de negocio y no tiene dependencias externas. Aquí definimos:
- entities: Clases que representan los objetos del dominio (por ejemplo,
User,Product). Definen las propiedades y métodos relacionados con el negocio. - repositories: Interfaces que definen cómo interactuar con los datos (por ejemplo,
IUserRepository). No contienen implementación concreta.
- entities: Clases que representan los objetos del dominio (por ejemplo,
-
application: Esta capa contiene los casos de uso (o “use cases”), que representan las acciones específicas del negocio.
- use-cases: Funciones o clases que implementan la lógica del negocio (por ejemplo,
CreateUser,UpdateProduct). - dto (Data Transfer Objects): Objetos que se utilizan para transferir datos entre capas, facilitando la validación y transformación de datos.
- use-cases: Funciones o clases que implementan la lógica del negocio (por ejemplo,
-
infrastructure: Contiene la implementación concreta y los detalles técnicos de la aplicación.
- controllers: Manejan las solicitudes HTTP y actúan como punto de entrada para la aplicación.
- models: Definen los esquemas de la base de datos (por ejemplo, usando MongoDB o Sequelize).
- routes: Define las rutas de la API y conecta los controladores con los casos de uso.
- database: Configuración y conexión a la base de datos.
-
config: Almacena configuraciones, como variables de entorno y archivos de configuración específicos de la aplicación.
-
tests: Carpeta para almacenar pruebas unitarias y de integración.
Ejemplo de implementación: ¶
domain/entities/User.js
class User {
constructor(id, name, email) {
this.id = id;
this.name = name;
this.email = email;
}
}
module.exports = User;
domain/repositories/IUserRepository.js
class IUserRepository {
create(user) {
throw new Error('Method not implemented.');
}
findById(id) {
throw new Error('Method not implemented.');
}
}
module.exports = IUserRepository;
application/use-cases/CreateUser.js
class CreateUser {
constructor(userRepository) {
this.userRepository = userRepository;
}
execute(userData) {
const user = new User(userData.id, userData.name, userData.email);
return this.userRepository.create(user);
}
}
module.exports = CreateUser;
infrastructure/controllers/UserController.js
const CreateUser = require('../../application/use-cases/CreateUser');
const UserRepository = require('../models/UserRepository');
class UserController {
static async createUser(req, res) {
const userRepository = new UserRepository();
const createUser = new CreateUser(userRepository);
const userData = req.body;
try {
const user = await createUser.execute(userData);
res.status(201).json(user);
} catch (error) {
res.status(400).json({ message: error.message });
}
}
}
module.exports = UserController;
Ventajas de esta arquitectura: ¶
- Alta mantenibilidad: Cada capa tiene responsabilidades claras, lo que facilita la localización de errores y la implementación de nuevas funciones.
- Pruebas fáciles: El desacoplamiento de la lógica de negocio y la infraestructura facilita la prueba de casos de uso independientes.
- Escalabilidad: Permite añadir nuevas funcionalidades o cambiar la infraestructura (por ejemplo, cambiar de base de datos) sin afectar la lógica del negocio.
Paso 8: Monorepo usando Yarn o NPM Workspaces ¶
En proyectos grandes con múltiples aplicaciones o paquetes, un monorepo permite gestionar todo el código en un solo repositorio. Usar herramientas como Yarn Workspaces o NPM Workspaces facilita compartir código y configuraciones, lo que mejora la productividad y la consistencia.
Estructura del proyecto ¶
miMonorepo
├── packages
│ ├── common
│ │ ├── index.js
│ │ └── package.json
│ └── ui-components
│ ├── Button.js
│ ├── Modal.js
│ └── package.json
├── apps
│ ├── client
│ │ ├── src
│ │ ├── public
│ │ └── package.json
│ └── server
│ ├── src
│ ├── controllers
│ └── package.json
├── package.json
└── README.md
Configuración del Monorepo con Yarn Workspaces: ¶
package.json (raíz)
{
"name": "miMonorepo",
"private": true,
"workspaces": [
"apps/*",
"packages/*"
]
}
Ventajas del Monorepo: ¶
- Gestión centralizada: Todas las dependencias y scripts se gestionan desde la raíz del repositorio.
- Reutilización de código: Los paquetes como
commonyui-componentsse comparten fácilmente entre las aplicaciones del monorepo. - Consistencia: Al tener un solo repositorio, es más fácil mantener configuraciones uniformes y aplicar cambios globales.
Ejemplo de uso: ¶
apps/client/src/App.js
import Button from 'ui-components/Button';
function App() {
return (
<div>
<h1>Hola desde Monorepo</h1>
<Button label="Clic aquí" />
</div>
);
}
export default App;
Ejecución del Monorepo: ¶
Para instalar todas las dependencias, ejecuta:
yarn install
Para ejecutar el cliente:
yarn workspace client start
Para ejecutar el servidor:
yarn workspace server start
Herramientas útiles: ¶
- Yarn Workspaces: Facilita la gestión de dependencias y la ejecución de scripts en un monorepo.
- Lerna: Complemento para Yarn o NPM Workspaces que ayuda a gestionar versiones y despliegues en monorepos grandes.
- Turbo Repo: Herramienta para acelerar la ejecución de scripts y la gestión de caché en monorepos.
- Portless: Si te cansas de recordar qué puerto corresponde a cada servicio del monorepo, Portless reemplaza los puertos por URLs estables con nombre.
Colofón ¶
No importa el tamaño de tu proyecto, organizarlo correctamente desde el principio te ahorrará tiempo y dolores de cabeza a medida que crece. Aquí tienes algunos consejos finales:
- Mantén la simplicidad: No sobrecompliques tu estructura si no es necesario.
- Sigue un estándar: Usa convenciones establecidas y sigue las mejores prácticas de la comunidad.
- Documenta tu estructura: Incluye un archivo
README.mdque explique cómo está organizada tu estructura y cómo usar el proyecto.
Con una buena organización del proyecto, estarás preparado para escalar, colaborar y mantener tu código de forma efectiva.
12 recursos para developers cada domingo en tu bandeja de entrada
Además de una skill práctica bien explicada, trucos para mejorar tu futuro profesional y una pizquita de humor útil para el resto de la semana. Gratis.