Un preset es un conjunto con nombre de transformaciones con un coste de tamaño y de ejecución conocido. Un preset más pesado aplica más transformación; no es un aumento medido de la protección. Un nombre fija el objetivo de complejidad; el tamaño de salida se deriva de ese objetivo. Fijar complexity explícitamente anula el objetivo, y un valor fijado directamente siempre se aplica a cada token, incluso en light.
La escala
| Preset | complexity | Tamaño gzip típico | Mínimo de cadenas | Úsalo cuando |
|---|---|---|---|---|
minify | 0 | 1.09x a 1.17x | desactivado | Sin ofuscación. Los identificadores se renombran y el código se comprime; los literales de cadena siguen siendo legibles. |
light | 5 | 1.29x a 1.60x | activado | Por defecto. Añade la codificación de cadenas a minify y reescribe la sintaxis, sin capas estructurales. El preset adecuado para el bundle completo de una app. |
medium | 7 | 6.04x a 8.33x | activado | Código que quieres que sea claramente más difícil de seguir. En el bundle completo de una app multiplica el tiempo de arranque (coste de carga), así que mide antes tus páginas. |
hard | 12 | 6.62x a 9.23x | activado | Código que importa: precios, control de acceso, comprobaciones de licencia, lógica de negocio en el cliente. Dirígelo a ese código con una directiva; en un bundle completo cuesta más que medium. |
extreme | 25 | 8.25x a 11.19x | activado | La complejidad aplicada más alta. Dirígelo a un archivo o a una región en lugar de a todo el bundle. |
Tamaño de salida comprimido con gzip frente al mismo archivo ya minificado, medido en cinco bundles de producción reales ya minificados, con AfterPack 0.2.6 el 2026-10-16; el método está en Rendimiento.
El mínimo de cadenas está activado para cualquier objetivo positivo.
Coste de carga
Medido con AfterPack 1.0.0 el 2026-10-24, en cinco apps pequeñas construidas con Vite y React, Vue, Astro, SvelteKit y Next.js. Cada app se ejecutó con todo su bundle en un preset y se compara con la misma app construida sin AfterPack; el método y el tiempo de cada app están en Rendimiento.
| Preset | JavaScript que carga la página, sin comprimir | Tiempo hasta el primer clic que funciona |
|---|---|---|
light | 1.12x a 1.42x | +4 ms a +32 ms |
medium | 10.2x a 11.9x | 3.1x a 11x |
hard | 14.3x a 15.8x | 3.2x a 13.7x |
extreme | 27.1x a 30.7x | 5.9x a 24x |
El tamaño crece aproximadamente en el mismo factor en todos los frameworks. El tiempo de arranque crece según cuánto de ese código se ejecuta antes de que la página responda, así que la app de Next.js fue la que más pagó. El runtime del propio framework forma parte del bundle, y todos los presets también lo protegen.
En el bundle completo de una app, light añade como mucho unas decenas de milisegundos. A partir de medium, mide tus propias páginas antes de publicar el preset en todo el bundle.
El valor por defecto es light
Ejecuta npx afterpack@latest dist/ sin --preset, o instala un plugin sin configurar nada, y obtienes light.
$ npx afterpack@latest dist/npx afterpack@latest dist/ --preset=hard # step upLos flags unen su valor con =. Un valor separado por espacio se rechaza como flag desconocido.
light es el mínimo sin configuración. Cada literal de cadena que puede reescribir pasa por un decodificador en tiempo de ejecución. Renombra los identificadores y reescribe la sintaxis, y no añade capas estructurales. A partir del motor 0.2.3, los bucles ya no se reescriben en funciones auxiliares de callback en minify y light, lo que elimina la ralentización de 2-5x que esas funciones causaban en los bucles críticos. En light, los nombres de propiedades y de globales siguen pasando por constantes codificadas, lo que tiene cierto coste en código muy caliente. Algunas cadenas siguen siendo legibles en todos los presets: los prólogos de directivas, los operandos de typeof, los nombres de propiedad que necesita el runtime y los nombres de exportación. El Protection Map las enumera, y el motor informa del recuento y del total de bytes en cada build. Subir el preset a medium o superior añade trabajo estructural en cada token: inflación, remodelado del flujo de control, y cadenas y enteros vinculados a un valor compartido en tiempo de ejecución. No cambia la legibilidad de las cadenas, que ya está en su mínimo.
minify es el único peldaño que desactiva ese mínimo. A partir del motor 0.2.3, solo renombra los identificadores y comprime el código, sin ofuscación aplicada. El motor 0.2.2 también reescribía la sintaxis en minify.
Presupuesto de tamaño
Toda salida lleva la sobrecarga fija del runtime del motor (los decodificadores y el intérprete de expresiones enteras), por lo que un archivo de unos cientos de bytes sale proporcionalmente más grande que esos rangos. Lee la proporción sobre un bundle real, no sobre un archivo pequeño.
inflation.max no está establecido por defecto, así que el objetivo de complejidad decide por sí solo el tamaño de salida. Establécelo tú mismo solo cuando tengas un presupuesto de tamaño real que prefieras no superar. Alcanzar un valor explícito es un error: DIAG_SIZE_CAP_REACHED, sin salida, código de salida 3 desde la CLI, y un build fallido desde un plugin. A partir del motor 0.2.3, nunca se escribe en su lugar una salida con menos protección: el archivo terminado se comprueba contra el límite y la codificación de cadenas siempre termina primero. En el motor 0.2.2, un límite ajustado podía detener antes la codificación de cadenas y dejar algunas cadenas legibles.
Los bytes ofuscados, y con ellos el tamaño gzip, cambian de un build a otro por diseño. Por defecto cada build genera una semilla nueva, y seed: "git" genera una nueva en cada commit, así que cada versión publica un programa distinto. Una semilla fija reproduce los bytes solo para la misma entrada con la misma versión del motor. Fija el presupuesto de tamaño del bundle sobre el código tal como lo escribió tu bundler, antes de AfterPack, o da un margen al presupuesto sobre la salida protegida.
Establecer el objetivo directamente
complexity es un número no negativo sin límite superior. --complexity=200 es una sobrescritura válida en el nivel Free, muy por encima de lo que establece extreme.
npx afterpack@latest dist/ --preset=hard --complexity=40Eso es hard con su objetivo de complejidad sobrescrito a 40; nada más del preset cambia. Pasar el nombre de un preset a --complexity es un error.
Aplicar un preset a una región
En Free, un solo preset cubre todo el build: --preset en la CLI, o preset en tu configuración. El único control más acotado es paths.exclude, que deja fuera archivos completos y los copia a la salida sin proteger. Cada uno de los demás archivos paga el coste de carga del preset, así que mantén el bundle completo de una app en light salvo que tus propias mediciones permitan más.
En Pro, una directiva en el código fuente pone un preset más pesado en una función o un archivo, y el resto del bundle mantiene tu preset global:
/* @afterpack preset=extreme */
function pricingEngine(plan, region) {
return resolve(plan, region);
}
/* @afterpack end */Para cubrir un archivo, envuelve su código en una sola directiva. Las directivas son solo comentarios de bloque, que un plugin de framework lee de tu código fuente; la CLI no lee ninguna. Consulta Directivas para la gramática y las reglas por nivel.
Siguiente
- Configuración: cada clave que toca un preset.
- Referencia de la CLI: los flags que seleccionan un preset.
- Directivas:
skipopreset=<name>para un tramo. - Cómo funciona AfterPack: qué aporta realmente un objetivo más alto frente a un lector estático.
- Buenas prácticas: qué proteger más y qué dejar sin tocar.