Webpack para servidor Node con TypeScript

Resumen

Configurar Webpack con TypeScript para un servidor Node.js es el primer paso para montar un proyecto de server-side rendering con React. Aquí aprenderás a transpilar tu código TypeScript a JavaScript, separar la configuración del cliente y del servidor, y crear un flujo de desarrollo con recarga automática usando nodemon.

Esta guía es útil si ya conoces Webpack a nivel básico y quieres preparar la base de un proyecto SSR antes de instalar Express o cualquier framework adicional.

¿Cómo separar la configuración de Webpack para cliente y servidor?

Cuando un proyecto necesita correr tanto en navegador como en Node, conviene tener dos archivos de configuración independientes. Así cada entorno declara solo lo que necesita.

Lo primero es renombrar el archivo original a webpack.config.client.js y crear uno nuevo llamado webpack.config.server.js. El del cliente sigue produciendo app.js, mientras que el del servidor producirá index.js, siguiendo la convención de que index.js es el entry point natural de cualquier app de JavaScript en Node [02:54].

Dentro de src también se crea una carpeta server con un archivo index.ts que, por ahora, solo contiene un console.log de prueba para validar la transpilación.

¿Por qué usar dos archivos de configuración de Webpack? Porque el cliente y el servidor tienen targets distintos: el navegador necesita HTML y bundles optimizados para web, mientras que Node necesita ignorar node_modules y apuntar al runtime del servidor.

¿Qué cambios necesita Webpack para apuntar a Node.js?

La configuración del servidor parte de la del cliente, pero con varios ajustes clave que la adaptan al entorno de backend.

Ajustes esenciales en webpack.config.server.js

  • Agregar target: 'node' para indicar que el bundle correrá en Node.js y no en el navegador.
  • Cambiar el entry a src/server/index.ts.
  • Renombrar la salida a index.js.
  • Eliminar el plugin HtmlWebpackPlugin, ya que el servidor no genera HTML estático.
  • Quitar el procesamiento de íconos, que es exclusivo del cliente.
  • Mantener el loader con JavaScript Compiler configurado para parsear sintaxis TypeScript y leer archivos .tsx.
  • Conservar las extensiones .tsx, .ts y .js en resolve [05:48].

El loader minifica el código solo cuando el entorno no es de desarrollo, y excluye node_modules para acelerar la compilación.

Cómo ignorar node_modules con webpack-node-externals

Aquí entra una dependencia clave: webpack-node-externals. Se instala como dependencia de desarrollo y permite que Webpack ignore todos los paquetes de node_modules al momento de transpilar, evitando empaquetarlos dentro del bundle del servidor.

La configuración se agrega justo antes de resolve:

javascript const nodeExternals = require('webpack-node-externals');

module.exports = { target: 'node', entry: './src/server/index.ts', externals: [nodeExternals()], // resto de la config };

¿Qué hace webpack-node-externals? Es una función que se ejecuta dentro del array de externals y le dice a Webpack que no incluya los paquetes de node_modules en el bundle final. El servidor los resolverá en tiempo de ejecución.

También se conserva stats: 'errors-only' para que la terminal solo muestre mensajes cuando algo falle, y se elimina la configuración de source maps y del servidor de desarrollo de Webpack, porque no aplican al backend.

¿Cómo crear scripts de build y desarrollo en package.json?

Con la configuración lista, el siguiente paso es definir los scripts que orquestan la compilación y la ejecución.

Script para construir el servidor

Dentro de package.json se agrega un script build-server que apunta directamente al archivo de configuración:

"build-server": "webpack --config webpack.config.server.js"

Al ejecutar yarn build-server, Webpack genera la carpeta dist con el archivo index.js ya transpilado. Si lo abres, verás el console.log original convertido a JavaScript que Node puede ejecutar [09:35].

Script de desarrollo con nodemon

Para automatizar el flujo de desarrollo se usa nodemon, una dependencia de desarrollo que monitorea cambios en archivos y reinicia Node automáticamente. Se instala así:

bash yarn add -D nodemon

Luego se crean dos scripts:

  • build-dev: define NODE_ENV=development, ejecuta el build del servidor y lanza Node sobre dist/index.js.
  • dev: usa nodemon con la bandera --watch para vigilar archivos .ts y volver a ejecutar npm run build-dev cada vez que detecta un cambio.

Ejemplo del script dev:

"dev": "nodemon --watch 'src/**/*.ts' --exec "npm run build-dev""

¿Para qué sirve nodemon en un servidor de TypeScript? Funciona como un demonio que vigila cambios en tus archivos fuente y reinicia el servidor automáticamente. Así puedes editar el código y ver el resultado sin detener y volver a correr Node manualmente.

Al correr yarn dev, cualquier cambio en el console.log del servidor recompila el bundle y vuelve a imprimir el mensaje actualizado en la terminal.

¿Por qué esta configuración es la base del server-side rendering?

Todo lo construido aquí es la antesala del SSR con React. El servidor necesita estar listo antes de poder renderizar componentes desde el backend, y eso implica tener un pipeline confiable que convierta TypeScript en JavaScript ejecutable por Node.

La combinación de Webpack con target: 'node', webpack-node-externals y nodemon deja un entorno limpio: compila rápido, ignora dependencias innecesarias y reacciona a cambios en tiempo real. Sobre esta base ya puedes instalar Express, definir rutas y, más adelante, integrar el renderizado de React desde el servidor.

¿Tú prefieres usar Webpack para el backend o te inclinas más por herramientas como tsx o ts-node? Cuéntame en los comentarios cómo configuras tus servidores con TypeScript.