Setup de React moderno con Vite, TypeScript y estructura de carpetas recomendada
Introducción
Si estás empezando un proyecto React nuevo o querés modernizar uno existente, Vite se ha convertido en la herramienta preferida por su velocidad y eficiencia. Agregar TypeScript a la mezcla mejora la mantenibilidad y la seguridad del tipado. Juntos, estos tres elementos forman una base sólida para aplicaciones escalables y limpias.
En este tutorial, vas a aprender paso a paso cómo crear un proyecto React con Vite y TypeScript, explorar una estructura de carpetas ampliamente adoptada, configurar herramientas complementarias como ESLint, Prettier y Husky, y finalmente ejecutar el servidor de desarrollo y generar una compilación optimizada. Todo el proceso se ilustra con comandos reales y la salida esperada, para que puedas seguir sin dudas.
Este artículo está dirigido a desarrolladores que ya saben programar en JavaScript/TypeScript y quieren un punto de partida profesional, sin relleno innecesario. No necesitas conocimientos previos sobre Vite, aunque familiaridad con la línea de comandos y los conceptos básicos de React ayudará.
A lo largo de las próximas secciones, vas a ver cómo crear un nuevo proyecto, examinar una estructura de carpetas razonable, comprender las configuraciones esenciales de TypeScript, agregar linting y formateo automáticos, y finalmente ver cómo arrancar el servidor de desarrollo y generar una compilación para producción. Al final, vas a tener un proyecto completamente funcional que podés ampliar de inmediato.
Instalación del entorno: Node y npm
Antes que nada, necesitás un entorno Node.js funcional. La mayoría de las distribuciones de Node incluyen npm (el gestor de paquetes de Node), pero podés verificar las versiones con un simple comando.
node -v
npm -vSi la salida muestra versiones antiguas (por debajo de 18.x para Node), es recomendable actualizar a través del gestor de versiones de Node (nvm) o el administrador de paquetes de tu sistema operativo. Una versión moderna de Node garantiza soporte para los últimos features del lenguaje, mejor rendimiento y parches de seguridad.
Creando un nuevo proyecto con Vite
Vite está disponible como un comando de npm, create-vite. La forma más rápida de iniciar un nuevo proyecto React con TypeScript es la siguiente:
npm create vite@latest my-app -- --typescriptPuedes reemplazar my-app con el nombre que prefieras. El comando ejecuta un asistente interactivo que pregunta por cosas como el framework (React) y el lenguaje (TypeScript). Cuando todo está listo, verás una salida similar a esta:
✔ Framework: react
✔ Language: TypeScript
✔ Package manager: npm
Sucediste crear el proyecto my-appDespués del asistente, el CLI te guiará a través de:
cd my-app
npm installEl npm install descarga todas las dependencias necesarias (React, TypeScript, Vite, etc.) y genera un package.json con los scripts correctos predefinidos (npm run dev, npm run build, etc.).
Explorando la estructura de carpetas recomendada
Una vez dentro del nuevo directorio, podés examinar la estructura generada por defecto. Aunque Vite ya te entrega un esqueleto utilizable, a menudo es mejor adaptarlo a una convención que escale bien a medida que la aplicación crece. Debajo tenés un esquema común que se alinea con muchas guías de código limpio y proyectos de producción reales.
my-app/
├── node_modules/
├── public/
│ ├── index.html
│ └── favicon.ico
├── src/
│ ├── assets/
│ │ └── images/
│ │ └── icons/
│ ├── components/
│ │ ├── ui/
│ │ ├── layout/
│ │ └── features/
│ ├── hooks/
│ ├── pages/
│ ├── types/
│ ├── utils/
│ ├── services/
│ ├── store/
│ └── App.tsx
├── .eslintrc.cjs
├── .prettierrc
├── .huskyrc
├── tsconfig.json
└── vite.config.tsA continuación, profundizamos en cada carpeta y explicamos cuál es su propósito.
src/ – El corazón de la aplicación
El directorio src es el punto de partida para tu código fuente. Contiene todo lo que el código compilado de Vite verá. Es importante mantenerlo separado de los archivos de configuración y de los archivos estáticos, para facilitar que la compilación ignore entradas no relevantes.
src/components – Componentes UI reutilizables
Los componentes React deberían residir aquí. Una división común subdivide aún más:
src/components/ui/– Componentes de interfaz de usuario de bajo nivel (botones, tarjetas, modales, etc.) que suelen ser independientes del dominio.src/components/layout/– Componentes de nivel superior comoNavbar,Sidebar,Footer.src/components/features/– Componentes específicos de cada característica que pertenecen a una ruta o funcionalidad particular.
Mantener separados los componentes de UI de los componentes de características ayuda a que los equipos colaboren sin chocar entre sí.
src/pages – Rutas de nivel superior
Si estás usando React Router, podrías guardar los componentes de las rutas en src/pages. Esto aisla la lógica de enrutamiento de la lógica de la interfaz de usuario. Por ejemplo, un archivo src/pages/Dashboard.tsx puede contener tanto un componente funcional como su definición de ruta:
// src/pages/Dashboard.tsx
import React from 'react';
import { Route } from 'react-router-dom';
export const DashboardPage = () => (
<div>Bienvenido al panel de control</div>
);
// En router.tsx
<Route path="/dashboard" element={<DashboardPage />} />src/hooks – Lógica de efectos reutilizable
Los hooks personalizados deberían ubicarse aquí. Ejemplos típicos:
useLocalStorage.ts– Persistir estado enlocalStorage.useDebounce.ts– Retrasar actualizaciones de entrada.useApi.ts– Envuelve fetch y manejo de errores.
Mantenerlos juntos hace más fácil descubrirlos, probarlos y reutilizarlos en cualquier parte de la app.
src/utils – Utilidades puras
Las funciones puras, helpers y utilidades genéricas van acá: src/utils/deepMerge.ts, src/utils/formatDate.ts, src/utils/cn.ts (para clases condicionales). Como son puros, son fáciles de probar y de importar en cualquier lado sin causar acoplamiento circular.
src/types – Tipado centralizado
Los types comunes, interfaces y tipos de tipos deberían guardarse en src/types. Ejemplo:
// src/types/user.ts
export interface User {
id: number;
name: string;
email: string;
}Centralizar los tipos facilita buscar contracts compartidos entre slices de estado, servicios y componentes.
Archivos estáticos – Assets, imágenes, etc.
El directorio public/ contiene assets estáticos que Vite sirve sin procesamiento (HTML5 boilerplate, íconos, imágenes). Para recursos dinámicos (imágenes generadas por el usuario, videos, etc.), podrías agregar un subdirectorio src/assets/ y servirlos a través de un routeo de imágenes.
Configurando TypeScript
Aunque Vite crea automáticamente un tsconfig.json, vale la pena entender los ajustes clave.
Configuración básica en tsconfig.json
Al inspeccionar el archivo generado, verás algo como lo siguiente:
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ES2020"],
"skipLibCheck": true,
"module": "ESNext",
"noEmit": true,
"jsx": "react-jsx",
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"declaration": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}Cada uno de estos valores ayuda a Vite a servir el código de forma eficiente, a producir declaraciones para el uso de tipos en tiempo de ejecución y a mantener la compilación estricta.
Tipos de archivo .tsx
React usa la sintaxis de JSX. En TypeScript, podés escribir archivos .tsx. El atributo jsx: "react-jsx" en tsconfig habilita el nuevo modo de fragmento automático (React 17+), reduciendo la necesidad de importar React en cada archivo. Ejemplo:
// src/components/ui/Button.tsx
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "primary" | "secondary";
}
export const Button = ({ variant = "primary", ...props }: ButtonProps) => (
<button className={`btn btn-${variant}`} {...props} />
);Agregar un archivo .eslintrc.cjs
Aunque Vite configura ESLint automáticamente cuando instalás eslint-config, podés crear un archivo .eslintrc.cjs para ajustes personalizados:
// .eslintrc.cjs
module.exports = {
root: true,
env: { browser: true, es2020: true },
plugins: ["@typescript-eslint"],
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
],
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
ecmaFeatures: { jsx: true },
},
settings: { react: { version: "detect" } },
rules: { "no-console": "warn" },
};Agregar un archivo .prettierrc
Prettier asegura un estilo consistente de formateo. Un archivo .prettierrc típicamente se ve así:
{
"singleQuote": true,
"trailingComma": "es5",
"semi": false,
"printWidth": 80
}Husky y commits limpios
Husky permite vincular scripts con el gestor de control de versiones. Para ejecutar ESLint y Prettier en cada commit, podés agregar un archivo .huskyrc (o mejor, un husky config en package.json). Un enfoque simple es:
{
"husky": {
"hooks": {
"pre-commit": "eslint --fix && prettier --write src/"
}
}
}Cuando instalás el paquete husky y corré npx husky install, se configuran los hooks.
Ejecutar el desarrollo y construir
Una vez que hayas editado los archivos, podés arrancar el servidor de desarrollo con:
npm run devEste comando ejecuta vite dev, que sirve tu aplicación en http://localhost:5173. El servidor también habilita hot-module-replacement (HMR), por lo que los cambios en componentes o CSS se reflejan instantáneamente sin recargar la página.
Para preparar el proyecto para producción, usás:
npm run buildVite compilará el código TypeScript a JavaScript optimizado, aplicará treeshaking y generará una carpeta dist/. La salida incluye un index.html y recursos estáticos con hashes, permitiéndote servir el paquete con cualquier servidor estático (por ejemplo, Nginx, Netlify, Vercel).
Mejores prácticas y errores comunes
- Evita archivos de componentes monolíticos. Cada archivo debería tener una única responsabilidad. Si un componente se vuelve grande, divide el archivo en subcomponentes.
- Usa importaciones absolutas. Agregar un alias
@envite.config.ts("@": "./src") evita rutas largas y hace que los cambios en la estructura de carpetas sean más simples. - Nunca importes React explícitamente en archivos .tsx. Con
jsx: "react-jsx", React ya está en el scope, reduciendo el bytecode innecesario. - Mantén los archivos
.tsxconcisos. Si necesitas muchas imports, considera mover la lógica a un hook separado o archivo de utils. - Haz que los tipos sean reexportados. En
src/types/index.ts, podés reexportar todos los types para que los consumidores puedan escribirfrom '@/types'en lugar defrom '@/types/user'. - Evita la compilación en
src/main.tsx. Ese archivo normalmente contiene soloReactDOM.createRoot(...).render(<App />). Mantenerlo limpio previene errores innecesarios. - Usa
clsxocvapara clases condicionales. En lugar de concatenar strings, una función utilitaria hace que la lógica de estilos sea más clara y evita errores de tipado. - Verifica los archivos de tipos generados. Cuando usas
tsc --noEmit, asegúrate de que no haya errores de tipo ocultos. - Configura CI para correr
npm run buildynpm run lint. Asegura que solo el código válido y formateado llegue a producción.
Conclusión
Ahora tenés un flujo de trabajo completo para crear un proyecto React moderno con Vite y TypeScript. Has explorado una estructura de carpetas ampliamente adoptada, has configurado TypeScript, has agregado linting y formateo automáticos, y sabes cómo ejecutar el servidor de desarrollo y compilar para producción.
Si seguís las mejores prácticas mencionadas (mantener componentes pequeños, usar importaciones absolutas, usar hooks personalizados, etc.), vas a tener un código base limpio y escalable desde el primer día.
El próximo paso podría ser agregar un sistema de manejo de estado global (Redux, Zustand, Jotai), definir routes con React Router, o desplegar la aplicación en un proveedor cloud como Netlify o Vercel. Cada adición construye sobre esta base sólida, permitiéndote crear aplicaciones React impresionantes y de alto rendimiento.
¡Feliz programación!
DUGLAS MORENO
Comentarios (0)
Sé el primero en comentar.