Skip to content

🗂️ Estructura de un proyecto Angular

Qué es cada archivo/carpeta que genera ng new. Se irá completando por clase.

📦 package.json — el "carnet de identidad" del proyecto

Es el archivo central de cualquier proyecto de Node (no solo Angular). Define el nombre, la versión, los scripts (atajos de comandos) y las dependencias.

jsonc
{
  "name": "27june",       // nombre del proyecto (el que pusiste en `ng new`)
  "version": "0.0.0",     // versión de TU app (empieza en 0.0.0)
  "scripts": { ... },     // atajos de comandos que ejecutas con "npm run ..."
  "prettier": { ... }     // config de formateo de código (opcional)
}

🔢 Versionado semántico (SemVer) — el campo version

La versión no es un número cualquiera: sigue el estándar SemVer con el formato MAJOR.MINOR.PATCH (mayor.menor.parche).

  2  .  3  .  1
  │     │     │
  │     │     └── PATCH → arreglos de bugs (no cambia cómo se usa)
  │     └──────── MINOR → nuevas funciones COMPATIBLES (no rompe nada anterior)
  └────────────── MAJOR → cambios que ROMPEN compatibilidad (breaking changes)
Subes...CuándoEjemplo
PATCH (x.x.+1)Corriges un bug sin cambiar el funcionamiento.2.0.02.0.1
MINOR (x.+1.0)Añades una función nueva sin romper lo existente.2.0.12.1.0
MAJOR (+1.0.0)Haces un cambio que rompe compatibilidad.2.1.03.0.0

💡 Al subir un nivel, los de la derecha vuelven a 0: subir MINOR pone PATCH en 0 (2.3.42.4.0); subir MAJOR pone MINOR y PATCH en 0 (2.4.03.0.0).

💡 Un proyecto recién creado empieza en 0.0.0 (aún no publicado/estable). El profe lo cambió a 2.0.0 solo para mostrar cómo se maneja el campo.

🧪 Tip de entrevista: "¿Qué significa SemVer?" → MAJOR.MINOR.PATCH: MAJOR rompe compatibilidad, MINOR añade sin romper, PATCH arregla bugs.

🏃 scripts — atajos de comandos

Los scripts son alias: en vez de escribir el comando largo, ejecutas npm run <nombre>. Angular crea estos por defecto:

ScriptComando realCómo se ejecutaQué hace
ngngnpm run ngAcceso directo al CLI dentro del proyecto.
startng servenpm startLevanta el servidor de desarrollo (la app en el navegador, con recarga automática).
buildng buildnpm run buildCompila la app para producción (carpeta dist/).
watchng build --watch --configuration developmentnpm run watchCompila y recompila cada vez que cambias un archivo.
testng testnpm testEjecuta las pruebas (Jasmine + Karma).

💡 start y test son especiales: se pueden lanzar sin runnpm start y npm test. Los demás sí necesitan runnpm run build, npm run watch.

💡 El más usado en el día a día es npm start (= ng serve): arranca tu app en http://localhost:4200 y se recarga sola al guardar cambios.

🔍 Cómo leer la salida de npm start (ng serve)

Al ejecutar npm run start verás algo así:

> 27june@2.0.0 start          ← qué proyecto y script se está corriendo
> ng serve                    ← el comando real que ejecuta el script

| Initial total | 47.85 kB    ← peso total inicial de tu app (lo que carga el navegador)
Application bundle generation complete. [2.066 seconds]   ← compiló en 2 seg
Watch mode enabled. Watching for file changes...          ← vigila cambios y recompila
  → Local:  http://localhost:4200/   ← AQUÍ ves tu app en el navegador
  → press h + enter to show help
  • Initial total = cuánto "pesa" tu app al cargar. Cuanto más pequeño, más rápido carga. Recién creada es muy ligera (~48 kB).
  • Watch mode enabled = se queda corriendo y recompila solo cuando guardas.
  • Local: http://localhost:4200/ = la dirección donde abrir tu app. 4200 es el puerto por defecto de Angular.
  • Para detener el servidor: Ctrl + C en la terminal.

