Road to Angular Next: Creación proyecto Angular 17

0
120
Creación proyecto Angular 17

En este artículo, exploraremos la creación de cero de un proyecto de Angular con SSR y veremos qué configuraciones nuevas nos trae. En el siguiente tutorial veremos cómo mejorar la configuración por defecto y añadir otras herramientas de desarrollo.

Creación proyecto

El primer paso va a ser crear un proyecto de Angular de cero, usando el siguiente comando:

npm init @angular ng-future  

Marcamos la opción “Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)”, que ya está lista para entornos productivos.

Salida por consola al ejecutar npm init @angular ng-future

Con la opción SSR habilitada Angular creará dos entornos de ejecución: cliente y servidor. La parte novedosa es que ya está integrado totalmente dentro del CLI de Angular. Con el SSR se mejora el performance y otras métricas importantes sin tener que instalar el paquete de Angular Universal, que este quedaría deprecado.

Estructura del proyecto

Si indagamos en la estructura de proyecto veremos que ha creado una serie de ficheros de configuración para la parte cliente como la parte servidora. Aquí tienes un resumen:

Cliente Servidor
main.ts main.server.ts
app.config.ts app.config.server.ts
~ server.ts

server.ts

En este fichero es donde se inicializa un servidor de NodeJS con Express con el siguiente contenido:

import { APP_BASE_HREF } from '@angular/common'  
import { CommonEngine } from '@angular/ssr'  
import express from 'express'  
import { fileURLToPath } from 'node:url'  
import { dirname, join, resolve } from 'node:path'  
import bootstrap from './src/main.server'

// The Express app is exported so that it can be used by serverless Functions.  
export function app(): express.Express {  
const server = express()  
const serverDistFolder = dirname(fileURLToPath(import.meta.url))  
const browserDistFolder = resolve(serverDistFolder, '../browser')  
const indexHtml = join(serverDistFolder, 'index.server.html')

const commonEngine = new CommonEngine()

server.set('view engine', 'html')  
server.set('views', browserDistFolder)

// Serve static files from /browser  
server.get(  
'*.*',  
express.static(browserDistFolder, {  
maxAge: '1y',  
}),  
)

// All regular routes use the Angular engine  
server.get('*', (req, res, next) => {  
const { protocol, originalUrl, baseUrl, headers } = req

commonEngine  
.render({  
bootstrap,  
documentFilePath: indexHtml,  
url: `${protocol}://${headers.host}${originalUrl}`,  
publicPath: browserDistFolder,  
providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],  
})  
.then(html => res.send(html))  
.catch(err => next(err))  
})

return server  
}

function run(): void {  
const port = process.env['PORT'] || 4000

// Start up the Node server  
const server = app()  
server.listen(port, () => {  
console.log(`Node Express server listening on http://localhost:${port}`)  
})  
}

run()  

Se hace boostrap de la aplicación del servidor y se exponen los assets estáticos (CSS, HTML, fuentes, imágenes, etc) con el siguiente código:

server.get(  
'*.*',  
express.static(browserDistFolder, {  
maxAge: '1y',  
}),  
)  

Aquí se podría integrar un CDN como CloudFront para servir los ficheros estáticos y que estén cacheados.

main.server.ts

En este fichero tenemos una función bootstrap exportada que se usa en el server.ts para lanzar la aplicación en el lado servidor. Se carga también el componente raíz AppComponent. Como podemos observar no hay ninguna mención de los Módulos de Angular, ya que se usan los nuevos Standalone Components (profundizaremos en esto en otra sección):

import { bootstrapApplication } from '@angular/platform-browser'  
import { AppComponent } from './app/app.component'  
import { config } from './app/app.config.server'

const bootstrap = () => bootstrapApplication(AppComponent, config)

export default bootstrap  

main.ts

En este fichero tendremos el código responsable de lanzar la aplicación en el cliente. Es muy parecido al main.server.tssalvo que la configuración es distinta, usa el app.config:

import { bootstrapApplication } from '@angular/platform-browser'  
import { appConfig } from './app/app.config'  
import { AppComponent } from './app/app.component'

bootstrapApplication(AppComponent, appConfig).catch(err => console.error(err))  

app.config

La configuración que está en el appConfig tendrá un nuevo provider que une la brecha entre el cliente y el servidor: el provideClientHydration() . Con este provider nuevo nos aseguraremos que el cliente y el servidor no duplican su trabajo.

import { ApplicationConfig } from '@angular/core'  
import { provideRouter } from '@angular/router'  
import { routes } from './app.routes'  
import { provideClientHydration } from '@angular/platform-browser'

export const appConfig: ApplicationConfig = {  
providers: [  
provideRouter(routes),  
provideClientHydration(),  
],  
}

app.config.server.ts

Por último tenemos el app.config.server.ts , que carga un nuevo provider: provideServerRendering() :

import { ApplicationConfig, mergeApplicationConfig } from '@angular/core'  
import { provideServerRendering } from '@angular/platform-server'  
import { appConfig } from './app.config'

const serverConfig: ApplicationConfig = {  
providers: [provideServerRendering()],  
}

export const config = mergeApplicationConfig(appConfig, serverConfig)  

¿Dónde están los NgModules?

Angular quiere empujar a los desarrolladores a que eviten el uso de módulos, decisión que creo que es correcta. El principal problema de los módulos es que introducen mucho boilerplate, es fácil no incluir una dependencia necesaria haciendo que la aplicación se rompa de manera sustancial y es fácil incluir dependencias de más que no harán más que añadir lastre a un bundle que ya es bastante pesado para un “Hola mundo”.

Conclusión

Como hemos visto en este tutorial hay configuraciones nuevas respecto a versiones anteriores, simplificando y reduciendo el número de ficheros que se crean con el CLI de Angular a la hora de comenzar un nuevo proyecto.

Nómada Digital y Artesano del Software de España | JavaScript es mi pasaporte al mundo. En Autentia, me centro en crear aplicaciones web robustas usando React, Angular y Vue, con un énfasis especial en pruebas y TypeScript para asegurar la calidad y mantenibilidad. Como ponente internacional y miembro y embajador del comité de Codemotion, disfruto compartiendo mis conocimientos y aprendiendo de la comunidad tecnológica global. Cuando no estoy programando, puedes encontrarme explorando el mundo, presentando Colivers Club; un podcast para nómadas digitales, escalando, jugando juegos de mesa o aprendiendo un hobby nuevo.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad