Qué es y para qué sirve
esbuild-plugin-tsc es un plugin para esbuild que delega la transpilación de ficheros TypeScript al compilador oficial tsc. Esto resulta útil cuando tu código depende de características que esbuild aún no cubre, como emitDecoratorMetadata, o cuando necesitas que los metadatos de los decoradores queden perfectamente reflejados en runtime.
Instalación y configuración inicial
npm i -D esbuild-plugin-tsc typescript
El siguiente fragmento muestra una configuración mínima para compilar un proyecto con decoradores:
// build.js
import { build } from 'esbuild';
import tscPlugin from 'esbuild-plugin-tsc';
await build({
entryPoints: ['src/main.ts'],
bundle: true,
outfile: 'dist/app.js',
platform: 'node',
plugins: [tscPlugin()]
}).catch(() => process.exit(1));
Filtrado selectivo de ficheros
Evita que todo el árbol de fuentes pase por tsc. Usa la opción filter para restringir la compilación solo a los módulos que realmente lo necesitan:
import { build } from 'esbuild';
import tscPlugin from 'esbuild-plugin-tsc';
await build({
entryPoints: ['src/index.ts'],
bundle: true,
outfile: 'dist/bundle.js',
plugins: [
tscPlugin({
filter: /src\/decorated\/.*\.ts$/,
tsconfig: 'tsconfig.build.json'
})
]
});
Integración con monorepos
Si tu repositorio contiene varios paquetes, puedes centralizar la configuración de TypeScript en un único tsconfig.base.json y luego extenderlo:
// packages/api/build.js
import { build } from 'esbuild';
import tscPlugin from 'esbuild-plugin-tsc';
await build({
entryPoints: ['src/server.ts'],
bundle: true,
outfile: 'lib/server.js',
plugins: [
tscPlugin({
tsconfig: '../../tsconfig.base.json',
filter: /\.ts$/
})
]
});
Combinación con otros plugins
esbuild-plugin-tsc puede coexistir con plugins de esbuild que gestionan estilos, assets o alias. El orden de los plugins importa: coloca tscPlugin antes que cualquier otro que transforme TypeScript para evitar conflictos.
import { build } from 'esbuild';
import tscPlugin from 'esbuild-plugin-tsc';
import { sassPlugin } from 'esbuild-sass-plugin';
await build({
entryPoints: ['src/ui.tsx'],
bundle: true,
outfile: 'dist/ui.js',
plugins: [
tscPlugin({ filter: /\.tsx?$/ }),
sassPlugin({ type: 'style' })
]
});
Consideraciones de rendimiento
Al usar tsc solo sobre un subconjunto de ficheros mantienes la mayor parte de la velocidad de esbuild. Para proyectos grandes, combina:
filterpara reducir el volumen de código procesado portscincremental: trueentsconfig.jsonpara aprovechar la compilación incrementalesbuilden modowatchpara recargas rápidas durante el desarrollo
Ejemplo real: API con routing por decoradores
// src/controllers/UserController.decorated.ts
import { Controller, Get } from '@nestjs/common';
@Controller('users')
export class UserController {
@Get()
list() {
return [{ id: 1, name: 'Ada' }];
}
}
// build.js
import { build } from 'esbuild';
import tscPlugin from 'esbuild-plugin-tsc';
await build({
entryPoints: ['src/main.ts'],
bundle: true,
platform: 'node',
target: 'node18',
outfile: 'dist/main.js',
plugins: [
tscPlugin({
filter: /\.decorated\.ts$/,
tsconfig: 'tsconfig.json'
})
]
});