💡 Mientras ng serve esté corriendo, la terminal queda "ocupada". Guarda un cambio en el código y la página del navegador se refresca sola (live reload).

🔍 Los scripts en detalle

ng serve (start) vs ng build (build) — la diferencia más importante:

ng serveng build
Para quéDesarrollar: ver la app mientras programas.Publicar: generar la app final.
¿Crea archivos?No, la sirve en memoria.Sí, genera la carpeta dist/.
ServidorSí, en http://localhost:4200.No, solo deja los archivos listos.
Recarga al guardarSí (live reload).No.

La línea watch por partes: ng build --watch --configuration development

  • ng build → compila la app.
  • --watch → se queda vigilando y recompila cada vez que cambias un archivo (no tienes que volver a lanzarlo a mano).
  • --configuration development → usa la config de desarrollo (compila más rápido y sin optimizar tanto; por defecto ng build usa production).

💡 ¿watch o serve? Para programar normalmente usas serve (te da el servidor + recarga). watch sirve cuando necesitas los archivos en dist/ regenerándose solos (p. ej. otra herramienta consume ese dist/).

🌍 Scripts personalizados por entorno (dev · QA · prod)

Los scripts que trae Angular son solo los básicos: puedes añadir los tuyos. Lo típico es tener un script de compilación por cada entorno (desarrollo, QA, producción), cada uno apuntando a una --configuration distinta.

jsonc
"scripts": {
  "start": "ng serve",
  "build": "ng build",
  "build:dev": "ng build --configuration development",
  "build:qa":  "ng build --configuration qa",
  "build:prod": "ng build --configuration production"
}

Y los ejecutas así:

bash
npm run build:qa     # compila usando la configuración "qa"
npm run build:prod   # compila para producción

📌 ¿De dónde salen esas "configuraciones"? Se definen en angular.json, en la sección configurations (ahí pones, p. ej., qué URL de API usar en dev, qa o prod, y qué optimizaciones aplicar). El script solo dice cuál usar con --configuration.

💡 Entornos típicos:

  • development (dev) → mientras programas (rápido, sin optimizar, con datos de prueba).
  • QA / staging → para que el equipo de pruebas valide, simulando producción.
  • production (prod) → la versión final optimizada para los usuarios reales.

🎨 prettier — formateo automático del código

Prettier es una herramienta que da formato al código automáticamente (sangría, comillas, longitud de línea…) para que se vea consistente. Aquí va su config:

jsonc
"prettier": {
  "printWidth": 100,        // máximo 100 caracteres por línea
  "singleQuote": true,      // usa comillas simples '' en vez de dobles ""
  "overrides": [
    {
      "files": "*.html",    // para los archivos HTML...
      "options": { "parser": "angular" }  // ...usa el parser de Angular
    }
  ]
}

💡 Que esté dentro del package.json es solo una de las formas de configurar Prettier; también puede ir en un archivo aparte (.prettierrc).

📚 dependencies vs devDependencies

Son las dos listas de paquetes que tu proyecto necesita. La diferencia es cuándo se necesitan:

dependenciesdevDependencies
¿Cuándo se usan?En producción (la app las necesita para funcionar).Solo en desarrollo (programar, compilar, testear).
¿Van al usuario final?Sí, forman parte de la app.No, no se incluyen en el build de producción.
Ejemplos en Angular@angular/core, @angular/router, rxjs.@angular/cli, @angular/build, karma, jasmine, typescript.
Cómo instalar unanpm install <paquete>npm install -D <paquete> (-D = dev).

💡 Regla mental: si la app la necesita funcionandodependencies. Si solo la necesitas tú para construir/probardevDependencies.

🔧 Qué son los devDependencies que trae Angular

PaquetePara qué
@angular/cliLa herramienta ng (generar, servir, compilar).
@angular/buildEl motor que compila la app.
@angular/compiler-cliCompilador de Angular (procesa plantillas/componentes).
typescriptEl compilador de TypeScript.
jasmine-core, @types/jasmineFramework para escribir pruebas.
karma + karma-*Ejecutor que corre las pruebas en un navegador.

