create-react-zr-architecture 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +279 -0
- package/bin/cli.js +198 -0
- package/package.json +45 -0
- package/template/_env +1 -0
- package/template/_env.example +1 -0
- package/template/_gitignore +35 -0
- package/template/create-src-files.sh +785 -0
- package/template/setup-template.sh +277 -0
- package/template/src/app/App.tsx +25 -0
- package/template/src/domain/entities/User.ts +8 -0
- package/template/src/domain/repositories/UserRepository.ts +11 -0
- package/template/src/domain/types/.gitkeep +0 -0
- package/template/src/domain/usecases/users/CreateUserUseCase.ts +15 -0
- package/template/src/domain/usecases/users/GetAllUsersUseCase.ts +10 -0
- package/template/src/infrastructure/api/apiClient.ts +73 -0
- package/template/src/infrastructure/config/.gitkeep +0 -0
- package/template/src/infrastructure/data/.gitkeep +0 -0
- package/template/src/infrastructure/repositories/UserRepositoryImpl.ts +32 -0
- package/template/src/infrastructure/services/.gitkeep +0 -0
- package/template/src/lib/utils.ts +6 -0
- package/template/src/main.tsx +10 -0
- package/template/src/presentation/assets/logos/.gitkeep +0 -0
- package/template/src/presentation/components/layouts/.gitkeep +0 -0
- package/template/src/presentation/components/shared/.gitkeep +0 -0
- package/template/src/presentation/components/tables/.gitkeep +0 -0
- package/template/src/presentation/context/auth/AuthContext.tsx +84 -0
- package/template/src/presentation/context/auth/useAuthContext.tsx +12 -0
- package/template/src/presentation/pages/Index.tsx +76 -0
- package/template/src/presentation/pages/auth/LoginPage.tsx +39 -0
- package/template/src/presentation/routes/config/.gitkeep +0 -0
- package/template/src/presentation/routes/guards/.gitkeep +0 -0
- package/template/src/presentation/utils/.gitkeep +0 -0
- package/template/src/presentation/viewmodels/hooks/.gitkeep +0 -0
- package/template/src/shared/config/env.ts +9 -0
- package/template/src/shared/constants/index.ts +29 -0
- package/template/src/shared/hooks/.gitkeep +0 -0
- package/template/src/shared/lib/.gitkeep +0 -0
- package/template/src/shared/types/index.ts +42 -0
- package/template/src/shared/utils/format.ts +30 -0
- package/template/src/shared/utils/validation.ts +22 -0
- package/template/src/styles/index.css +59 -0
- package/template/src/vite-env.d.ts +10 -0
package/README.md
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# π Create React Clean Architecture
|
|
2
|
+
|
|
3
|
+
Generador CLI para crear proyectos React con **Clean Architecture**, TypeScript, Vite, Tailwind CSS y shadcn/ui.
|
|
4
|
+
|
|
5
|
+
## β¨ CaracterΓsticas
|
|
6
|
+
|
|
7
|
+
- ποΈ **Clean Architecture** - SeparaciΓ³n clara de capas (Domain, Infrastructure, Presentation)
|
|
8
|
+
- β‘ **Vite** - Build tool ultra rΓ‘pido
|
|
9
|
+
- π¨ **Tailwind CSS + shadcn/ui** - Componentes modernos y estilizados
|
|
10
|
+
- π¦ **TypeScript** - Tipado estΓ‘tico
|
|
11
|
+
- π **TanStack Query** - Manejo de estado del servidor
|
|
12
|
+
- π» **Zustand** - State management simple
|
|
13
|
+
- π **React Hook Form + Zod** - Formularios con validaciΓ³n
|
|
14
|
+
- π **Axios** - Cliente HTTP
|
|
15
|
+
- π **Socket.io** - WebSockets listo para usar
|
|
16
|
+
- π£οΈ **React Router** - NavegaciΓ³n
|
|
17
|
+
|
|
18
|
+
## π¦ InstalaciΓ³n
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx create-react-clean-arch mi-proyecto
|
|
22
|
+
cd mi-proyecto
|
|
23
|
+
npm run dev
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## π Estructura del Proyecto
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
mi-proyecto/
|
|
30
|
+
βββ src/
|
|
31
|
+
β βββ app/ # ConfiguraciΓ³n de la aplicaciΓ³n
|
|
32
|
+
β β βββ App.tsx
|
|
33
|
+
β βββ domain/ # Capa de Dominio (LΓ³gica de Negocio)
|
|
34
|
+
β β βββ entities/ # Entidades del dominio
|
|
35
|
+
β β βββ repositories/ # Interfaces de repositorios
|
|
36
|
+
β β βββ usecases/ # Casos de uso
|
|
37
|
+
β β βββ types/ # Tipos del dominio
|
|
38
|
+
β βββ infrastructure/ # Capa de Infraestructura
|
|
39
|
+
β β βββ api/ # Cliente API
|
|
40
|
+
β β βββ config/ # Configuraciones
|
|
41
|
+
β β βββ data/ # Fuentes de datos
|
|
42
|
+
β β βββ repositories/ # Implementaciones de repositorios
|
|
43
|
+
β β βββ services/ # Servicios externos
|
|
44
|
+
β βββ presentation/ # Capa de PresentaciΓ³n (UI)
|
|
45
|
+
β β βββ components/ # Componentes React
|
|
46
|
+
β β β βββ layouts/
|
|
47
|
+
β β β βββ shared/
|
|
48
|
+
β β β βββ tables/
|
|
49
|
+
β β β βββ ui/ # Componentes shadcn/ui
|
|
50
|
+
β β βββ context/ # Context API
|
|
51
|
+
β β βββ pages/ # PΓ‘ginas
|
|
52
|
+
β β βββ routes/ # ConfiguraciΓ³n de rutas
|
|
53
|
+
β β βββ utils/ # Utilidades de UI
|
|
54
|
+
β β βββ viewmodels/ # ViewModels y hooks
|
|
55
|
+
β βββ shared/ # CΓ³digo compartido
|
|
56
|
+
β β βββ config/ # ConfiguraciΓ³n global
|
|
57
|
+
β β βββ constants/ # Constantes
|
|
58
|
+
β β βββ hooks/ # Hooks compartidos
|
|
59
|
+
β β βββ types/ # Tipos compartidos
|
|
60
|
+
β β βββ utils/ # Utilidades
|
|
61
|
+
β βββ lib/ # LibrerΓas y helpers
|
|
62
|
+
β βββ styles/ # Estilos globales
|
|
63
|
+
β βββ main.tsx # Punto de entrada
|
|
64
|
+
βββ .env # Variables de entorno
|
|
65
|
+
βββ tailwind.config.js # ConfiguraciΓ³n Tailwind
|
|
66
|
+
βββ tsconfig.json # ConfiguraciΓ³n TypeScript
|
|
67
|
+
βββ vite.config.ts # ConfiguraciΓ³n Vite
|
|
68
|
+
βββ package.json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## π― Clean Architecture
|
|
72
|
+
|
|
73
|
+
### Capas
|
|
74
|
+
|
|
75
|
+
1. **Domain (Dominio)**
|
|
76
|
+
- Contiene la lΓ³gica de negocio pura
|
|
77
|
+
- Independiente de frameworks y librerΓas
|
|
78
|
+
- Define entidades, interfaces y casos de uso
|
|
79
|
+
|
|
80
|
+
2. **Infrastructure (Infraestructura)**
|
|
81
|
+
- Implementaciones concretas de las interfaces del dominio
|
|
82
|
+
- ComunicaciΓ³n con APIs, bases de datos, servicios externos
|
|
83
|
+
- Manejo de datos y persistencia
|
|
84
|
+
|
|
85
|
+
3. **Presentation (PresentaciΓ³n)**
|
|
86
|
+
- Componentes de UI
|
|
87
|
+
- ViewModels y hooks
|
|
88
|
+
- Manejo de estado de la UI
|
|
89
|
+
|
|
90
|
+
4. **Shared (Compartido)**
|
|
91
|
+
- CΓ³digo reutilizable entre capas
|
|
92
|
+
- Utilidades, constantes, tipos comunes
|
|
93
|
+
|
|
94
|
+
### Flujo de Datos
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
UI (Presentation) β ViewModel β UseCase (Domain) β Repository Interface (Domain) β Repository Implementation (Infrastructure) β API
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## π οΈ Uso
|
|
101
|
+
|
|
102
|
+
### Agregar Componentes shadcn/ui
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npx shadcn-ui@latest add button
|
|
106
|
+
npx shadcn-ui@latest add card
|
|
107
|
+
npx shadcn-ui@latest add form
|
|
108
|
+
npx shadcn-ui@latest add table
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Crear una Entidad
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// src/domain/entities/Product.ts
|
|
115
|
+
import { BaseEntity } from '@/shared/types';
|
|
116
|
+
|
|
117
|
+
export interface Product extends BaseEntity {
|
|
118
|
+
name: string;
|
|
119
|
+
price: number;
|
|
120
|
+
description: string;
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Crear un Repositorio
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// src/domain/repositories/ProductRepository.ts
|
|
128
|
+
import { Product } from '@/domain/entities/Product';
|
|
129
|
+
|
|
130
|
+
export interface ProductRepository {
|
|
131
|
+
getAll(): Promise<Product[]>;
|
|
132
|
+
getById(id: string): Promise<Product>;
|
|
133
|
+
create(product: Omit<Product, 'id' | 'createdAt' | 'updatedAt'>): Promise<Product>;
|
|
134
|
+
update(id: string, product: Partial<Product>): Promise<Product>;
|
|
135
|
+
delete(id: string): Promise<void>;
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Implementar el Repositorio
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
// src/infrastructure/repositories/ProductRepositoryImpl.ts
|
|
143
|
+
import { ProductRepository } from '@/domain/repositories/ProductRepository';
|
|
144
|
+
import { Product } from '@/domain/entities/Product';
|
|
145
|
+
import { apiClient } from '@/infrastructure/api/apiClient';
|
|
146
|
+
|
|
147
|
+
export class ProductRepositoryImpl implements ProductRepository {
|
|
148
|
+
async getAll(): Promise<Product[]> {
|
|
149
|
+
return apiClient.get<Product[]>('/products');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async getById(id: string): Promise<Product> {
|
|
153
|
+
return apiClient.get<Product>(`/products/${id}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async create(product: Omit<Product, 'id' | 'createdAt' | 'updatedAt'>): Promise<Product> {
|
|
157
|
+
return apiClient.post<Product>('/products', product);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async update(id: string, product: Partial<Product>): Promise<Product> {
|
|
161
|
+
return apiClient.put<Product>(`/products/${id}`, product);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async delete(id: string): Promise<void> {
|
|
165
|
+
return apiClient.delete<void>(`/products/${id}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export const productRepository = new ProductRepositoryImpl();
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Crear un Caso de Uso
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// src/domain/usecases/products/GetAllProductsUseCase.ts
|
|
176
|
+
import { ProductRepository } from '@/domain/repositories/ProductRepository';
|
|
177
|
+
import { Product } from '@/domain/entities/Product';
|
|
178
|
+
|
|
179
|
+
export class GetAllProductsUseCase {
|
|
180
|
+
constructor(private productRepository: ProductRepository) {}
|
|
181
|
+
|
|
182
|
+
async execute(): Promise<Product[]> {
|
|
183
|
+
return this.productRepository.getAll();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Usar en un Componente con TanStack Query
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
// src/presentation/pages/ProductsPage.tsx
|
|
192
|
+
import { useQuery } from '@tanstack/react-query';
|
|
193
|
+
import { GetAllProductsUseCase } from '@/domain/usecases/products/GetAllProductsUseCase';
|
|
194
|
+
import { productRepository } from '@/infrastructure/repositories/ProductRepositoryImpl';
|
|
195
|
+
|
|
196
|
+
const getAllProductsUseCase = new GetAllProductsUseCase(productRepository);
|
|
197
|
+
|
|
198
|
+
export const ProductsPage = () => {
|
|
199
|
+
const { data: products, isLoading, error } = useQuery({
|
|
200
|
+
queryKey: ['products'],
|
|
201
|
+
queryFn: () => getAllProductsUseCase.execute(),
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
if (isLoading) return <div>Cargando...</div>;
|
|
205
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
206
|
+
|
|
207
|
+
return (
|
|
208
|
+
<div>
|
|
209
|
+
<h1>Productos</h1>
|
|
210
|
+
{products?.map((product) => (
|
|
211
|
+
<div key={product.id}>
|
|
212
|
+
<h2>{product.name}</h2>
|
|
213
|
+
<p>{product.description}</p>
|
|
214
|
+
<p>${product.price}</p>
|
|
215
|
+
</div>
|
|
216
|
+
))}
|
|
217
|
+
</div>
|
|
218
|
+
);
|
|
219
|
+
};
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## π§ Scripts Disponibles
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
npm run dev # Iniciar servidor de desarrollo
|
|
226
|
+
npm run build # Construir para producciΓ³n
|
|
227
|
+
npm run preview # Vista previa de la build
|
|
228
|
+
npm run lint # Ejecutar linter
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## π Variables de Entorno
|
|
232
|
+
|
|
233
|
+
```env
|
|
234
|
+
VITE_API_URL=http://localhost:3000/api
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## π LibrerΓas Incluidas
|
|
238
|
+
|
|
239
|
+
| LibrerΓa | VersiΓ³n | PropΓ³sito |
|
|
240
|
+
|----------|---------|-----------|
|
|
241
|
+
| React | ^18.3.1 | Framework UI |
|
|
242
|
+
| TypeScript | ^5.6.2 | Tipado estΓ‘tico |
|
|
243
|
+
| Vite | ^5.4.8 | Build tool |
|
|
244
|
+
| Tailwind CSS | ^3.4.13 | Estilos |
|
|
245
|
+
| React Router | ^6.26.2 | NavegaciΓ³n |
|
|
246
|
+
| TanStack Query | ^5.56.2 | State management del servidor |
|
|
247
|
+
| Zustand | ^4.5.5 | State management |
|
|
248
|
+
| React Hook Form | ^7.53.0 | Formularios |
|
|
249
|
+
| Zod | ^3.23.8 | ValidaciΓ³n de esquemas |
|
|
250
|
+
| Axios | ^1.7.7 | Cliente HTTP |
|
|
251
|
+
| Socket.io Client | ^4.8.0 | WebSockets |
|
|
252
|
+
| Lucide React | ^0.446.0 | Iconos |
|
|
253
|
+
|
|
254
|
+
## π€ Contribuir
|
|
255
|
+
|
|
256
|
+
Las contribuciones son bienvenidas. Por favor:
|
|
257
|
+
|
|
258
|
+
1. Fork el proyecto
|
|
259
|
+
2. Crea una rama para tu feature (`git checkout -b feature/AmazingFeature`)
|
|
260
|
+
3. Commit tus cambios (`git commit -m 'Add some AmazingFeature'`)
|
|
261
|
+
4. Push a la rama (`git push origin feature/AmazingFeature`)
|
|
262
|
+
5. Abre un Pull Request
|
|
263
|
+
|
|
264
|
+
## π Licencia
|
|
265
|
+
|
|
266
|
+
MIT Β© Diego Aguilera
|
|
267
|
+
|
|
268
|
+
## π Enlaces
|
|
269
|
+
|
|
270
|
+
- [Repositorio](https://github.com/diegoAguilera02/create-react-clean-arch)
|
|
271
|
+
- [Issues](https://github.com/diegoAguilera02/create-react-clean-arch/issues)
|
|
272
|
+
- [shadcn/ui](https://ui.shadcn.com/)
|
|
273
|
+
- [Vite](https://vitejs.dev/)
|
|
274
|
+
- [TanStack Query](https://tanstack.com/query/latest)
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
Creado con β€οΈ usando Clean Architecture
|
|
279
|
+
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
import fs from 'fs-extra';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
|
|
13
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
14
|
+
// Argumentos
|
|
15
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
16
|
+
const args = process.argv.slice(2);
|
|
17
|
+
const projectName = args[0];
|
|
18
|
+
|
|
19
|
+
if (!projectName) {
|
|
20
|
+
console.log(chalk.red('β Error: Debes proporcionar un nombre para el proyecto'));
|
|
21
|
+
console.log(chalk.cyan('\nUso: npx create-react-clean-arch mi-proyecto'));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
26
|
+
// Detectar package manager
|
|
27
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
28
|
+
function detectPackageManager() {
|
|
29
|
+
const userAgent = process.env.npm_config_user_agent || '';
|
|
30
|
+
if (userAgent.includes('pnpm')) return 'pnpm';
|
|
31
|
+
if (userAgent.includes('yarn')) return 'yarn';
|
|
32
|
+
return 'npm';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const pkgManager = detectPackageManager();
|
|
36
|
+
|
|
37
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
38
|
+
// Funciones auxiliares
|
|
39
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
40
|
+
function runCommand(command, cwd = process.cwd()) {
|
|
41
|
+
try {
|
|
42
|
+
execSync(command, { cwd, stdio: 'inherit', shell: true });
|
|
43
|
+
return true;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Manejar Ctrl+C correctamente
|
|
50
|
+
process.on('SIGINT', () => {
|
|
51
|
+
console.log('\n\nπ Proceso cancelado por el usuario');
|
|
52
|
+
process.exit(0);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
56
|
+
// Main
|
|
57
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
58
|
+
async function main() {
|
|
59
|
+
console.log(chalk.bold.cyan('\nπ Create React Clean Architecture\n'));
|
|
60
|
+
|
|
61
|
+
const projectPath = path.join(process.cwd(), projectName);
|
|
62
|
+
|
|
63
|
+
// Verificar si el directorio ya existe
|
|
64
|
+
if (fs.existsSync(projectPath)) {
|
|
65
|
+
console.log(chalk.red(`β Error: El directorio "${projectName}" ya existe`));
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
70
|
+
// 1. Crear proyecto base con Vite
|
|
71
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
72
|
+
const spinnerVite = ora('Creando proyecto base con Vite...').start();
|
|
73
|
+
|
|
74
|
+
const createCommand = pkgManager === 'pnpm'
|
|
75
|
+
? `pnpm create vite@latest ${projectName} -- --template react-ts`
|
|
76
|
+
: pkgManager === 'yarn'
|
|
77
|
+
? `yarn create vite ${projectName} --template react-ts`
|
|
78
|
+
: `npm create vite@latest ${projectName} -- --template react-ts`;
|
|
79
|
+
|
|
80
|
+
const viteSuccess = runCommand(createCommand);
|
|
81
|
+
|
|
82
|
+
if (!viteSuccess) {
|
|
83
|
+
spinnerVite.fail('Error al crear proyecto base');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
spinnerVite.succeed('Proyecto base creado');
|
|
88
|
+
|
|
89
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
90
|
+
// 2. Aplicar template Clean Architecture
|
|
91
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
92
|
+
const spinnerTemplate = ora('Aplicando template Clean Architecture...').start();
|
|
93
|
+
|
|
94
|
+
const templatePath = path.join(__dirname, '../template');
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
// Copiar todos los archivos del template
|
|
98
|
+
fs.copySync(templatePath, projectPath, {
|
|
99
|
+
overwrite: true,
|
|
100
|
+
filter: (src) => {
|
|
101
|
+
// No copiar node_modules si existe
|
|
102
|
+
return !src.includes('node_modules');
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Renombrar archivos con _ prefix
|
|
107
|
+
const filesToRename = [
|
|
108
|
+
{ from: '_package.json', to: 'package.json' },
|
|
109
|
+
{ from: '_gitignore', to: '.gitignore' },
|
|
110
|
+
{ from: '_env', to: '.env' },
|
|
111
|
+
{ from: '_env.example', to: '.env.example' },
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
filesToRename.forEach(({ from, to }) => {
|
|
115
|
+
const fromPath = path.join(projectPath, from);
|
|
116
|
+
const toPath = path.join(projectPath, to);
|
|
117
|
+
|
|
118
|
+
if (fs.existsSync(fromPath)) {
|
|
119
|
+
fs.moveSync(fromPath, toPath, { overwrite: true });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Reemplazar {{name}} en package.json
|
|
124
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
125
|
+
let packageJson = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
126
|
+
packageJson = packageJson.replace(/{{name}}/g, projectName);
|
|
127
|
+
fs.writeFileSync(packageJsonPath, packageJson);
|
|
128
|
+
|
|
129
|
+
spinnerTemplate.succeed('Template aplicado exitosamente');
|
|
130
|
+
} catch (error) {
|
|
131
|
+
spinnerTemplate.fail('Error al aplicar template');
|
|
132
|
+
console.error(error);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
137
|
+
// 3. Instalar dependencias
|
|
138
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
139
|
+
const spinnerDeps = ora(`Instalando dependencias con ${pkgManager}...`).start();
|
|
140
|
+
|
|
141
|
+
const installCommand = pkgManager === 'pnpm'
|
|
142
|
+
? 'pnpm install --shamefully-hoist'
|
|
143
|
+
: pkgManager === 'yarn'
|
|
144
|
+
? 'yarn'
|
|
145
|
+
: 'npm install';
|
|
146
|
+
|
|
147
|
+
const installSuccess = runCommand(installCommand, projectPath);
|
|
148
|
+
|
|
149
|
+
if (!installSuccess) {
|
|
150
|
+
spinnerDeps.fail('Error al instalar dependencias');
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
spinnerDeps.succeed('Dependencias instaladas');
|
|
155
|
+
|
|
156
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
157
|
+
// 4. Inicializar git
|
|
158
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
159
|
+
const spinnerGit = ora('Inicializando repositorio git...').start();
|
|
160
|
+
|
|
161
|
+
runCommand('git init', projectPath);
|
|
162
|
+
runCommand('git add -A', projectPath);
|
|
163
|
+
runCommand('git commit -m "Initial commit from create-react-clean-arch"', projectPath);
|
|
164
|
+
|
|
165
|
+
spinnerGit.succeed('Repositorio git inicializado');
|
|
166
|
+
|
|
167
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
168
|
+
// 5. Mensaje final
|
|
169
|
+
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
170
|
+
console.log(chalk.bold.green('\n⨠‘Proyecto creado exitosamente!\n'));
|
|
171
|
+
|
|
172
|
+
console.log(chalk.cyan('Estructura Clean Architecture:'));
|
|
173
|
+
console.log(' β
domain/ (entities, repositories, usecases)');
|
|
174
|
+
console.log(' β
infrastructure/ (api, repositories, services)');
|
|
175
|
+
console.log(' β
presentation/ (components, pages, viewmodels)');
|
|
176
|
+
console.log(' β
shared/ (hooks, utils, types)\n');
|
|
177
|
+
|
|
178
|
+
console.log(chalk.cyan('LibrerΓas instaladas:'));
|
|
179
|
+
console.log(' β
React Router DOM');
|
|
180
|
+
console.log(' β
TanStack Query');
|
|
181
|
+
console.log(' β
Zustand');
|
|
182
|
+
console.log(' β
React Hook Form + Zod');
|
|
183
|
+
console.log(' β
Tailwind CSS + shadcn/ui');
|
|
184
|
+
console.log(' β
Axios + Socket.io\n');
|
|
185
|
+
|
|
186
|
+
console.log(chalk.cyan('π― PrΓ³ximos pasos:\n'));
|
|
187
|
+
console.log(chalk.white(` cd ${projectName}`));
|
|
188
|
+
const devCommand = pkgManager === 'npm' ? 'npm run dev' : `${pkgManager} dev`;
|
|
189
|
+
console.log(chalk.white(` ${devCommand}\n`));
|
|
190
|
+
console.log(chalk.yellow('π‘ Agregar componentes shadcn:\n'));
|
|
191
|
+
console.log(chalk.white(` npx shadcn-ui@latest add button`));
|
|
192
|
+
console.log(chalk.white(` npx shadcn-ui@latest add card form table\n`));
|
|
193
|
+
|
|
194
|
+
console.log(chalk.gray('DocumentaciΓ³n completa en README.md'));
|
|
195
|
+
console.log(chalk.gray('Creado con Aura...'));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
main().catch(console.error);
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-react-zr-architecture",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Create React applications with Clean Architecture, TypeScript, Vite, Tailwind CSS, and shadcn/ui",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-react-zr-architecture": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"template"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"test": "node bin/cli.js test-project"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react",
|
|
18
|
+
"clean-architecture",
|
|
19
|
+
"vite",
|
|
20
|
+
"typescript",
|
|
21
|
+
"tailwindcss",
|
|
22
|
+
"shadcn-ui",
|
|
23
|
+
"template",
|
|
24
|
+
"boilerplate",
|
|
25
|
+
"starter"
|
|
26
|
+
],
|
|
27
|
+
"author": "Diego Aguilera",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/diegoAguilera02/create-react-zr-architecture"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/diegoAguilera02/create-react-zr-architecture/issues"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/diegoAguilera02/create-react-zr-architecture#readme",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18.0.0"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"fs-extra": "^11.2.0",
|
|
42
|
+
"chalk": "^5.3.0",
|
|
43
|
+
"ora": "^8.0.1"
|
|
44
|
+
}
|
|
45
|
+
}
|
package/template/_env
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VITE_API_URL=http://localhost:3000/api
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VITE_API_URL=http://localhost:3000/api
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
pnpm-debug.log*
|
|
8
|
+
lerna-debug.log*
|
|
9
|
+
|
|
10
|
+
node_modules
|
|
11
|
+
dist
|
|
12
|
+
dist-ssr
|
|
13
|
+
*.local
|
|
14
|
+
|
|
15
|
+
# Editor directories and files
|
|
16
|
+
.vscode/*
|
|
17
|
+
!.vscode/extensions.json
|
|
18
|
+
.idea
|
|
19
|
+
.DS_Store
|
|
20
|
+
*.suo
|
|
21
|
+
*.ntvs*
|
|
22
|
+
*.njsproj
|
|
23
|
+
*.sln
|
|
24
|
+
*.sw?
|
|
25
|
+
|
|
26
|
+
# Environment
|
|
27
|
+
.env.local
|
|
28
|
+
.env.development.local
|
|
29
|
+
.env.test.local
|
|
30
|
+
.env.production.local
|
|
31
|
+
|
|
32
|
+
# Database
|
|
33
|
+
*.db
|
|
34
|
+
*.sqlite
|
|
35
|
+
*.sqlite3
|