El equipo de Angular está trabajando en un nuevo constructor llamado aplicación (el constructor actual se llama navegador), ya está disponible como vista previa para desarrolladores en Angular 16.2 y será el predeterminado para las nuevas aplicaciones generadas utilizando Angular 17

así que primero

¿Qué es un constructor en Angular?

Angular builder (llamado executer en nx repos) es básicamente el compilador que convierte tu aplicación Angular TS, Angular HTML, y archivos SCSS en HTML plano, JS y archivos css que pueden ser entendidos por el navegador

ahora mismo tenemos múltiples constructores

  1. @angular-devkit/build-angular:browser : para la compilación de producción
  2. @angular-devkit/build-angular:dev-serverpara servir p.ej. ng serve que todavía usa @angular-devkit/build-angular:browser bajo el capó pero sin mucha optimización y exponiendo algunas partes del compilador Angular en el tiempo de ejecución.
  3. @angular-devkit/build-angular:server para ssr production build
  4. @nguniversal/builders:ssr-dev-server para ssr serve
  5. @nguniversal/builders:prerender para prerender.

ahora todos estos estan basados en webpack, hay uno nuevo @angular-devkit/build-angular:browser-esbuild y como su nombre indica usa esbuild, actualmente esta disponible como developer preview (de hecho lo estoy usando en produccion para https://interview.community sin ningun problema)

¿dónde encaja el nuevo constructor?

Usará @angular-devkit/build-angular:browser-esbuild bajo el capó pero lo extenderá para reemplazar también @angular-devkit/build-angular:server y @nguniversal/builders:prerender

y como ahora puede hacerlo tanto el navegador como el ssr build, hará que @angular-devkit/build-angular:dev-server pueda reemplazar a @nguniversal/builders:ssr-dev-server

así que básicamente en el futuro tendremos 2 en lugar de los 5 actuales (bueno, hay algunos otros constructores para pruebas unitarias e i18n, pero eso es otra historia)

¿Cuáles son los beneficios de hacer todo esto?

  1. Configuración más simple en el angular.json (o project.json en el caso de nx), ya que no es necesario repetir la configuración en un montón de lugares)
  2. Es más rápido, ya que hay algunos pasos comunes entre la construcción del navegador, prerender, y ssr tener un constructor significará que estos pasos se ejecutarán una vez en lugar de 3 ahora.
  3. habilitará el uso de módulos es (aka esm) en el SSR, ahora funciona para proyectos que no tienen SSR


¿cómo probar este nuevo constructor?

  1. Actualiza a la última versión de Angular (@angular/cli es 16.2.3 en el momento en que publiqué el artículo)
  2. actualiza tu archivo angular.json: cambia tu constructor en build de @angular-devkit/build-angular:browser a @angular-devkit/build-angular:application
  • (opcional) actualiza outputPath para que no tenga browser ya que ahora es una carpeta para el servidor y el browser reemplazar clave principal para ser navegador que apunta todavía a su archivo main.ts
  • Añade "server": "src/main.server.ts" o cualquiera que sea la ruta para su main.server.ts
  • Añade "ssr: { "entry": "server.ts" } en sus configuraciones de producción o si prefiere tener ssr en su desarrollo entonces añádalo como opción
  • Elimina server , serve-ssr , y prerender de su archivo
    actualice su archivo server.ts para que sea.

3. Actualice su archivo server.ts para que sea

 import { APP_BASE_HREF } from '@angular/common';
import { ngExpressEngine } from '@nguniversal/express-engine';
import express from 'express';
import { fileURLToPath } from 'node:url';
import { dirname, join } 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 distFolder = dirname(fileURLToPath(import.meta.url));
  const indexHtml = join(distFolder, 'index.server.html');

  // Our Universal express-engine (found @ https://github.com/angular/universal/tree/main/modules/express-engine)
  server.engine('html', ngExpressEngine({
    bootstrap
  }));

  server.set('view engine', 'html');
  server.set('views', distFolder);

  // Example Express Rest API endpoints
  // server.get('/api/**', (req, res) => { });
  // Serve static files from /browser
  server.get('*.*', express.static(distFolder, {
    maxAge: '1y'
  }));

  // All regular routes use the Universal engine
  server.get('*', (req, res) => {
    res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
  });

  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();

4. Actualiza su tsconfig.app.json para que sea

/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app",
    "types": [],
    "allowSyntheticDefaultImports": true
  },
  "files": [
    "src/main.ts",
    "src/main.server.ts",
    "server.ts"
  ],
  "include": [
    "src/**/*.d.ts"
  ]
}

5. tu script serve:ssr será node dist/nombre_proyecto/server.mjs

y eso es todo, usted es bueno ir ahora

puedes ver el ejemplo de cambios y la aplicación funcionando aquí

Fuente