💡 Casi todo lo de testing (jasmine, karma) y de compilación va en devDependencies: el usuario final no necesita esas herramientas, solo tú.

🔣 Los símbolos ^ y ~ en las versiones (rangos SemVer)

Antes de una versión verás ^ o ~. Indican hasta qué actualizaciones automáticas se permiten al hacer npm install (recuerda SemVer = MAJOR.MINOR.PATCH):

SímboloPermite actualizar...Ejemplo ~/^4.2.3 acepta
^ (caret)MINOR y PATCH (no cambia MAJOR).4.2.3 → hasta < 5.0.0 (p. ej. 4.9.1)
~ (tilde)solo PATCH (no cambia MINOR ni MAJOR).4.2.3 → hasta < 4.3.0 (p. ej. 4.2.9)
(sin símbolo)nada: versión exacta y fija.solo 4.2.3
  • ^ es más permisivo (acepta más actualizaciones) → es el que pone npm por defecto.
  • ~ es más estricto (solo parches/bugfixes) → más seguro/conservador.

🧪 Tip de entrevista: "¿Diferencia entre ^ y ~?" → ^ permite subir MINOR+PATCH; ~ solo PATCH. Ninguno sube MAJOR (eso rompería compatibilidad).

📐 Ejemplo real (los del profe): ^22.0 y ~6.0

"^22.0"   → acepta de 22.0.0 hasta < 23.0.0   (sube MINOR y PATCH: 22.1, 22.5.3…)
"~6.0"    → acepta de 6.0.0  hasta < 6.1.0    (sube SOLO PATCH: 6.0.1, 6.0.9…)
  • Con ^22.0 podrías terminar en 22.9.x, pero nunca en 23.x (eso sería un cambio MAJOR que rompe compatibilidad).
  • Con ~6.0 te quedas dentro de 6.0.x: solo entran parches (arreglos de bugs).

💡 Truco para recordar: el caret ^ "apunta hacia arriba" → deja subir más (MINOR). La tilde ~ es más "plana/pegada" → casi no deja subir (solo PATCH).

🖼️ Gráfico: hasta dónde llega cada símbolo

                    MAJOR . MINOR . PATCH
                      │       │       │
        ┌─────────────┘       │       └──────────────┐
        │                     │                      │
        ▼                     ▼                      ▼
   ❌ NADIE sube          ^ caret SÍ            ^ y ~ SÍ
   (rompería todo)        ~ tilde NO            (ambos)


  ^22.0   ✅ MINOR + PATCH
  ──────────────────────────────────────────────────────
   22.0.0   22.1.0   22.5.3   22.9.9  │  23.0.0
   [✅══════════✅════════✅═══════✅═)  │  ❌ (nuevo MAJOR)
   └──────────── permitido ───────────┘  └─ bloqueado


  ~6.0    ✅ solo PATCH
  ──────────────────────────────────────────────────────
   6.0.0   6.0.1   6.0.9  │  6.1.0
   [✅══════✅══════✅═)    │  ❌ (nuevo MINOR)
   └──── permitido ────┘    └─ bloqueado

📊 En una frase: ^ abre la puerta a más versiones (todo el MAJOR actual); ~ la deja casi cerrada (solo el MINOR actual). Ninguno cruza al siguiente MAJOR.

🅰️ angular.json — el "panel de control" del proyecto

Es el archivo de configuración principal de Angular. Aquí el CLI (ng) lee cómo construir, servir y testear tu app: rutas de archivos, estilos, presupuestos de tamaño, optimizaciones, etc. Cuando ejecutas ng build o ng serve, el CLI viene a leer aquí.

💡 Si package.json dice qué librerías usa el proyecto, angular.json dice cómo se compila y ejecuta ese proyecto.

🧱 Estructura general (simplificada)

jsonc
{
  "projects": {
    "27june": {                  // tu proyecto (puede haber varios en un workspace)
      "architect": {             // las "tareas" que sabe hacer el CLI
        "build": {  ... },       // configura `ng build`
        "serve": {  ... },       // configura `ng serve`
        "test":  {  ... }        // configura `ng test`
      }
    }
  }
}

⚙️ configurations — los entornos (¡por defecto vienen 2!)

Dentro de build está configurations, donde se definen los entornos. Angular crea dos por defecto:

jsonc
"configurations": {
  "production":  { ... },   // entorno de PRODUCCIÓN (optimizado para usuarios reales)
  "development": { ... }    // entorno de DESARROLLO (rápido, para programar)
}
ConfiguraciónPara quéQué suele activar
productionLa versión final para usuarios reales.Optimización, minificación, sin sourcemaps → archivos pequeños y rápidos.
developmentMientras programas.Sin optimizar, con sourcemaps → compila rápido y es fácil de depurar.
  • Estas son las que eliges con el flag --configuration: ng build --configuration production.
  • Aquí es donde añadirías una "qa" si quieres ese entorno (recuerda el script build:qa de más arriba): primero la defines en este configurations, y luego el script la usa con --configuration qa.

💡 defaultConfiguration: suele estar puesto en production, así un ng build "a secas" ya compila para producción.

🧪 Tip de entrevista: "¿Dónde se configuran los entornos en Angular?" → en angular.json, dentro de configurations (por defecto production y development).

📁 Carpetas del proyecto (vista general)

Carpeta / archivoPara qué
.angular/Caché interna del CLI (acelera compilaciones). No se toca.
.vscode/Configuración del editor VS Code para este proyecto.
node_modules/Todas las dependencias instaladas. No se sube al repo (va en .gitignore).
public/Archivos estáticos públicos (imágenes, favicon, fuentes…). Desde Angular 18.
src/El código de tu app (aquí trabajas el 99% del tiempo).
package.json / angular.json / tsconfig.*Configuración (vistos arriba).

📂 public/ — los assets públicos (desde Angular 18)

Carpeta para tus archivos estáticos: imágenes, iconos, fuentes, favicon… Lo que pongas aquí se sirve tal cual, accesible públicamente en el proyecto.

📌 Cambio de versión: antes (Angular ≤17) se usaba una carpeta assets/ para esto. Desde Angular 18 el framework habilita public/ en su lugar. Si necesitas mostrar una imagen en tu app, la pones aquí.

📦 node_modules/ — donde viven las dependencias

Aquí npm guarda todas las dependencias del proyecto (las que listaste en package.json). Se llena al ejecutar npm install.

😅 El meme: "node_modules es el objeto más pesado del universo". Crece muchísimo porque cada dependencia trae a su vez sus propias dependencias (y así en cadena).

⚠️ Nunca se sube al repositorio (va en .gitignore). No hace falta: con el package.json + package-lock.json, cualquiera lo regenera con npm install.

🌳 La carpeta src/ (el corazón de la app)

src/
├── app/              ← tus COMPONENTES y lógica (aquí construyes la app)
│   ├── app.ts        ← componente raíz (la clase App)
│   └── app.config.ts ← configuración de la app (providers, rutas…)
├── index.html        ← el ÚNICO .html real que sirve el navegador
├── main.ts           ← punto de ARRANQUE de la app
└── styles.scss       ← estilos GLOBALES (afectan a toda la app)

🎨 styles.scss — estilos globales

Estilos que aplican a toda la app (a diferencia de los estilos de cada componente, que solo afectan a ese componente). Trae un comentario: "You can add global styles to this file…". Aquí pones, p. ej., la tipografía o colores base de todo el sitio.

🚀 main.ts — el punto de arranque (bootstrap)

Es el primer archivo que se ejecuta. Su trabajo es arrancar ("bootstrap") la app cargando el componente raíz. En Angular moderno (standalone, v17+) se ve así:

ts
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { App } from './app/app';

bootstrapApplication(App, appConfig)        // arranca la app con el componente raíz "App"
  .catch((err) => console.error(err));      // si falla el arranque, muestra el error
  • bootstrapApplication(App, appConfig) = "inicia Angular usando App como componente raíz y appConfig como configuración".
  • App viene de ./app/app → es el componente principal.
  • appConfig viene de ./app/app.config → ahí van los providers, rutas, etc.

