# Ofusca un build de Parcel

@afterpack/parcel-optimizer ofusca en memoria cada bundle empaquetado como un Optimizer de Parcel 2, y hace fallar el build de forma segura antes que publicar un chunk que da 404 en producción.

Source: https://www.afterpack.dev/es/docs/frameworks/parcel

`@afterpack/parcel-optimizer` es un **Optimizer** de Parcel 2, registrado en `.parcelrc`. Ofusca cada bundle empaquetado **en memoria**, durante la propia fase de optimización de Parcel, así que el bundle nunca llega a disco en claro.

> **No es @afterpack/parcel**
>
> El paquete es `@afterpack/parcel-optimizer`.

## Instalación

```bash
npm install -D @afterpack/parcel-optimizer
```

```jsonc
// .parcelrc
{
  "extends": "@parcel/config-default",
  "optimizers": {
    "*.{js,mjs,cjs}": ["...", "@afterpack/parcel-optimizer"]
  }
}
```

El spread `"..."` importa: conserva los optimizers por defecto de Parcel (`@parcel/optimizer-swc`) y coloca AfterPack el **último**. AfterPack se ejecuta después de la minificación. Dependencia peer: Parcel `>=2.9.0`.

## Build

Las entradas de `.parcelrc` son nombres de paquete sin opciones en línea, así que las opciones salen de `afterpack.json` en la raíz de tu proyecto, el único archivo de configuración que leen todas las integraciones de AfterPack:

```json
{
  "seed": "git",
  "preset": "medium"
}
```

Solo se generan artefactos en la raíz del proyecto; nada va junto a tus bundles:

