# Ofusca una app de Electron

@afterpack/electron conecta main, preload y renderer con una sola semilla en una única llamada, y rechaza el bytecodePlugin de electron-vite y las copias de seguridad sin protección antes de que puedan publicar tu código fuente.

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

`@afterpack/electron` ofusca desde una sola llamada los tres programas que publica una app de Electron (main, preload y renderer), con una semilla de build compartida entre ellos. Si los conectas a mano, cada parte es su propio build del bundler y toma su propia semilla aleatoria, de modo que las piezas de una misma aplicación salen estructuralmente sin relación entre sí.

electron-builder no es un bundler. Empaqueta en un instalador una app ya compilada y nunca toca tu JavaScript, así que necesita un bundler por encima con o sin AfterPack.

## Instalación

```bash
npm install -D @afterpack/electron
```

```ts
// electron.vite.config.ts
import { withAfterpack } from "@afterpack/electron";
import { defineConfig, externalizeDepsPlugin } from "electron-vite";

export default withAfterpack(
  defineConfig({
    main: { plugins: [externalizeDepsPlugin()] },
    preload: { plugins: [externalizeDepsPlugin()] },
    renderer: {},
  }),
);
```

`withAfterpack` envuelve una configuración completa de electron-vite (la forma de objeto, función o promesa que devuelve `defineConfig`) y conecta [`@afterpack/vite`](https://www.afterpack.dev/es/docs/frameworks/vite) en cada parte que declara la configuración, nunca en una que no declara. Dependencia peer: `vite ^5 \| ^6 \| ^7 \| ^8`.

## Build

Cómo conectas la pasada depende de si tu toolchain configura las tres partes en una sola llamada o con una configuración por parte.

### Una parte cada vez

Las toolchains que configuran cada parte por separado (Electron Forge con `@electron-forge/plugin-vite`) llaman a `afterpackElectron` una vez por configuración:

```ts
// vite.main.config.ts   (and vite.preload.config.ts / vite.renderer.config.ts)
import { afterpackElectron } from "@afterpack/electron";

export default { plugins: [afterpackElectron({ leg: "main" })] };
```

`leg` es obligatorio.

### Una semilla, tres formas

- **electron-vite (`withAfterpack`)** y **Forge + `plugin-vite`**: las tres configuraciones se compilan en un solo proceso de Node, así que las partes comparten semilla automáticamente.
- **`vite-plugin-electron`**: también un solo proceso. Coloca `afterpackElectron({ leg: "renderer" })` el último en `plugins`, después del propio `vite-plugin-electron`, para que el `generateBundle` de AfterPack selle el bundle terminado.
- **Scripts propios que ejecutan cada parte como un comando independiente**: no hay proceso compartido, así que fija la semilla entre ellos con una variable de entorno:

```jsonc
// package.json
"build": "AFTERPACK_seed=git vite build -c vite.main.ts && vite build -c vite.renderer.ts"
```

`AFTERPACK_seed` acepta los mismos valores que [`seed`](https://www.afterpack.dev/es/docs/config#seed): un entero, `"git"` (derivado de `HEAD`) o cualquier otra cadena, a la que el motor aplica un hash. Una opción `seed` explícita sigue teniendo prioridad sobre ella. [Estrategia de semilla](https://www.afterpack.dev/es/docs/best-practices#seed-strategy) explica cuándo fijarla y cuándo no.

## Verificación

El [Protection Map](https://www.afterpack.dev/es/docs/protection-map) se escribe por parte, en `.afterpack/<leg>/protectionMap.html`, cuando había un source map disponible y el build no se ejecuta en CI (`CI=true` o `CI=1`). El modo de [producción](https://www.afterpack.dev/es/docs/config#build-mode) no lo desactiva, pero electron-vite no emite source maps a menos que los pidas, así que el mapa está desactivado por defecto. Revisa main, preload y renderer por separado. Cada informe contiene todo tu código fuente. Nunca lo subas al repositorio ni lo sirvas.

> **Nunca incluyas source maps dentro de la app**
>
> Un `.map` en `app.asar` da acceso a tu código fuente original. Mantén desactivada la emisión de source maps (el valor por defecto en producción) en todo lo que empaquetes.

## Opciones

Aquí también funciona cada [clave de configuración](https://www.afterpack.dev/es/docs/config), aplicada a todas las partes mediante `withAfterpack(config, options)` o pasada a cada parte mediante `afterpackElectron(options)`. Estas opciones existen solo en este paquete:

| Opción | Tipo | Valor por defecto |
|---|---|---|
| `leg` | `"main" \| "preload" \| "renderer"` | obligatoria en `afterpackElectron` |
| `projectRoot` | `string` | `process.cwd()`. electron-vite toma `src/renderer/` como raíz del build del renderer. Sobrescríbela si tu build se ejecuta desde otro sitio |

[`seed`](https://www.afterpack.dev/es/docs/config#seed) toma por defecto un único valor nuevo compartido por todas las partes de una sesión de build. [`protectionMap.enabled`](https://www.afterpack.dev/es/docs/config#protectionMap-enabled) sigue la regla habitual de los source maps, y cada parte escribe su propio informe en `.afterpack/<leg>/protectionMap.html`.

```ts
// Heavier protection, reproducible per commit, applied to every leg:
withAfterpack(config, { preset: "hard", seed: "git" });
```

## Directivas

Cada parte conecta [`@afterpack/vite`](https://www.afterpack.dev/es/docs/frameworks/vite) por debajo, así que la [captura de directivas](https://www.afterpack.dev/es/docs/frameworks/vite#directives) funciona allí de la misma manera.

## Casos límite

### Matriz de compatibilidad

| Toolchain | Conexión | ¿Una sola semilla automáticamente? |
|---|---|---|
| electron-vite | `withAfterpack(defineConfig({ … }))`, una llamada | Sí |
| Forge + `plugin-vite` | `afterpackElectron({ leg })` en cada una de las tres configuraciones | Sí |
| Forge + `plugin-webpack` | [`@afterpack/webpack`](https://www.afterpack.dev/es/docs/frameworks/webpack) en cada configuración | Sí |
| `vite-plugin-electron` | `afterpackElectron({ leg: "renderer" })`, colocado el **último** | Sí, una vez colocado después de ese plugin |
| electron-builder | empaqueta, no hace bundling; conecta el bundler que está por encima | n/a |
| Scripts propios (procesos independientes) | un plugin por parte, o `npx afterpack@latest <dir>` | No; fija `AFTERPACK_seed` |

### Qué rechaza

Se aplican dos comprobaciones de fallo seguro (fail closed) en cualquier parte conectada a través de este paquete.

**`bytecodePlugin`.** El propio `bytecodePlugin` de electron-vite sustituye cada chunk emitido por un stub cargador de 3 líneas y publica la aplicación real como bytecode de V8 (`.jsc`). Los dos no se pueden combinar, porque el bytecode sustituye el chunk que generó Rollup. El build falla en la parte donde está activado `bytecodePlugin`, o allí donde aparezca después un archivo `.jsc`/`.cjsc` en la salida. Quita uno de los dos.

**`build.backup: true`.** Las [copias de seguridad](https://www.afterpack.dev/es/docs/config#build-backup) se rechazan de plano: la llamada lanza un error en lugar de continuar, porque un `.backup.<hash>.js` es tu código fuente original completo, escrito junto a la salida dentro del árbol que tu empaquetador copia en `app.asar`. Todos los usuarios que instalaran la app lo recibirían.

El mismo riesgo se extiende a cualquier artefacto que tu empaquetador no sepa excluir. El glob `files` por defecto de electron-builder hace coincidencias con `dot: true` y no excluye `.afterpack/` por defecto. Excluye esto de lo que empaquetas:

```jsonc
// electron-builder
"files": ["**/*", "!.afterpack/**", "!**/*.backup.*", "!**/*.map"]
// electron-forge
packagerConfig: { ignore: [/^\/\.afterpack/, /\.backup\./, /\.map$/] }
```

Los [source maps](https://www.afterpack.dev/es/docs/config#sourceMap-enabled) reciben una advertencia en lugar de un rechazo: un `.map` con `sourcesContent` dentro de `app.asar` equivale a una desofuscación completa. Limita `sourceMap: { enabled: true, emitUrl: true }` a los builds locales de depuración y excluye `*.map` de lo que empaquetas.

### Canales IPC

Los nombres de canal deben coincidir byte a byte entre los dos bundles. `ipcMain.on("save-file", …)` e `ipcRenderer.send("save-file", …)` son la misma cadena en ambos lados. Son literales de cadena normales en JavaScript emitido normal, así que mantener ambas partes con la misma [semilla](https://www.afterpack.dev/es/docs/config#seed) y el mismo nivel de protección ([`preset`](https://www.afterpack.dev/es/docs/config#preset) / [`complexity`](https://www.afterpack.dev/es/docs/config#complexity)) es lo que mantiene coherentes las dos mitades.

Si un nombre de canal se construye en tiempo de ejecución en lugar de escribirse como literal, deja esa construcción en un módulo que excluyas con [`paths.exclude`](https://www.afterpack.dev/es/docs/config#paths-exclude), o baja el nivel de protección de esa región con una entrada [`regions`](https://www.afterpack.dev/es/docs/config#regions) del plugin del bundler ([Pro](https://www.afterpack.dev/es/docs/pro#what-pro-buys)).

### Sin el plugin: la CLI

¿Prefieres no añadir una dependencia, o compilas alguna parte con algo que no es Vite? Ejecuta [`npx afterpack@latest`](https://www.afterpack.dev/es/docs/cli) una vez por directorio de salida después del build:

```bash
npx afterpack@latest out/main --seed=git
npx afterpack@latest out/renderer --seed=git
```

Sin un [argumento de ruta](https://www.afterpack.dev/es/docs/cli#usage), la CLI detecta `out/`, el directorio en el que escribe electron-vite; indica el directorio si el tuyo es otro. Cada ejecución 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); un único archivo también sirve como argumento. Fija la misma [`--seed`](https://www.afterpack.dev/es/docs/config#seed) en todas las ejecuciones: `git`, derivada del commit actual, es la forma más sencilla de garantizarlo. Una ejecución de la CLI no aplica ninguno de los rechazos anteriores; ofusca todo el JavaScript que encuentra. Mantén la misma [`--seed`](https://www.afterpack.dev/es/docs/config#seed) y el mismo [`--preset`](https://www.afterpack.dev/es/docs/config#preset) en todas las ejecuciones.

## Siguiente

- [Frameworks](https://www.afterpack.dev/es/docs/frameworks): la matriz completa.
- [Vite](https://www.afterpack.dev/es/docs/frameworks/vite): la semántica de las opciones que este paquete reenvía.
- [Referencia de la CLI](https://www.afterpack.dev/es/docs/cli#flags): la lista de flags 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.
- [Protege la lógica de licencias de una app de Electron](https://www.afterpack.dev/es/docs/use-cases/electron-license-logic): cómo aplicar esto a una comprobación local de licencia o de prueba.
- [Buenas prácticas → Estrategia de semilla](https://www.afterpack.dev/es/docs/best-practices#seed-strategy): cuándo fijarla y cuándo no.
- [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.