💡 Cadena de arranque: el navegador abre index.html → este carga main.tsmain.ts hace bootstrap del componente App → la app aparece en pantalla.

🧩 Los archivos del componente raíz (app.ts y app.config.ts)

En Angular moderno el componente raíz vive en la carpeta app/:

ArchivoQué es
app.tsEl componente raíz (la clase App, decorada con @Component). Es el "cascarón" donde vive toda la app.
app.config.tsLa configuración de la aplicación: providers, router, HttpClient, etc. (lo que antes iba en el AppModule).

📝 Ojo (nombres nuevos): en Angular reciente el componente raíz es App en app.ts. En cursos/proyectos antiguos lo verás como AppComponent en app.component.ts y con un app.module.ts (sistema de NgModules). Es lo mismo conceptualmente, con nombres distintos.

🔗 <app-root> — cómo se conecta TODO

El archivo index.html es la única página HTML real. Dentro tiene una etiqueta rara que tú no creaste:

html
<body>
  <app-root></app-root>   <!-- aquí Angular "inyecta" toda tu app -->
</body>

<app-root> es un hueco vacío. Angular lo busca y mete dentro tu componente raíz. ¿Cómo sabe que ahí va App? Porque el componente App (en app.ts) declara ese nombre en su selector:

ts
// app.ts
@Component({
  selector: 'app-root',   // 👈 coincide con <app-root> del index.html
  ...
})
export class App { }

🧠 La cadena completa (de principio a fin)

1. index.html          →  el navegador abre esta página
   <app-root></app-root>   (un hueco vacío esperando)

2. main.ts             →  bootstrapApplication(App, appConfig)
        │                  "arranca Angular con el componente App"

3. app.ts (App)        →  su selector es 'app-root'
        │                  → Angular RELLENA el <app-root> con la vista de App

4. app.config.ts       →  appConfig le da la configuración (rutas, providers…)

   🎉 La app aparece dentro del <app-root> en el navegador

💡 Resumen mental: index.html pone el hueco (<app-root>), main.ts da la orden de arranque, app.ts es el contenido que rellena el hueco, y app.config.ts son los ajustes. Si cambias el selector en app.ts, tendrías que cambiar también la etiqueta en index.html (deben coincidir).

🧪 Tip de entrevista: "¿Qué es <app-root>?" → el selector del componente raíz; el punto del index.html donde Angular monta la aplicación.

🗺️ Diagrama: cómo se relacionan los 4 archivos

                          ┌───────────────────────────────┐
   ① El navegador abre →  │          index.html           │
                          │                               │
                          │   <body>                      │
                          │     <app-root></app-root> ◄───┼──┐  hueco vacío
                          │   </body>                     │  │
                          │   <script src="main.ts">      │  │
                          └──────────────┬────────────────┘  │
                                         │ ② carga y ejecuta  │
                                         ▼                    │
                          ┌───────────────────────────────┐  │
                          │            main.ts            │  │
                          │                               │  │
                          │  bootstrapApplication(        │  │
                          │       App,        ───────────┐│  │
                          │       appConfig   ──────────┐││  │
                          │  )                          │││  │
                          └─────────────────────────────┼┼┼──┘
                            ③ arranca con App y config  │││
                          ┌──────────────────┐  ┌───────▼▼┴────────┐
                          │  app.config.ts   │  │      app.ts      │
                          │                  │  │                  │
                          │  export const    │  │  @Component({    │
                          │   appConfig = {  │  │   selector:      │
                          │   providers: [   │  │   'app-root' ────┼──► coincide
                          │     router,      │  │   template: ...  │     con
                          │     httpClient   │  │  })              │  <app-root>
                          │   ]              │  │  class App { }   │
                          │  }               │  │                  │
                          └────────┬─────────┘  └────────┬─────────┘
                                   │                     │
                                   └──────────┬──────────┘

                                  🎉 Angular rellena el <app-root>
                                     del index.html con la vista de App