- **Un [`protectionMap.html`](https://www.afterpack.dev/es/docs/protection-map) por bundle**, en `.afterpack/<bundle>.<id>.protectionMap.html`, cuando el mapa está activado (consulta [Verificación](#verify)).
- Un source map, cuando la [política de sourceMap](https://www.afterpack.dev/es/docs/config#sourceMap-enabled) lo activa. Se devuelve a Parcel en lugar de escribirse directamente, así que Parcel le pone nombre y lo emite con su propio hash de contenido.

`.afterpack/` lleva su propio `.gitignore`; el plugin nunca edita el de tu proyecto.

## Verificación

Como no hay un informe combinado, revisa directamente el bundle que te interesa: `.afterpack/<bundle-name>.<id>.protectionMap.html` para cada entrada o chunk diferido que Parcel empaquetó. Por defecto se escribe un informe cuando el bundle lleva un source map y el build no se ejecuta en CI (`CI=true` o `CI=1`); pon `"protectionMap": { "enabled": true }` en `afterpack.json` para [forzarlo](https://www.afterpack.dev/es/docs/config#protectionMap-enabled). Cada informe contiene todo tu código fuente. Nunca lo subas al repositorio ni lo sirvas.

Para comprobar un despliegue, añade el reporter del plugin al comando de build. Cada build escribe entonces un recibo de protección en `.afterpack/receipts/`, en la [raíz de tu proyecto](https://www.afterpack.dev/es/docs/cli#files), uno por cada directorio de salida de destino (`.afterpack/receipts/dist.json` para `dist`). [`afterpack verify`](https://www.afterpack.dev/es/docs/cli#afterpack-verify-dir) falla cuando un archivo cambió después de ofuscarse o cuando no hay recibo:

```bash
parcel build index.html --reporter @afterpack/parcel-optimizer/reporter
npx afterpack@latest verify dist
```

## Opciones

Ahí se puede establecer cada [clave de configuración](https://www.afterpack.dev/es/docs/config), por ejemplo `{ "preset": "hard", "complexity": 40 }`. [`protectionMap.enabled`](https://www.afterpack.dev/es/docs/config#protectionMap-enabled) depende de si el bundle lleva un source map, no del [modo de build](https://www.afterpack.dev/es/docs/config#build-mode), y siempre se guarda en `.afterpack/`, ignorado por git. Este plugin no tiene opción `build.backup`. Establecerla muestra una advertencia. Las opciones explícitas siempre tienen prioridad sobre los valores por defecto de producción.

## Directivas

Las directivas son una función [Pro](https://www.afterpack.dev/es/docs/pro). En un [build Free](https://www.afterpack.dev/es/docs/directives#free-builds), una directiva que aumenta la protección detiene el build con `DIAG_PRO_DIRECTIVE_REQUIRES_KEY`.

El plugin lee las directivas de tu código fuente. Sin un source map utilizable, la pasada no tiene nada que recuperar y lo indica.

**Una directiva en tu módulo de entrada no se recupera.** La pasada informa de `DIAG_DIRECTIVE_SOURCE_UNRESOLVED` e indica el módulo. Las directivas en cualquier otro módulo que no sea de entrada funcionan con normalidad en cuanto los source maps están activados. Mueve el código protegido a un módulo importado si necesitas una directiva en el módulo de entrada.

## Casos límite

### Los placeholders de hash de contenido pueden hacer fallar tu build

Con el hash de contenido activado (el valor por defecto de `parcel build`) y un target sin ESM nativo, los placeholders de hash de contenido de Parcel acaban dentro de cadenas ofuscadas, y cada chunk dividido da 404 en producción.

Este plugin detecta la colisión y hace fallar el build en lugar de publicarlo:

```
AfterPack obfuscated 1 Parcel content-hash placeholder(s) in app.[hash].js (HASH_REF_...).
  hint: Run `parcel build --no-content-hash` (chunk URLs stop being content-addressed).
  hint: Or set "complexity": 0 in afterpack.json to ship minify-only.
```

La salida ESM por defecto de Parcel no se ve afectada.

### Conviene saber

- **Una pasada por bundle, en procesos worker.** Parcel ejecuta los optimizers por bundle, y los bundles empaquetados en procesos worker distintos no pueden compartir estado. Los bundles empaquetados en el mismo proceso comparten una semilla. Para fijar una sola semilla en todos los workers, establece [`seed`](https://www.afterpack.dev/es/docs/config#seed) de forma explícita o exporta `AFTERPACK_seed`.
- **Parcel cachea la salida de los optimizers.** Un rebuild con `.parcel-cache` caliente y la entrada sin cambios no vuelve a ejecutar AfterPack ni rota una semilla sin fijar. Borra `.parcel-cache` para una pasada nueva; en CI se compila de todos modos con la caché fría.
- **Dos advertencias inofensivas.** Parcel imprime `ES module dependencies are experimental` (todos los paquetes de AfterPack son ESM) e informa de que el plugin `contains non-statically analyzable dependencies` (la resolución en tiempo de ejecución del binario nativo del motor). Ninguna afecta al build.

### Sin el plugin: la CLI

Compila con Parcel como siempre y luego apunta AfterPack a la salida:

```bash
npx parcel build
```

```bash
npx afterpack@latest dist/ --seed=git
```

Sin un [argumento de ruta](https://www.afterpack.dev/es/docs/cli#usage), la CLI detecta `dist/`, la salida por defecto de Parcel; indica el directorio si el tuyo es otro. AfterPack recorre el directorio, recopila cada `.js`/`.mjs`/`.cjs` y los ofusca [en el sitio](https://www.afterpack.dev/es/docs/cli#what-a-run-does). Una ejecución de la CLI no tiene la protección del hash de contenido, y genera un único [`protectionMap.html`](https://www.afterpack.dev/es/docs/protection-map) combinado para todo el directorio en lugar de uno por bundle. El [fallo seguro (fail closed)](https://www.afterpack.dev/es/docs/diagnostics#fail-closed-no-exceptions) se mantiene: un directorio de build inexistente, la ausencia de archivos JS, un [diagnóstico](https://www.afterpack.dev/es/docs/diagnostics) `error`/`critical` o un archivo que el motor no pudo ofuscar terminan todos con un código distinto de cero.

## Siguiente

- [Frameworks](https://www.afterpack.dev/es/docs/frameworks): la matriz completa.
- [esbuild](https://www.afterpack.dev/es/docs/frameworks/esbuild#directives): otro plugin que recupera las directivas de un source map después de la minificación.
- [Referencia de la CLI](https://www.afterpack.dev/es/docs/cli): los flags completos de la vía alternativa.
- [Builds y CI](https://www.afterpack.dev/es/docs/builds): semillas, desarrollo frente a producción, promocionar los mismos bytes.
- [Protection Map](https://www.afterpack.dev/es/docs/protection-map): cómo leer el informe.
- [Configuración](https://www.afterpack.dev/es/docs/config): cada opción y qué superficie puede establecerla.
- [Presets](https://www.afterpack.dev/es/docs/presets): la escala de cinco peldaños.
