# Обфускація застосунку Electron

@afterpack/electron підключає main, preload і renderer з одним сідом одним викликом і відхиляє bytecodePlugin з electron-vite та незахищені резервні копії, перш ніж вони встигнуть випустити ваш вихідний код.

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

`@afterpack/electron` одним викликом обфускує всі три програми, які випускає застосунок Electron (main, preload, renderer), і всі вони використовують один сід збірки. Якщо підключати вручну, кожна частина — це окрема збірка бандлера з власним випадковим сідом, тож частини одного застосунку виходять структурно не пов'язаними між собою.

electron-builder — не бандлер. Він пакує вже зібраний застосунок в інсталятор і ніколи не чіпає ваш JavaScript, тож над ним у будь-якому разі потрібен бандлер, незалежно від AfterPack.

## Встановлення

```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` обгортає всю конфігурацію electron-vite (об'єкт, функцію або проміс, які повертає `defineConfig`) і підключає [`@afterpack/vite`](https://www.afterpack.dev/uk/docs/frameworks/vite) до кожної частини, яку оголошує конфігурація, і ніколи до тієї, якої вона не оголошує. Peer-залежність: `vite ^5 \| ^6 \| ^7 \| ^8`.

## Збірка

Як підключати прохід, залежить від того, чи ваш інструментарій налаштовує всі три частини одним викликом, чи окремою конфігурацією для кожної частини.

### По одній частині

Інструментарії, які налаштовують кожну частину окремо (Electron Forge з `@electron-forge/plugin-vite`), натомість викликають `afterpackElectron` один раз для кожної конфігурації:

```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` обов'язковий.

### Один сід, три способи

- **electron-vite (`withAfterpack`)** і **Forge + `plugin-vite`**: усі три конфігурації збираються в одному процесі Node, тож частини отримують спільний сід автоматично.
- **`vite-plugin-electron`**: теж один процес. Поставте `afterpackElectron({ leg: "renderer" })` останнім у `plugins`, після самого `vite-plugin-electron`, щоб `generateBundle` AfterPack запечатував уже готовий бандл.
- **Власні скрипти, які запускають кожну частину окремою командою**: спільного процесу немає, тож закріпіть сід для всіх через змінну середовища:

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

`AFTERPACK_seed` приймає ті самі значення, що й [`seed`](https://www.afterpack.dev/uk/docs/config#seed): ціле число, `"git"` (виводиться з `HEAD`) або будь-який інший рядок, який рушій хешує. Явний параметр `seed` усе одно має над ним пріоритет. [Стратегія сіду](https://www.afterpack.dev/uk/docs/best-practices#seed-strategy) пояснює, коли його закріплювати, а коли ні.

## Перевірка

[Protection Map](https://www.afterpack.dev/uk/docs/protection-map) записується окремо для кожної частини, у `.afterpack/<leg>/protectionMap.html`, коли вдалося знайти source map і збірка не працює в CI (`CI=true` або `CI=1`). [Продакшн-режим](https://www.afterpack.dev/uk/docs/config#build-mode) її не вимикає, але electron-vite не видає source map, якщо ви їх не запросите, тож мапа за замовчуванням вимкнена. Досліджуйте main, preload і renderer окремо. Кожен звіт містить увесь ваш вихідний код. Ніколи не комітьте його і не роздавайте з сервера.

> **Ніколи не випускайте source map усередині застосунку**
>
> `.map` в `app.asar` веде до вашого оригінального вихідного коду. Тримайте генерацію source map вимкненою (так за замовчуванням у продакшні) для всього, що ви пакуєте.

## Параметри

Будь-який [ключ конфігурації](https://www.afterpack.dev/uk/docs/config) працює і тут: для всіх частин через `withAfterpack(config, options)` або для кожної частини окремо через `afterpackElectron(options)`. Ці параметри існують лише в цьому пакеті:

| Параметр | Тип | За замовчуванням |
|---|---|---|
| `leg` | `"main" \| "preload" \| "renderer"` | обов'язковий в `afterpackElectron` |
| `projectRoot` | `string` | `process.cwd()`. electron-vite запускає збірку renderer від кореня `src/renderer/`. Перевизначте його, якщо ваша збірка запускається з іншого місця |

[`seed`](https://www.afterpack.dev/uk/docs/config#seed) за замовчуванням — одне нове значення, спільне для всіх частин у межах сесії збірки. [`protectionMap.enabled`](https://www.afterpack.dev/uk/docs/config#protectionMap-enabled) підпорядковується звичайному правилу щодо source map, і кожна частина записує власний звіт у `.afterpack/<leg>/protectionMap.html`.

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

## Директиви

Директиви — це можливість тарифу [Pro](https://www.afterpack.dev/uk/docs/pro). У [збірці Free](https://www.afterpack.dev/uk/docs/directives#free-builds) директива, яка посилює захист, зупиняє збірку з помилкою `DIAG_PRO_DIRECTIVE_REQUIRES_KEY`.

Кожна частина під капотом підключає [`@afterpack/vite`](https://www.afterpack.dev/uk/docs/frameworks/vite), тож [збір директив](https://www.afterpack.dev/uk/docs/frameworks/vite#directives) працює там так само.

## Особливі випадки

### Матриця підтримки

| Інструментарій | Підключення | Один сід автоматично? |
|---|---|---|
| electron-vite | `withAfterpack(defineConfig({ … }))`, один виклик | Так |
| Forge + `plugin-vite` | `afterpackElectron({ leg })` у кожній із трьох конфігурацій | Так |
| Forge + `plugin-webpack` | [`@afterpack/webpack`](https://www.afterpack.dev/uk/docs/frameworks/webpack) у кожній конфігурації | Так |
| `vite-plugin-electron` | `afterpackElectron({ leg: "renderer" })`, **останнім** | Так, якщо стоїть після цього плагіна |
| electron-builder | він пакує, а не збирає бандл; підключайте бандлер над ним | н/д |
| Власні скрипти (окремі процеси) | плагін для кожної частини або `npx afterpack@latest <dir>` | Ні; закріпіть `AFTERPACK_seed` |

### Що він відхиляє

Дві перевірки з зупинкою з помилкою (fail closed) діють для будь-якої частини, підключеної через цей пакет.

**`bytecodePlugin`.** Власний `bytecodePlugin` з electron-vite замінює кожен згенерований чанк 3-рядковою заглушкою-завантажувачем і випускає справжній застосунок як байткод V8 (`.jsc`). Ці двоє не можуть працювати разом, бо байткод замінює чанк, згенерований Rollup. Збірка завершується помилкою на частині, де ввімкнено `bytecodePlugin`, або там, де файл `.jsc`/`.cjsc` згодом з'являється в результаті. Приберіть одне або інше.

**`build.backup: true`.** [Резервні копії](https://www.afterpack.dev/uk/docs/config#build-backup) відхиляються повністю: виклик кидає виняток замість того, щоб продовжити, бо `.backup.<hash>.js` — це ваш повний оригінальний вихідний код, записаний поруч із результатом усередині дерева, яке ваш пакувальник копіює в `app.asar`. Кожен користувач, який встановить застосунок, отримав би його.

Той самий ризик стосується будь-якого артефакту, про який ваш пакувальник не знає, що його треба виключити. Стандартний glob `files` в electron-builder збігається з `dot: true` і за замовчуванням не виключає `.afterpack/`. Виключіть ці шляхи з того, що ви пакуєте:

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

На [source map](https://www.afterpack.dev/uk/docs/config#sourceMap-enabled) видається попередження, а не відмова: `.map` із `sourcesContent` усередині `app.asar` — це повна деобфускація. Залишайте `sourceMap: { enabled: true, emitUrl: true }` лише для локальних налагоджувальних збірок і виключайте `*.map` з того, що ви пакуєте.

### Канали IPC

Назви каналів мають збігатися байт у байт в обох бандлах. `ipcMain.on("save-file", …)` і `ipcRenderer.send("save-file", …)` — це той самий рядок з обох боків. Це звичайні рядкові літерали у звичайному згенерованому JavaScript, тож саме однаковий [сід](https://www.afterpack.dev/uk/docs/config#seed) і однаковий рівень захисту ([`preset`](https://www.afterpack.dev/uk/docs/config#preset) / [`complexity`](https://www.afterpack.dev/uk/docs/config#complexity)) для обох частин тримають дві половини узгодженими.

Якщо назва каналу складається під час виконання, а не записана літералом, тримайте цю конструкцію в модулі, який ви виключаєте через [`paths.exclude`](https://www.afterpack.dev/uk/docs/config#paths-exclude), або знизьте рівень захисту для цієї ділянки через запис [`regions`](https://www.afterpack.dev/uk/docs/config#regions) у плагіні бандлера ([Pro](https://www.afterpack.dev/uk/docs/pro#what-pro-buys)).

### Без плагіна: CLI

Не хочете додавати залежність або збираєте частину чимось іншим, ніж Vite? Натомість запустіть [`npx afterpack@latest`](https://www.afterpack.dev/uk/docs/cli) один раз для кожного каталогу виводу після збірки:

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

Без [аргументу шляху](https://www.afterpack.dev/uk/docs/cli#usage) CLI визначає `out/`, каталог, у який пише electron-vite; якщо ваш відрізняється, вкажіть каталог явно. Кожен запуск обходить каталог, збирає кожен `.js`/`.mjs`/`.cjs` і обфускує їх [на місці](https://www.afterpack.dev/uk/docs/cli#what-a-run-does); аргументом може бути й один файл. Закріпіть однаковий [`--seed`](https://www.afterpack.dev/uk/docs/config#seed) для всіх запусків: `git`, що виводиться з поточного коміту, — найпростіший спосіб це гарантувати. Запуск CLI не має жодної з наведених вище відмов; він обфускує будь-який JavaScript, який знайде. Тримайте однакові [`--seed`](https://www.afterpack.dev/uk/docs/config#seed) і [`--preset`](https://www.afterpack.dev/uk/docs/config#preset) для всіх запусків.

## Далі

- [Фреймворки](https://www.afterpack.dev/uk/docs/frameworks): повна матриця.
- [Vite](https://www.afterpack.dev/uk/docs/frameworks/vite): семантика параметрів, які пересилає цей пакет.
- [Довідник CLI](https://www.afterpack.dev/uk/docs/cli#flags): список прапорців для запасного шляху.
- [Збірки та CI](https://www.afterpack.dev/uk/docs/builds): сіди, dev проти prod, просування тих самих байтів.
- [Захист логіки ліцензування в застосунку Electron](https://www.afterpack.dev/uk/docs/use-cases/electron-license-logic): застосування цього до локальної перевірки ліцензії або пробного періоду.
- [Найкращі практики → Стратегія сіду](https://www.afterpack.dev/uk/docs/best-practices#seed-strategy): коли закріплювати, а коли ні.
- [Protection Map](https://www.afterpack.dev/uk/docs/protection-map): як читати звіт.
- [Конфігурація](https://www.afterpack.dev/uk/docs/config): кожен параметр і де його можна задати.