Lectura del diagrama (paso a paso):

  1. index.html se abre en el navegador. Tiene el hueco <app-root> y carga main.ts.
  2. main.ts ejecuta bootstrapApplication(App, appConfig) → la orden de arranque.
  3. Recibe dos cosas: App (el componente raíz) y appConfig (la configuración).
  4. app.ts define App con selector: 'app-root' → por eso Angular sabe dónde ponerlo (en el <app-root> del paso 1).
  5. app.config.ts aporta los providers (router, HttpClient…) que la app necesita.
  6. Resultado: Angular rellena el <app-root> con la vista de App. ✨

🔑 Las 2 conexiones que NO se ven a simple vista:

  • main.ts importa App y appConfig (de los otros dos archivos).
  • El selector de app.ts debe ser igual a la etiqueta de index.html.

app.config.ts en detalle (archivo "vital")

El profe lo marcó como sumamente importante: es donde se registra lo que la app necesita a nivel global (router, manejo de errores, tipo de reactividad…). Todo eso vive en un array llamado providers.

ts
import { ApplicationConfig, provideBrowserGlobalErrorListeners,
         provideZonelessChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideBrowserGlobalErrorListeners(),   // captura errores globales del navegador
    provideZonelessChangeDetection(),       // activa el modo ZONELESS (sin Zone.js)
    provideRouter(routes)                   // activa el enrutador con tus rutas
  ]
};
ElementoQué hace
ApplicationConfigEl tipo TypeScript de este objeto de configuración.
providers: [...]La lista de servicios/funcionalidades globales que se activan al arrancar.
provideBrowserGlobalErrorListeners()Engancha escuchadores de errores globales del navegador.
provideZonelessChangeDetection()🔥 Activa el modo zoneless (detección de cambios sin Zone.js, basada en Signals). → ver 02-Conceptos.md.
provideRouter(routes)Activa el enrutador (navegación entre páginas) usando las rutas de app.routes.ts.

🔥 ¡Conexión con la teoría! provideZonelessChangeDetection() es exactamente el modo zoneless que el profe dibujó (Zone.js vs zoneless). Aquí se ve activado de verdad en tu proyecto → tu app ya usa la reactividad moderna con Signals.

💡 provide...() = "activar/registrar algo". Cada función provide* enciende una funcionalidad. Cuando más adelante uses HttpClient, añadirás provideHttpClient() aquí.

🗝️ El modelo mental del profe — "providers, providers, providers": casi toda regla o configuración que quieras agregar a tu proyecto se maneja con un provider. La forma de pensarlo es: "necesito tal cosa… → seguro hay un provide*() para eso". ¿Rutas? provideRouter(). ¿Peticiones HTTP? provideHttpClient(). ¿Animaciones? provideAnimations(). Todos se registran en este array providers.

📝 Nota de versiones: provideZonelessChangeDetection() aparece explícito en estas versiones; el profe comentó que en la última versión el zoneless podría venir por defecto y no aparecer escrito en este archivo. Si no lo ves, no te asustes.

🧪 Tip de entrevista: "¿Para qué sirve app.config.ts?" → define la configuración global de la app (los providers): router, manejo de errores, HttpClient, modo de detección de cambios, etc. Es lo que en el sistema antiguo hacía el AppModule.

📄 app.html — el template del componente (primer "Hola mundo")

Es el HTML del componente raíz: lo que se ve en pantalla. Si borras lo que trae y escribes algo, aparece al instante en el navegador (gracias al live reload).

html
HOLA MUNDO

<router-outlet/>
  • Escribir HOLA MUNDO → se muestra tal cual en la página. (Primer cambio visible: confirma que editas el componente correcto y que la recarga automática funciona.)
  • <router-outlet/> → es el marco del enrutador: aquí Angular muestra el componente que corresponda según la ruta actual (de app.routes.ts).

💡 Por qué está el <router-outlet/> por defecto: el App viene con imports: [RouterOutlet] justamente para poder usar esta etiqueta. Todo lo que escribas fuera del outlet (como HOLA MUNDO) se ve siempre; lo que entra dentro del outlet cambia según la URL.

🔗 Conecta con: app.ts (imports: [RouterOutlet]) y app.routes.ts (las rutas que se renderizan aquí).

🧭 app.routes.ts — las rutas (navegación)

Define las rutas de la app: qué componente se muestra para cada URL. Recién creado está vacío:

ts
import { Routes } from '@angular/router';

export const routes: Routes = [];   // aún sin rutas
  • Routes = el tipo TS (un array de rutas).
  • routes = el array que tú vas a llenar. Empieza vacío ([]).
  • Estas routes son las que recibe provideRouter(routes) en app.config.ts.

🛣️ Cómo se ve una ruta cuando la llenas

ts
import { Routes } from '@angular/router';
import { Home } from './home/home';
import { About } from './about/about';

export const routes: Routes = [
  { path: '',       component: Home },   // URL "/"        → muestra <Home>
  { path: 'about',  component: About },  // URL "/about"   → muestra <About>
  { path: '**',     component: Home },   // cualquier otra → (comodín 404)
];
PropiedadQué es
pathEl trozo de URL (sin / inicial). '' es la página de inicio.
componentQué componente mostrar en esa URL.
'**'Comodín: captura cualquier ruta no definida (útil para una página 404).

🔗 El circuito del router: defines rutas aquí → provideRouter(routes) las activa en app.config.ts → el componente se muestra en el <router-outlet> (por eso app.ts tenía imports: [RouterOutlet]).

⚠️ MUY IMPORTANTE (lo recalcó el profe): en Angular el ruteo NO es por estructura de carpetas. Crear una carpeta hola/ no habilita la URL /hola automáticamente (eso pasa en otros frameworks como Next.js, no en Angular). En Angular tienes que declarar la ruta a mano en app.routes.ts y asociarla a un componente. Sin esa entrada en el array routes, la URL no existe.

🧪 Tip de entrevista: "¿El enrutado de Angular es basado en carpetas?" → No. Es explícito/por configuración: cada ruta se declara en app.routes.ts (path + component).

💡 <router-outlet> es una etiqueta que pones en tu HTML; ahí Angular intercambia el componente según la URL actual. Es el "marco" donde aparecen las páginas.

⚙️ Los archivos tsconfig.*.json (configuración de TypeScript)

Angular escribe el código en TypeScript (JS con tipos), y el compilador (tsc) necesita saber cómo compilarlo. Esa configuración vive en archivos tsconfig.

En vez de un solo archivo gigante, Angular lo divide en 3 para separar responsabilidades:

ArchivoPara qué sirve
tsconfig.jsonConfig base / raíz. Las reglas comunes que heredan los demás.
tsconfig.app.jsonConfig de la aplicación (el código que se compila y se publica).
tsconfig.spec.jsonConfig de los tests (archivos .spec.ts, las pruebas).

💡 Idea clave: tsconfig.json es el "padre"; tsconfig.app.json y tsconfig.spec.json son "hijos" que extienden al padre y añaden lo suyo.

🔍 Ejemplo: tsconfig.spec.json (el de los tests)

jsonc
{
  "extends": "./tsconfig.json",        // hereda toda la config base
  "compilerOptions": {
    "outDir": "./out-tsc/spec",        // dónde deja los archivos compilados de los tests
    "types": [
      "jasmine"                        // incluye los tipos de Jasmine (framework de tests)
    ]
  }
}
  • extends = "parte de la config de este otro archivo y solo cambio/añado lo que ponga aquí". Evita repetir reglas en cada archivo.
  • compilerOptions = opciones de cómo compila TypeScript.
  • outDir = carpeta de salida donde van los .js ya compilados.
  • types = qué definiciones de tipos cargar. Aquí jasmine porque los tests se escriben con ese framework.

🧪 Jasmine es el framework de pruebas que Angular trae por defecto (junto a Karma para ejecutarlas). Por eso el tsconfig.spec.json añade sus tipos: para que en los .spec.ts funcionen describe(), it(), expect(), etc.

💡 ¿Por qué separar app y spec? El código de pruebas no debe acabar en la app final que ve el usuario. Separar los tsconfig mantiene los tests fuera del build de producción.